package usda.weru.mcrew;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileReader;
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;

import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;
import org.apache.log4j.Logger;
import org.openide.util.Exceptions;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;

class SkeletonUpdater {

    private static final Logger LOGGER = Logger.getLogger(SkeletonUpdater.class);
    List<String> opdates;
    List<String> opnames;
    List<String> vegnames;
    Integer rotationYears;
    public String notes = "";

    SkeletonUpdater() {

    }

    //
    // Reads a WEPS management file and saves the dates, operations and crops in vectors. This will handle both management
    // file versions 1.1 and 1.2
    //
    public boolean readWEPSManBrief(String wepsLongName) {

        opnames = new Vector<String>();
        opdates = new Vector<String>();
        vegnames = new Vector<String>();
        rotationYears = 1;
        String sSTART = "start";
        BufferedReader br = null;
        try {
            br = new BufferedReader(new TFileReader(new TFile(wepsLongName)));
            String temp;
            //loop to find out the 'D'&'O' pair, then set to DOM tree
            temp = br.readLine();
            while (temp != null) {
                temp = temp.trim();
                if (temp.length() == 0) {
                    temp = br.readLine();
                    continue;
                }
                if (temp.startsWith("*START")) {
                    int rotationIndex = temp.toLowerCase().indexOf(sSTART) + sSTART.length();
                    String rotationStr = temp.substring(rotationIndex).trim();
                    if (rotationStr.endsWith("<")) {
                        rotationStr = rotationStr.substring(0, rotationStr.length() - 2);
                    }
                    rotationStr = rotationStr.trim();
                    rotationYears = (Integer.valueOf(rotationStr));
                }
                if (temp.charAt(0) == 'D') {
                    String txtdate = temp.substring(2).trim();
                    if (txtdate.endsWith("<")) {
                        txtdate = txtdate.substring(0, txtdate.length() - 2);
                    }
                    txtdate = txtdate.trim();
                    // switch the day/month to month/day
                    StringTokenizer thedate = new StringTokenizer(txtdate, "/");
                    String day = thedate.nextToken();
                    String month = thedate.nextToken();
                    String year = thedate.nextToken();
                    String skeldate = month + "/" + day + "/" + year;

                    //rotationYears = new Integer(year);
                    temp = br.readLine();
                    if (temp != null) {
                        String txtname = temp.substring(5).trim();
                        if (txtname.endsWith("<")) {
                            txtname = txtname.substring(0, txtname.length() - 2);
                        }
                        txtname = txtname.trim();
                        opnames.add(txtname);
                    } else {
                        LOGGER.warn("Unexpected null value.");
                    }

                    opdates.add(skeldate);
                    vegnames.add("");

                    temp = br.readLine();
                    String g03 = "G 03";
                    while (temp != null && temp.charAt(0) != 'D') {
                        if (temp.startsWith(g03)) {
                            temp = br.readLine();//need to confirm if the name is "no crop" or not.
                            if (temp != null) {
                                String subvegname = temp.substring(2).trim();
                                if (subvegname.endsWith("<")) {
                                    subvegname = subvegname.substring(0, subvegname.length() - 2);
                                }
                                subvegname = subvegname.trim();
                                int index = vegnames.size();
                                vegnames.set(index - 1, subvegname);
                            } else {
                                LOGGER.warn("Unexpected null value.");
                            }
                        }
                        temp = br.readLine();
                    }
                } else if (temp.charAt(0) == 'N') { // Notes field
                    if (temp.length() > 2 && temp.substring(2) != null) {
                        notes = notes + (temp.substring(2)) + "\n";
                    }
                    temp = br.readLine();

                } else {
                    temp = br.readLine();
                }
            }
        } catch (IOException e) {
            //System.err.println("RunFileData: " + e);
            return false;
        } finally {
            try {
                br.close();
            } catch (IOException e) {
                LOGGER.error("Error closing file stream.", e);
            }
        }

        return true;

    }

