package eu.eudat.models.data.entities.xmlmodels.datasetprofiledefinition;

import eu.eudat.models.data.components.commons.DefaultValue;
import eu.eudat.models.data.components.commons.ViewStyle;
import eu.eudat.models.data.components.commons.Visibility;
import eu.eudat.models.data.components.commons.datafield.FieldData;
import eu.eudat.logic.utilities.interfaces.XmlSerializable;
import eu.eudat.logic.utilities.builders.ModelBuilder;
import eu.eudat.logic.utilities.builders.XmlBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.util.LinkedList;
import java.util.List;

public class Field implements DatabaseViewStyleDefinition, XmlSerializable<Field> {
    private String id;
    private int ordinal;
    private String rdaCommonStandard;
    private String numbering;
    private ViewStyle viewStyle;
    private DefaultValue defaultValue;
    private Visibility visible;
    private FieldData data;
    private List<eu.eudat.models.data.admin.components.datasetprofile.Field.ValidationType> validations;

    private Boolean export;

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }

    public int getOrdinal() {
        return ordinal;
    }
    public void setOrdinal(int ordinal) {
        this.ordinal = ordinal;
    }

    public String getRdaCommonStandard() {
        return rdaCommonStandard;
    }
    public void setRdaCommonStandard(String rdaCommonStandard) {
        this.rdaCommonStandard = rdaCommonStandard;
    }

    public ViewStyle getViewStyle() {
        return viewStyle;
    }
    public void setViewStyle(ViewStyle viewStyle) {
        this.viewStyle = viewStyle;
    }

    public FieldData getData() {
        return data;
    }
    public void setData(FieldData data) {
        this.data = data;
    }

    public DefaultValue getDefaultValue() {
        return defaultValue;
    }
    public void setDefaultValue(DefaultValue defaultValue) {
        this.defaultValue = defaultValue;
    }

    public Visibility getVisible() {
        return visible;
    }
    public void setVisible(Visibility visible) {
        this.visible = visible;
    }

    public List<eu.eudat.models.data.admin.components.datasetprofile.Field.ValidationType> getValidations() {
        return validations;
    }
    public void setValidations(List<eu.eudat.models.data.admin.components.datasetprofile.Field.ValidationType> validations) {
        this.validations = validations;
    }

    public String getNumbering() {
        return numbering;
    }
    public void setNumbering(String numbering) {
        this.numbering = numbering;
    }

    public Boolean getExport() {
        return export;
    }

    public void setExport(Boolean export) {
        this.export = export;
    }

    @Override
    public Element toXml(Document doc) {
        Element rootElement = doc.createElement("field");
        rootElement.setAttribute("id", this.id);
        rootElement.setAttribute("ordinal", "" + this.ordinal);

        Element rdaCommonStandard = doc.createElement("rdaCommonStandard");
        rdaCommonStandard.setTextContent(this.rdaCommonStandard);

        Element viewStyle = doc.createElement("viewStyle");
        viewStyle.setAttribute("renderstyle", this.viewStyle.getRenderStyle());
        viewStyle.setAttribute("cssClass", this.viewStyle.getCssClass());

        Element visibility = this.visible.toXml(doc);

        Element defaultValue = doc.createElement("defaultValue");
        defaultValue.setAttribute("type", this.defaultValue.getType());
        defaultValue.setAttribute("value", this.defaultValue.getValue());

        Element validations = doc.createElement("validations");
        for (eu.eudat.models.data.admin.components.datasetprofile.Field.ValidationType validationType : this.validations) {
            Element validation = doc.createElement("validation");
            validation.setAttribute("type", "" + validationType.getValue());
            validations.appendChild(validation);
        }

        Element numbering = doc.createElement("numbering");
        numbering.setTextContent(this.numbering);

        rootElement.appendChild(rdaCommonStandard);
        rootElement.appendChild(numbering);
        rootElement.appendChild(validations);
        rootElement.appendChild(defaultValue);
        rootElement.appendChild(visibility);
        rootElement.appendChild(viewStyle);
        if (this.data != null) rootElement.appendChild(this.data.toXml(doc));
        rootElement.setAttribute("export", this.export == null || this.export ? "true" : "false");
        return rootElement;
    }

    @Override
    public Field fromXml(Element element) {
        this.id = element.getAttribute("id");
        this.ordinal = Integer.parseInt(element.getAttribute("ordinal"));


        this.viewStyle = new ViewStyle();
        Element viewStyle = (Element) XmlBuilder.getNodeFromListByTagName(element.getChildNodes(), "viewStyle");

        this.viewStyle.setRenderStyle(viewStyle.getAttribute("renderstyle"));
        this.viewStyle.setCssClass(viewStyle.getAttribute("cssClass"));

        Element visibility = (Element) XmlBuilder.getNodeFromListByTagName(element.getChildNodes(), "visible");

        this.visible = new Visibility().fromXml(visibility);

        Element numbering = XmlBuilder.getNodeFromListByTagName(element.getChildNodes(), "numbering");
        if (numbering != null) this.numbering = numbering.getTextContent();

        Element rdaCommonStandard = XmlBuilder.getNodeFromListByTagName(element.getChildNodes(), "rdaCommonStandard");
        if (rdaCommonStandard != null) this.rdaCommonStandard = rdaCommonStandard.getTextContent();

        Element dataElement = (Element) XmlBuilder.getNodeFromListByTagName(element.getChildNodes(), "data");

        Element defaultValue = (Element) XmlBuilder.getNodeFromListByTagName(element.getChildNodes(), "defaultValue");

        this.defaultValue = new DefaultValue();
        this.defaultValue.setType(defaultValue.getAttribute("type"));
        this.defaultValue.setValue(defaultValue.getAttribute("value"));
        this.data = new ModelBuilder().toFieldData(null, this.viewStyle.getRenderStyle(), dataElement);
        if (this.data != null) this.data.fromXml(dataElement);

        this.validations = new LinkedList<>();
        Element validations = (Element) XmlBuilder.getNodeFromListByTagName(element.getChildNodes(), "validations");
        if (validations != null) {
            NodeList validationElements = validations.getChildNodes();
            for (int temp = 0; temp < validationElements.getLength(); temp++) {
                Node validationElement = validationElements.item(temp);
                if (validationElement.getNodeType() == Node.ELEMENT_NODE) {
                    int enumValue = Integer.parseInt(((Element) validationElement).getAttribute("type"));
                    eu.eudat.models.data.admin.components.datasetprofile.Field.ValidationType validationType = eu.eudat.models.data.admin.components.datasetprofile.Field.ValidationType.fromInteger(enumValue);
                    this.validations.add(validationType);
                }
            }
        }
        if (element.hasAttribute("export")) {
            this.export = Boolean.parseBoolean(element.getAttribute("export"));
        } else {
            this.export = true;
        }
        return this;
    }

}
