/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package expressiontree.operands;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.apfloat.Apfloat;
import org.w3c.dom.Document;
import propertyhandler.Properties;

/**
 * A számok osztálya.
 * @author Esta
 */
public class NumberType extends Matrix {

    /**
     * Az az adattag, ami azt jelzi, hogy változóról van-e szó.
     */
    private boolean variable;

    /**
     * Az a metódus, ami megmondja, hogy változó-e a this.
     * @return az elemben tárolt érték.
     */
    public boolean isVariable() {
        return this.variable;
    }

    /**
     * A szám értékével tér vissza ez a metódus.
     * @return az elemben eltárolt szám értéke.
     */
    public Apfloat getNumericValue() {
        return this.values[0][0];
    }

    /**
     * Beállítja a szám értékét.
     * @param value az új érték.
     */
    public void setValue(Apfloat value) {
        this.values[0][0] = value;
    }

    /**
     * Megmondja, hogy long értéket tartalmaz-e az operandus.
     * @return true ha this.values[0][0] long.
     */
    public boolean isLongValue() {
        return ((new Apfloat(this.values[0][0].longValue()).compareTo(this.values[0][0])) == 0);
    }

    /**
     * Megmondja, hogy egész értéket tartalmaz-e az operandus.
     * @return true ha this.values[0][0] egész.
     */
    public boolean isIntegerValue() {
        return (this.values[0][0].floor().compareTo(this.values[0][0].ceil()) == 0);
    }

    /**
     * Konstruktor, ami beállítja a pontosságot is.
     * @param precision a pontosság.
     * @param variable az adott szám változó-e.
     */
    public NumberType(long precision, boolean variable) {
        super(1, 1, precision);
        this.variable = variable;
    }

    /**
     * Az alapértelmezett konstruktor.
     */
    public NumberType() {
        super(1, 1);
        this.variable = false;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof NumberType) {
            NumberType op = (NumberType) o;
            return (this.getNumericValue().compareTo(op.getNumericValue()) == 0);
        }
        return false;
    }

    @Override
    public int hashCode() {
        int hash = 7 * this.getNumericValue().intValue();
        return hash;
    }

    @Override
    public String toString() {
        return this.values[0][0].toString(true);
    }

    /**
     * Olyan toString, aminek megmondhatjuk, hogy hány tizedesre írja ki az értéket.
     * @param precision a számjegyek száma.
     * @return az érték.
     */
    public String toString(int precision) {
        if (this.values[0][0].toString(true).length() - this.values[0][0].truncate().toString(true).length() - 1 > precision) {
            return this.values[0][0].toString(true).substring(0, this.values[0][0].truncate().toString(true).length() + precision);
        } else {
            return this.values[0][0].toString(true);
        }
    }

    @Deprecated
    @Override
    public String toXML() {
        StringBuilder sb = new StringBuilder();
        sb.append("<?xml version=\"1.0\"?>\n");
        sb.append("\n<expression>\n");
        sb.append("   <number>");
        sb.append(this.getNumericValue().toString(true));
        sb.append("</number>\n");
        sb.append("</expression>\n");
        return sb.toString();
    }

    @Override
    public void saveToXML(File file) throws FileNotFoundException, IOException, ParserConfigurationException, XMLStreamException {
        file.createNewFile();
        if (!file.canWrite()) {
            throw new FileNotFoundException("CANT_WRITE");
        }
        DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
        builderFactory.setValidating(true);
        DocumentBuilder builder = builderFactory.newDocumentBuilder();
        Document doc = builder.newDocument();
        doc.setXmlVersion("1.0");
        XMLOutputFactory outfact = javax.xml.stream.XMLOutputFactory.newInstance();
        XMLStreamWriter out = outfact.createXMLStreamWriter(new FileOutputStream(file), doc.getXmlEncoding());
        out.writeStartDocument(doc.getXmlEncoding(), doc.getXmlVersion());
        out.writeCharacters("\n");
        //hozzáadjuk a style-sheet-et
        out.writeCharacters("\n");
        out.writeStartElement("?xml-stylesheet type=\"text/xsl\" href=\"" + xmlhandling.XMLBuilder.createXSL(file, false) + "\"?");
        out.writeCharacters("\n");
        out.writeCharacters("\n");
        //comment a tetejére
        out.writeComment("\n" +
                "Author     : " + Properties.getUserName() + "\n" +
                "Description: XMLCalculator output document.\n" +
                "Saved with XMLCalculator.\n");
        out.writeCharacters("\n");
        //hozzáadjuk a xsd-t
        out.writeStartElement("expression");
        out.writeAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
        out.writeAttribute("\nxmlns", "http://localhost/");
        out.writeAttribute("\nxsi:schemaLocation", "http://localhost/ \n" + xmlhandling.XMLBuilder.createXSD(file));
        out.writeAttribute("\nprecision", "" + this.precision);
        out.writeCharacters("\n   ");
        out.writeStartElement("number");
        out.writeCharacters(this.toString(true));
        out.writeEndElement();
        out.writeCharacters("\n");
        out.writeEndElement();
        out.writeCharacters("\n");
        out.close();
    }
}
