package com.amee.platform.resource.datacategory;

import com.amee.base.resource.MediaTypeNotSupportedException;
import com.amee.domain.data.DataCategory;
import com.amee.domain.data.DataItem;
import com.amee.domain.data.ItemDefinition;
import com.amee.domain.data.ItemValue;
import com.amee.domain.tag.Tag;
import com.amee.service.data.DataService;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.util.Map;
import java.util.Properties;

@Service
@Scope("prototype")
public class DataCategoryEcospoldRenderer implements DataCategoryRenderer {

    private final Namespace XSI_NS = Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
    private final Namespace NS = Namespace.getNamespace("http://www.EcoInvent.org/EcoSpold01");
    private final String SCHEMA_LOCATION = "http://www.EcoInvent.org/EcoSpold01 EcoSpold01Dataset.xsd";

    private DataCategory dataCategory;
    private Element rootElem;
    private Element datasetElem;
    private Element flowDataElem;

    @Autowired
    private DataService dataService;

    public void start() {
        rootElem = new Element("ecoSpold", NS);
        rootElem.addNamespaceDeclaration(XSI_NS);
        rootElem.setAttribute("schemaLocation", SCHEMA_LOCATION, XSI_NS);
    }

    public void ok() {
        // Not implemented for ecospold.
    }

    public void newDataCategory(DataCategory dataCategory) {
        this.dataCategory = dataCategory;

        // Only display ecoinvent data in ecospold format.
        if (dataCategory.getEcoinventMetaInformation().isEmpty()) {
            throw new MediaTypeNotSupportedException();
        }

        datasetElem = new Element("dataset", NS);
        if (rootElem != null) {
            rootElem.addContent(datasetElem);
        }
    }

    public void addBasic() {

        // Add the dataset attributes from metadata
        Properties attributes = new Properties();
        try {
            attributes.load(new ByteArrayInputStream(dataCategory.getEcoinventDatasetAttributes().getBytes()));
            for (String name : attributes.stringPropertyNames()) {
                datasetElem.setAttribute(name, attributes.getProperty(name));
            }
        } catch (IOException e) {
            throw new RuntimeException("Caught IOException: " + e.getMessage(), e);
        }

        // Add the metainformation element
        try {
            SAXBuilder builder = new SAXBuilder();
            Document doc = builder.build(new StringReader(dataCategory.getEcoinventMetaInformation()));
            datasetElem.addContent(doc.getRootElement().detach());
        } catch (JDOMException e) {
            throw new RuntimeException("Caught JDOMException: " + e.getMessage(), e);
        } catch (IOException e) {
            throw new RuntimeException("Caught IOException: " + e.getMessage(), e);
        }

        // Add the flowData (data items)
        flowDataElem = new Element("flowData", NS);
        if (datasetElem != null) {
            datasetElem.addContent(flowDataElem);
        }

        // For each data item, add each item value definition name and data item value
        for (DataItem dataItem : dataService.getDataItems(dataCategory)) {

            Element exchangeElem = new Element("exchange", NS);

            for (ItemValue itemValue : dataItem.getItemValues()) {

                // Convert group to category and subGroup to subCategory
                String name = itemValue.getName();
                if (name.equals("group")) {
                    name = "category";
                } else if (name.equals("subGroup")) {
                    name = "subCategory";
                }

                // The outputGroup and inputGroup values are displayed as child elements not attributes
                // Only display the element if it is non-empty.
                if ((name.equals("outputGroup") || name.equals("inputGroup")) && !itemValue.getValue().isEmpty()) {
                    exchangeElem.addContent(new Element(name, NS).setText(itemValue.getValue()));
                } else {
                    exchangeElem.setAttribute(name, itemValue.getValue());
                }
            }
            flowDataElem.addContent(exchangeElem);
        }
    }

    public void addPath() {
        // Not implemented for ecospold.
    }

    public void addParent() {
        // Not implemented for ecospold.
    }

    public void addAudit() {
        // Not implemented for ecospold.
    }

    public void addAuthority() {
        // Not implemented for ecospold.
    }

    public void addWikiDoc() {
        // Not implemented for ecospold.
    }

    public void addProvenance() {
        // Not implemented for ecospold.
    }

    public void addItemDefinition(ItemDefinition id) {
        // Not implemented for ecospold.
    }

    public void startTags() {
        // Not implemented for ecospold.
    }

    public void newTag(Tag tag) {
        // Not implemented for ecospold.
    }

    public String getMediaType() {
        return "application/x.ecospold+xml";
    }

    public Document getObject() {
        return new Document(rootElem);
    }
}

@@ -1982,352 +1982,207 @@
   %7D%0A
-%0A
     
+%7D%0A%0A
     
-datasetElem = new Element(%22dataset%22, NS);%0A        if (rootElem != null) %7B%0A            rootElem.addContent(datasetElem);%0A        %7D%0A    %7D%0A%0A    public void addBasic() %7B%0A%0A        // Add the dataset attributes from metadata%0A        Properties attributes = new Properties();%0A        try %7B%0A            attributes.load(new ByteArrayInputStream
+public void addBasic() %7B%0A%0A        try %7B%0A            SAXBuilder builder = new SAXBuilder();%0A%0A            // Add the dataset element%0A            Document doc = builder.build(new StringReader
 (dat
@@ -2226,19 +2226,8 @@
 es()
-.getBytes()
 ));%0A
@@ -2242,137 +2242,96 @@
     
-for (String name : attributes.stringPropertyNames()) %7B%0A                datasetElem.setAttribute(name, attributes.getProperty(name
+if (rootElem != null) %7B%0A                rootElem.addContent(doc.getRootElement().detach(
 ));%0A
@@ -2338,30 +2338,24 @@
         
-    %7D%0A
         
 %7D catch 
@@ -2350,126 +2350,67 @@
     
-%7D catch (IOException e) %7B%0A            throw new RuntimeException(%22Caught IOException: %22 + e.getMessage(), e);%0A
+datasetElem = rootElem.getChild(%22dataset%22, NS);%0A   
         
 %7D%0A%0A 
@@ -2397,35 +2397,40 @@
 NS);%0A           
+ 
 %7D%0A%0A
+    
         // Add t
@@ -2468,85 +2468,11 @@
     
-try %7B%0A            SAXBuilder builder = new SAXBuilder();%0A            Document
+   
  doc
@@ -2547,24 +2547,67 @@
 mation()));%0A
+            if (datasetElem != null) %7B%0A    
             
@@ -2653,32 +2653,46 @@
 nt().detach());%0A
+            %7D%0A
         %7D catch 

Use xml fragment for dataset. PL-3379.