package seng302.Data;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import seng302.DataInput.RegattaDataSource;
import seng302.Exceptions.InvalidRegattaDataException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;

/**
 * Created by esa46 on 25/04/17.
 */
public class RegattaData {


    private RegattaDataSource regattaDataSource;
    private Document doc;
    private Element rootElement;

    public RegattaData(RegattaDataSource regattaDataSource) {
        this.regattaDataSource = regattaDataSource;
    }


    /**
     * Creates an AC35 officially formatted xml description of a regatta
     *
     * @return String containing xml-formatted regatta description
     */
    public String createXML() {

        try {
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

            //root element
            doc = docBuilder.newDocument();
            rootElement = doc.createElement("RegattaConfig");
            doc.appendChild(rootElement);

            appendChildElements();

            // write the content into xml file
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
            DOMSource source = new DOMSource(doc);

            //Serialize document.
            StringWriter stringWriter = new StringWriter();
            StreamResult result = new StreamResult(stringWriter);
            transformer.transform(source, result);

            return stringWriter.toString();


        } catch (ParserConfigurationException pce) {
            throw new InvalidRegattaDataException();
        } catch (TransformerException tfe) {
            throw new InvalidRegattaDataException();
        }
    }

    /**
     * Creates all necessary child elements and appends them to the xml doc
     */
    private void appendChildElements() {
        appendRegattaID();
        appendRegattaName();
        appendCourseName();
        appendCentralLatitude();
        appendCentralLongitude();
        appendCentralAltitude();
        appedUtcOffset();
        appendMagneticVariation();
    }

    /**
     * Creates and appends regatta id element
     */
    private void appendRegattaID() {
        //regattaID element
        Element regattaID = doc.createElement("RegattaID");
        regattaID.appendChild(doc.createTextNode(Integer.toString(regattaDataSource.getRegatta().getRegattaID())));
        rootElement.appendChild(regattaID);
    }

    /**
     * Creates and appends regatta name element
     */
    private void appendRegattaName() {
        //regattaName element
        Element regattaName = doc.createElement("RegattaName");
        regattaName.appendChild(doc.createTextNode(regattaDataSource.getRegatta().getRegattaName()));
        rootElement.appendChild(regattaName);
    }

    /**
     * Creates and appends course name element
     */
    private void appendCourseName() {
        //courseName element
        Element courseName = doc.createElement("CourseName");
        courseName.appendChild(doc.createTextNode(regattaDataSource.getRegatta().getCourseName()));
        rootElement.appendChild(courseName);
    }

    /**
     * Creates and appends central latitude element
     */
    private void appendCentralLatitude() {
        //centralLatitude element
        Element centralLat = doc.createElement("CentralLatitude");
        centralLat.appendChild(doc.createTextNode(Double.toString(regattaDataSource.getRegatta().getCentralLatitude())));
        rootElement.appendChild(centralLat);
    }

    /**
     * Creates and appends central longitude element
     */
    private void appendCentralLongitude() {
        //centralLongitude element
        Element centralLong = doc.createElement("CentralLongitude");
        centralLong.appendChild(doc.createTextNode(Double.toString(regattaDataSource.getRegatta().getCentralLongitude())));
        rootElement.appendChild(centralLong);
    }

    /**
     * Creates and appends central altitude element
     */
    private void appendCentralAltitude() {
        //centralAltitude element
        Element centralAlt = doc.createElement("CentralAltitude");
        centralAlt.appendChild(doc.createTextNode(Double.toString(regattaDataSource.getRegatta().getCentralAltitude())));
        rootElement.appendChild(centralAlt);
    }

    /**
     * Creates and appends utc offset element
     */
    private void appedUtcOffset() {
        //utcOffset element
        Element utcOffset = doc.createElement("UtcOffset");
        utcOffset.appendChild(doc.createTextNode(Double.toString(regattaDataSource.getRegatta().getUtcOffset())));
        rootElement.appendChild(utcOffset);
    }

    /**
     * Creates and appends magnetic variation element
     */
    private void appendMagneticVariation() {
        //magneticVariation element
        Element magneticVariation = doc.createElement("MagneticVariation");
        magneticVariation.appendChild(doc.createTextNode(Double.toString(regattaDataSource.getRegatta().getMagneticVariation())));
        rootElement.appendChild(magneticVariation);

    }

}
