package org.spview.filehandler;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class FileParser {
    private final ArrayList<Element> pathlist = new ArrayList<>();
    private final ArrayList<String> attrlist = new ArrayList<>();
    private final ArrayList<String> AttributeOfFilelist = new ArrayList<>();
    private final ArrayList<String> yReverseElement = new ArrayList<>();
    private final ArrayList<String> hideElement = new ArrayList<>();
    private final ArrayList<String> xShiftState = new ArrayList<>();
    private final ArrayList<String> yShiftState = new ArrayList<>();
    private final String minX;
    private final String maxX;
    private final String minY;
    private final String maxY;
    private final String indexColorPred;
    private final String indexColorExp;

    public FileParser(String filename) throws ParserConfigurationException, SAXException, IOException {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        File fileXML = new File(filename);
        Document xml = builder.parse(fileXML);
        Element spvFile = xml.getDocumentElement();

        getAttributeList(spvFile, this.AttributeOfFilelist, "File", "AttributeOfFile");
        getAttributePath(spvFile, this.pathlist, this.attrlist);
        getTagValueList(spvFile, this.yReverseElement, "yReverse");
        getTagValueList(spvFile, this.hideElement, "hide");

        this.indexColorPred = getTagValue(spvFile, "indexColorPred", "0");
        this.indexColorExp = getTagValue(spvFile, "indexColorExp", "0");

        getTagValueList(spvFile, this.xShiftState, "xShiftState");
        getTagValueList(spvFile, this.yShiftState, "yShiftState");

        this.minX = getTagValue(spvFile, "xmin", "0.0");
        this.maxX = getTagValue(spvFile, "xmax", "0.0");
        this.minY = getTagValue(spvFile, "ymin", "0.0");
        this.maxY = getTagValue(spvFile, "ymax", "0.0");
    }

    private static void getAttributeList(Node n, ArrayList<String> array, String string, String attribute) {
        if (n instanceof Element) {
            Element element = (Element) n;
            if (n.getNodeName().equals(string)) {
                array.add(element.getAttribute(attribute));
            }
            // The child nodes of the current node are handled.
            int nbChild = n.getChildNodes().getLength();
            // A list of these child nodes is retrieved
            NodeList list = n.getChildNodes();

            // The program checks into the list
            for (int i = 0; i < nbChild; i++) {
                Node n2 = list.item(i);
                // if the child node is an Element, it is handled
                if (n2 instanceof Element) {
                    // Recursive use of the method to handle the node and its children
                    getAttributeList(n2, array, string, attribute);
                }
            }
        }
    }

    private static void getTagValueList(Node n, ArrayList<String> array, String string) {
        if (n instanceof Element) {
            Element element = (Element) n;
            if (n.getNodeName().equals(string)) {
                array.add(element.getTextContent());
            }
            // The child nodes of the current node are handled.
            int nbChild = n.getChildNodes().getLength();
            // A list of these child nodes is retrieved
            NodeList list = n.getChildNodes();

            // The program checks into the list
            for (int i = 0; i < nbChild; i++) {
                Node n2 = list.item(i);
                // if the child node is an Element, it is handled
                if (n2 instanceof Element) {
                    // Recursive use of the method to handle the node and its children
                    getTagValueList(n2, array, string);
                }
            }
        }
    }

    private static String getTagValue(Element eElement, String sTag, String defaultVal) {
        if (eElement.getElementsByTagName(sTag).item(0) == null) {
            return defaultVal;
        }
        NodeList nlList = eElement.getElementsByTagName(sTag).item(0).getChildNodes();
        Node nValue = nlList.item(0);
        return nValue.getNodeValue();
    }

    private static void getAttributePath(Node n, ArrayList<Element> pathlist, ArrayList<String> attrlist) {
        String type;
        if (n instanceof Element) {
            Element element = (Element) n;
            if (n.getNodeName().equals("path")) {
                pathlist.add(element);
                type = element.getAttribute("Type");
                attrlist.add(type);
            }
            // The child nodes of the current node are handled.
            int nbChild = n.getChildNodes().getLength();
            // A list of these child nodes is retrieved
            NodeList list = n.getChildNodes();

            // The program checks into the list
            for (int i = 0; i < nbChild; i++) {
                Node n2 = list.item(i);
                // if the child node is an Element, it is handled
                if (n2 instanceof Element) {
                    // Recursive use of the method to handle the node and its children
                    getAttributePath(n2, pathlist, attrlist);
                }
            }
        }
    }

    /* getter and setter */

    public ArrayList<String> getAttributeOfFilelist() {
        return AttributeOfFilelist;
    }

    public ArrayList<Element> getPathlist() {
        return pathlist;
    }

    public ArrayList<String> getAttrlist() {
        return attrlist;
    }

    public ArrayList<String> getyReverseElementslist() {
        return yReverseElement;
    }

    public ArrayList<String> getHideElementslist() {
        return hideElement;
    }

    public ArrayList<String> getxShiftElementslist() {
        return xShiftState;
    }

    public ArrayList<String> getyShiftElementslist() {
        return yShiftState;
    }

    public double getMinX() {
        return Double.parseDouble(this.minX);
    }

    public double getMinY() {
        return Double.parseDouble(this.minY);
    }

    public double getMaxX() {
        return Double.parseDouble(this.maxX);
    }

    public double getMaxY() {
        return Double.parseDouble(this.maxY);
    }

    public int getIndexColorPred() {
        return Integer.parseInt(indexColorPred);
    }

    public int getIndexColorExp() {
        return Integer.parseInt(indexColorExp);
    }
}