package seng302.DataInput;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import seng302.Model.Boat;
import seng302.Model.GPSCoordinate;
import seng302.Model.Mark;
import seng302.Model.Polars;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by cbt24 on 10/05/17.
 */
public class BoatXMLReader extends XMLReader implements BoatDataSource {

    private final Map<Integer, Boat> boatMap = new HashMap<>();
    private final Map<Integer, Mark> markerMap = new HashMap<>();

    /**
     * Polars table to assign to each boat.
     */
    Polars boatPolars;


    /**
     * Constructor for Boat XML
     *
     * @param filePath Name/path of file to read. Read as a resource.
     * @param boatPolars polars used by the boats
     * @throws IOException                  error
     * @throws SAXException                 error
     * @throws ParserConfigurationException error
     */
    public BoatXMLReader(String filePath, Polars boatPolars) throws IOException, SAXException, ParserConfigurationException {
        super(filePath);
        this.boatPolars = boatPolars;
        read();
    }

    public void read() {
        readSettings();
        readShapes();
        readBoats();
    }

    private void readBoats() {
        Element nBoats = (Element) doc.getElementsByTagName("Boats").item(0);
        for (int i = 0; i < nBoats.getChildNodes().getLength(); i++) {
            Node boat = nBoats.getChildNodes().item(i);
            if (boat.getNodeName().equals("Boat")) {
                readBoatNode(boat);
            }
        }
    }

    /**
     * Ignored data
     */
    private void readShapes() {

    }

    /**
     * Ignored data
     */
    private void readSettings() {

    }

    private boolean isYachtNode(Node boatNode) {
        return boatNode.getAttributes().getNamedItem("Type").getTextContent().toLowerCase().equals("yacht");
    }

    /**
     * Reads the information about one boat
     * Ignored values: ShapeID, StoweName, HullNum, Skipper, Type
     */
    private void readBoatNode(Node boatNode) {
        int sourceID = Integer.parseInt(boatNode.getAttributes().getNamedItem("SourceID").getTextContent());
        String name = boatNode.getAttributes().getNamedItem("BoatName").getTextContent();

        if (isYachtNode(boatNode)) readYacht(boatNode, sourceID, name);
        else readMark(boatNode, sourceID, name);
    }

    private void readYacht(Node boatNode, int sourceID, String name) {
        String shortName = boatNode.getAttributes().getNamedItem("ShortName").getTextContent();
        if (exists(boatNode, "Country")) {
            String country = boatNode.getAttributes().getNamedItem("Country").getTextContent();
            boatMap.put(sourceID, new Boat(sourceID, name, country, this.boatPolars));
        } else {
            boatMap.put(sourceID, new Boat(sourceID, name, shortName, this.boatPolars));
        }
    }

    private void readMark(Node boatNode, int sourceID, String name) {
        Node nCoord = ((Element)boatNode).getElementsByTagName("GPSposition").item(0);
        double x = Double.parseDouble(nCoord.getAttributes().getNamedItem("X").getTextContent());
        double y = Double.parseDouble(nCoord.getAttributes().getNamedItem("Y").getTextContent());
        Mark mark = new Mark(sourceID, name, new GPSCoordinate(y,x));
        markerMap.put(sourceID, mark);
    }

    @Override
    public Map<Integer, Boat> getBoats() {
        return boatMap;
    }

    @Override
    public Map<Integer, Mark> getMarkerBoats() {
        return markerMap;
    }
}
