package atmsdriver.model;

import atmsdriver.NetworkLoader;
import atmsdriver.model.Station.DIRECTION;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 *
 * @author andrew
 */
public class Highways {

    final private ArrayList<FEPLine> lines;
    final private String FEPHostName;
    final private int FEPPortNum;
    
    // NEED FINISH final private ArrayList<Highway> highways;
    
    public Highways(String ldsFileName, String loopsFileName, 
            String highwayMetaFileName, String FEPHostName, int FEPPortNum) {
        /*
        lines = loadLines(highwayMetaFileName);
        System.out.println("SIZE: " + toXML().toCharArray().length);
        */
        
        NetworkLoader ldr = new NetworkLoader(new File(ldsFileName), new File(loopsFileName));
        this.lines = (ArrayList<FEPLine>) ldr.getFEPLines();
        this.FEPHostName = FEPHostName;
        this.FEPPortNum = FEPPortNum;
        // NEED FINISH this.highways = loadHighways();
        //writeHighwaysMeta("hard.txt");
    }
    
    // NEED FINISH
    private void loadHighways()
    {
        
        //highways.add(new Highway(lines, ));
        
    }
/*
    private ArrayList<FEPLine> loadLines(String highwayMetaFileName) {
        ArrayList<FEPLine> lines = new ArrayList<>();
        try {
            Scanner sc = new Scanner(new File(highwayMetaFileName));
            String firstLine = sc.nextLine();

            Scanner linesc = new Scanner(firstLine);
            int numLines = linesc.nextInt();
            linesc.close();

            for (int i = 0; i < numLines; i++) {
                System.out.println("CURR: " + i);
                lines.add(loadLine(sc));
            }
            sc.close();

        } catch (FileNotFoundException ex) {
            Logger.getLogger(Highways.class.getName()).log(Level.SEVERE, null, ex);
        }
        return lines;
    }

    private FEPLine loadLine(Scanner sc) {
        String line = sc.nextLine();
        System.out.println(line);
        Scanner scline = new Scanner(line);

        int lineNum = scline.nextInt();
        int count = scline.nextInt();
        int numStations = scline.nextInt();
        ArrayList<Station> stations = new ArrayList<>();
        for (int i = 0; i < numStations; i++) {
            stations.add(loadStation(sc, lineNum));
        }

        return new FEPLine(lineNum, stations, count);
    }

    private Station loadStation(Scanner sc, int lineNum) {
        String line = sc.nextLine();
        System.out.println(line);
        Scanner scline = new Scanner(line);
        int ldsID = scline.nextInt();
        int drop = scline.nextInt();
        int fwy = scline.nextInt();
        DIRECTION dir = DIRECTION.getEnum(scline.next());
        double postmile = scline.nextDouble();
        int numLoops = scline.nextInt();
        String location = getStationLoc(line);
        ArrayList<LoopDetector> loops = new ArrayList<>();
        for (int i = 0; i < numLoops; i++) {
            loops.add(loadLoop(sc));
        }

        return new Station(lineNum, ldsID, drop, location, loops, fwy, dir, postmile);
    }

    private LoopDetector loadLoop(Scanner sc) {
        String line = sc.nextLine();
        Scanner scline = new Scanner(line);

        int loopID = scline.nextInt();
        int laneNum = scline.nextInt();
        String loopLoc = getLoopLoc(line); // NEED GET LOOPLOC
        scline.close();
        return new LoopDetector(loopID, loopLoc, laneNum);
    }

    private String getLoopLoc(String line) {
        Scanner sc = new Scanner(line);
        sc.nextInt();
        sc.nextInt();

        // GRABS FROM CURRENT TO END OF LINE
         
        sc.useDelimiter("\\z");
        String loc = sc.next().trim();
        sc.close();
        return loc;
    }

    // Returns the loction given the whole line from the lookup file
    private String getStationLoc(String line) {
        Scanner scline = new Scanner(line);
        scline.nextInt();
        scline.nextInt();
        scline.nextInt();
        scline.next();
        scline.nextDouble();
        scline.nextInt();

        // GRABS FROM CURRENT TO END OF LINE
        scline.useDelimiter("\\z");
        String loc = scline.next().trim();
        scline.close();
        return loc;
    }
*/
    public void writeToFEP() {
        try {
            Socket sock = new Socket(FEPHostName, FEPPortNum);
            PrintWriter out = new PrintWriter(sock.getOutputStream(), true);
            out.println(this.toXML());
            sock.close();
        } catch (IOException ex) {
            Logger.getLogger(Highways.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    // CHECK: DO WE EVEN NEED TO DO THIS?
    private void updateSequences() {
        for (FEPLine line : lines) {
            line.updateSequences();
        }
    }

    /**
     * Returns the network metadata in condensed form. This is just a quick
     * script function to make a proper highway metadata configuration file, so
     * that we can read the network faster.
     *
     * @return Network metadata
     */
    public void writeHighwaysMeta(String fileName) {

        try {
            FileWriter fw = new FileWriter(new File(fileName));
            StringBuilder build = new StringBuilder();
            build.append(lines.size());
            build.append("\n");
            System.out.println(lines.size());
            fw.write(build.toString());
            int count = 1;
            for (FEPLine line : lines) {
                System.out.println("Writing num: " + count);
                count++;
                fw.write(line.getLineMeta());

            }
        } catch (IOException ex) {
            Logger.getLogger(Highways.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public String toXML() {
        String xml = null;
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document theDoc = builder.newDocument();

            Element networkElement = theDoc.createElement(XML_TAGS.NETWORK.tag);
            theDoc.appendChild(networkElement);

            for (FEPLine line : lines) {
                line.toXML(networkElement);
            }

            Transformer tf = TransformerFactory.newInstance().newTransformer();

            tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            tf.setOutputProperty(OutputKeys.INDENT, "yes");
            tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

            Writer out = new StringWriter();
            tf.transform(new DOMSource(theDoc), new StreamResult(out));
            xml = out.toString();
            out.close();
        } catch (Exception ex) {
            Logger.getLogger(Highways.class.getName()).log(Level.SEVERE, null, ex);
        }
        return xml;

    }

    private static enum XML_TAGS {

        NETWORK("Network");

        String tag;

        private XML_TAGS(String n) {
            tag = n;
        }
    }
}
