package org.datacite.mds.tools.conversion;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.List;

import javax.validation.ConstraintViolationException;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.log4j.Logger;
import org.datacite.mds.domain.Dataset;
import org.datacite.mds.domain.Metadata;
import org.datacite.mds.tools.AbstractTool;
import org.datacite.mds.util.ValidationUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Transactional(propagation = Propagation.NEVER)
public abstract class BaseMetadataConvertor extends AbstractTool {

    Logger log = Logger.getLogger(this.getClass());

    Transformer transformer;

    public BaseMetadataConvertor(String xsltPath) {
        try {
            Resource xslt = new ClassPathResource(xsltPath);
            Source xsltSource;
            xsltSource = new StreamSource(xslt.getInputStream());
            TransformerFactory tFactory = TransformerFactory.newInstance();
            transformer = tFactory.newTransformer(xsltSource);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void run(String[] args) {
        log.info("starting");
        List<Dataset> datasets = Dataset.findAllDatasets();
        for (Dataset dataset : datasets) {
            Metadata metadata = Metadata.findLatestMetadatasByDataset(dataset);
            if (metadata != null)
                checkAndConvert(metadata);
        }
        log.info("done");
    }

    void checkAndConvert(Metadata metadata) {
        log.debug("checking " + metadata);
        if (!needsConversion(metadata))
            return;

        Metadata converted;
        try {
            converted = convert(metadata);
            converted.persist();
            log.info("converted " + metadata + " => " + converted);
        } catch (ConstraintViolationException e) {
            String msg = ValidationUtils.collateViolationMessages(e.getConstraintViolations());
            log.warn("failed to persist " + metadata + ": " + msg);
        } catch (Exception e) {
            log.warn("failed to convert " + metadata + ": " + e);
        }
    }

    public abstract boolean needsConversion(Metadata metadata);

    Metadata convert(Metadata orig) throws TransformerException {
        ByteArrayInputStream input = new ByteArrayInputStream(orig.getXml());
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        transformer.transform(new StreamSource(input), new StreamResult(output));

        Metadata converted = new Metadata();
        converted.setDataset(orig.getDataset());
        converted.setXml(output.toByteArray());
        converted.setIsConvertedByMds(true);
        return converted;
    }

}

@@ -1088,16 +1088,134 @@
 ormer;%0A%0A
+    private long count_check = 0;%0A    private long count_needs_conversion = 0;%0A    private long count_converted = 0;%0A%0A
     publ
@@ -1254,24 +1254,24 @@
 xsltPath) %7B%0A
-
         try 
@@ -2026,21 +2026,258 @@
   lo
-g.info(%22done%22
+ng count_failed = count_needs_conversion - count_converted;%0A        String stats = %22checked: %22 + count_check + %22, converted: %22 + count_converted + %22, failed: %22 + count_failed;%0A        log.info(%22done (%22 + stats + %22)%22);%0A        System.out.println(stats
 );%0A 
@@ -2363,32 +2363,55 @@
  %22 + metadata);%0A
+        count_check++;%0A
         if (!nee
@@ -2453,16 +2453,50 @@
  return;
+%0A        count_needs_conversion++;
 %0A%0A      
@@ -2675,16 +2675,47 @@
 erted);%0A
+            count_converted++;%0A
         
@@ -2885,23 +2885,34 @@
 iled to 
-persist
+validate converted
  %22 + met

add stats for conversion tool