package org.artisanlogiciel.osm;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class OsmReader {

    private String sample;

    private HashMap<NodeRef,Node> refs;
    private List<Way> ways;

    public List<Way> getBuildings() {
        return buildings;
    }

    private List<Way> buildings;

    public double getMinlat() {
        return minlat;
    }

    public double getMinlon() {
        return minlon;
    }

    public double getMaxlat() {
        return maxlat;
    }

    public double getMaxlon() {
        return maxlon;
    }

    double minlat = 0;
    double minlon = 0;
    double maxlat = 180;
    double maxlon = 180;

    public OsmReader(String sample) {
        this.sample = sample;
        refs = new HashMap<>();
        ways = new ArrayList<>();
        buildings = new ArrayList<>();
    }

    public List<Way> getWays() {
        return ways;
    }

    public void read()
    {
        /* TODO get minlat and minlon **/
        DocumentBuilderFactory factory =
        DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new FileInputStream(sample));
            Element root = doc.getDocumentElement();
            System.out.println(root);
            // <bounds minlat="43.6399000" minlon="7.0058300" maxlat="43.6435000" maxlon="7.0111700"/>
            NodeList boundList = doc.getElementsByTagName("bounds");
            for (int temp = 0; temp < boundList.getLength(); temp++) {
                org.w3c.dom.Node nNode = boundList.item(temp);
                if (nNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
                    Element e = (Element) nNode;
                    minlat = Double.valueOf(e.getAttribute("minlat"));
                    minlon = Double.valueOf(e.getAttribute("minlon"));
                    maxlat = Double.valueOf(e.getAttribute("maxlat"));
                    maxlon = Double.valueOf(e.getAttribute("maxlon"));
                }
            }

            int boundserror = 0;
            System.out.println("minlat " + minlat);
            System.out.println("maxlat " + maxlat);
            System.out.println("minlon " + minlon);
            System.out.println("maxlon " + maxlon);

            NodeList nList = doc.getElementsByTagName("node");
            for (int temp = 0; temp < nList.getLength(); temp++) {
                org.w3c.dom.Node nNode = nList.item(temp);
                if (nNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
                    Element e = (Element) nNode;
                    long id = Long.valueOf(e.getAttribute("id"));
                    double lat = Double.valueOf(e.getAttribute("lat"));
                    double lon = Double.valueOf(e.getAttribute("lon"));
                    if (lat < minlat)
                    {
                        boundserror ++;
                        System.err.println("lat < minlat " + lat );
                    }
                    else if (lat > maxlat)
                    {
                        boundserror ++;
                        System.err.println("lat > minlat " + lat);
                    }
                    if (lon < minlon)
                    {
                        boundserror ++;
                        System.err.println("lon < minlon " + lon);
                    }
                    else if (lon > maxlon)
                    {
                        boundserror ++;
                        System.err.println("lon > minlon " + lon);
                    }
                    Node node = new Node(new NodeRef(id), lat, lon);
                    refs.put(node.getRef(),node);
                }
            }
            NodeList wList = doc.getElementsByTagName("way");
            for (int temp = 0; temp < wList.getLength(); temp++) {
                org.w3c.dom.Node wNode = wList.item(temp);
                if (wNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
                    Element e = (Element) wNode;
                    try {
                        long id = Long.valueOf(e.getAttribute("id"));
                        List<NodeRef> nodeRefList = new ArrayList<>();
                        NodeList nrList = e.getElementsByTagName("nd");
                        for (int temp2 = 0; temp2 < nrList.getLength(); temp2++) {
                            org.w3c.dom.Node nrNode = nrList.item(temp2);
                            if (nrNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
                                Element nd = (Element) nrNode;
                                long ref = Long.valueOf(nd.getAttribute("ref"));
                                NodeRef nodeRef = new NodeRef(ref);
                                Node node = refs.get(nodeRef);
                                if ( node == null )
                                {
                                    System.out.println("unknown node id " + nodeRef);
                                }
                                else {
                                    nodeRefList.add(node.getRef());
                                }
                            }
                        }
                        if ( nodeRefList.size() > 0 )
                        {
                            Way way = new Way(id, nodeRefList);
                            // closed way ?
                            if (nodeRefList.get(0).equals(nodeRefList.get(nodeRefList.size() -1)))
                            {
                                buildings.add(way);
                            }
                            else
                            {
                                ways.add(way);
                            }
                        }
                    }
                    catch (Exception bad)
                    {
                        System.err.println("Too bad way");
                        bad.printStackTrace(System.err);
                    }
                }
            }
        }
        catch(Exception any)
        {
            System.err.println("Too bad");
            any.printStackTrace(System.err);
        }
    }

    public void dump()
    {
        System.out.println(refs);
        System.out.println(ways);
    }

}