    //
    // Writes out an NRCS XML skeleton file from the data that was read in.
    //
    public boolean writeSkeletonXMLFile(String filename) {

        Node root;
        //Saftey check, build required directory structure        
        TFile dir = new TFile(filename).getParentFile();
        if (!dir.exists()) {
            boolean created = dir.mkdirs();
            if (!created) {
                LOGGER.error("Unable to create required directory structure: " + dir.getAbsolutePath());
                return false;
            }
        }
        String nonEscapingElements[] = {XMLConstants.soperationname, XMLConstants.sname};

        try {

            Document wepsmanDoc = XMLDoc.createDocument(XMLConstants.smanagement_skeleton);

            root = wepsmanDoc.getDocumentElement();

            ((Element) root).setAttribute("ver", "1.0");    //Currently hardcoded until we have a better schema defined.
            ((Element) root).setAttribute("prog", usda.weru.util.Application.WEPS.getName());

            //Notes tag                        
            Node nodeNotes = wepsmanDoc.createElement(XMLConstants.snotes);
            XMLDoc.setTextData(nodeNotes, notes, wepsmanDoc);
            root.appendChild(nodeNotes);

            //Rotation Years tag
            Node rotyearsNode = wepsmanDoc.createElement(XMLConstants.srotationyears);
            XMLDoc.setTextData(rotyearsNode, rotationYears.toString(), wepsmanDoc);
            root.appendChild(rotyearsNode);

            TFile f = new TFile(filename);

            String shortName = f.getName();
            int index = shortName.lastIndexOf(".");
            String basename = shortName;
            if (index > 0) {
                basename = shortName.substring(0, index);
            }

            Node nameNode = wepsmanDoc.createElement(XMLConstants.sname);
            XMLDoc.setTextData(nameNode, basename, wepsmanDoc);
            root.appendChild(nameNode);

            Node operations = wepsmanDoc.createElement(XMLConstants.soperationskel);

            for (int i = 0; i < opdates.size(); i++) {
                Node wepsOp = wepsmanDoc.createElement(XMLConstants.sopskel);
                Node date = wepsmanDoc.createElement(XMLConstants.sdate);
                XMLDoc.setTextData(date, opdates.get(i), wepsmanDoc);
                wepsOp.appendChild(date);
                Node opNameNode = wepsmanDoc.createElement(XMLConstants.sname);
                XMLDoc.setTextData(opNameNode, opnames.get(i), wepsmanDoc);
                wepsOp.appendChild(opNameNode);
                String plant = vegnames.get(i);
                if (plant.length() > 0) {
                    Node vegNode = wepsmanDoc.createElement(XMLConstants.svegskel);
                    Node vegName = wepsmanDoc.createElement(XMLConstants.sname);
                    XMLDoc.setTextData(vegName, plant, wepsmanDoc);
                    vegNode.appendChild(vegName);
                    wepsOp.appendChild(vegNode);
                }
                operations.appendChild(wepsOp);
            }

            root.appendChild(operations);
              DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
            DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
            if(impl == null) {
                System.out.println("No DOMImplementation found !");
                return false;
            }
             LSSerializer serializer = impl.createLSSerializer();
            serializer.getDomConfig().setParameter("format-pretty-print", true);
            LSOutput output = impl.createLSOutput();
            output.setEncoding(XMLConstants.sEncoding);
            output.setCharacterStream(new FileWriter(filename));
            serializer.write(wepsmanDoc, output);

        } catch (DOMException e) {
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            //e.printStackTrace();
            // Could not write the file for some reason
            return false;
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | ClassCastException ex) {
            Exceptions.printStackTrace(ex);
        }

        return true;

    }

    //
    // Returns verctor of date strings read from management file
    //
    public List<String> getDates() {
        return opdates;
    }

    //
    // Returns vector of operation strings read from management file
    //
    public List<String> getOperations() {
        return opnames;
    }

    //
    // Returns vector of crop strings read from management file. On dates with no
    // vegetation the string is empty ""
    //
    public List<String> getCrops() {
        return vegnames;
    }
}
