package eu.eudat.logic.utilities.documents.xml.datasetProfileXml;


import eu.eudat.models.data.admin.components.datasetprofile.Page;
import eu.eudat.models.data.components.commons.ViewStyle;
import eu.eudat.models.data.components.commons.datafield.*;
import eu.eudat.models.data.user.components.datasetprofile.Field;
import eu.eudat.models.data.user.components.datasetprofile.FieldSet;
import eu.eudat.models.data.user.components.datasetprofile.Section;
import eu.eudat.logic.utilities.builders.XmlBuilder;

import org.springframework.core.env.Environment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.UUID;


public class ExportXmlBuilderDatasetProfile {


    public File build(eu.eudat.models.data.user.composite.DatasetProfile datasetProfile, Environment environment) throws IOException {

        File xmlFile = new File(environment.getProperty("temp.temp") + UUID.randomUUID() + ".xml");
        BufferedWriter writer = new BufferedWriter(new FileWriter(xmlFile, true));
        Document xmlDoc = XmlBuilder.getDocument();
//        Element root = xmlDoc.createElement("root");
//        root.appendChild(createPages(datasetProfile.getPages(), datasetProfile.getSections(), xmlDoc));

        xmlDoc.appendChild(createPages(datasetProfile.getPages(), datasetProfile.getSections(), xmlDoc));
        Element pages = (Element)xmlDoc.getFirstChild();
        pages.setAttribute("description", datasetProfile.getDescription());
        pages.setAttribute("language", datasetProfile.getLanguage());
        String xml = XmlBuilder.generateXml(xmlDoc);
        writer.write(xml);
        writer.close();
        return xmlFile;
    }

    public Element createPages(List<Page> datasetProfilePages, List<Section> sections, Document element) {
        Element pages = element.createElement("pages");
        datasetProfilePages.forEach(item -> {
            Element page = element.createElement("page");
            page.setAttribute("id", "" + item.getId());
            page.setAttribute("ordinal", "" + item.getOrdinal());
            page.setAttribute("title", "" + item.getTitle());
            sections.forEach(sectionFromLis -> {
                if (sectionFromLis.getPage().equals(item.getId())) {
                    Element elementSections = element.createElement("sections");
                    page.appendChild(createSections(sectionFromLis, element, elementSections));
                }
            });
            pages.appendChild(page);
        });
        return pages;
    }


    public Element createSections(Section sections, Document element, Element elementSections) {
//        if (sections.getSections() != null) {
            sections.getSections().forEach(sectionFor -> {
                Element elementSectionsChild = element.createElement("section");
                elementSections.appendChild(createSections(sectionFor, element, elementSectionsChild));
            });
//        }

        elementSections.setAttribute("defaultVisibility", "" + sections.getDefaultVisibility());
        elementSections.setAttribute("id", "" + sections.getId());
        elementSections.setAttribute("ordinal", "" + sections.getOrdinal());
        elementSections.setAttribute("page", "" + sections.getPage());
        elementSections.setAttribute("page", "" + sections.getPage());

        if (sections.getCompositeFields() != null) {
            elementSections.appendChild(createFieldSet(sections.getCompositeFields(), element));
        }

        if (sections.getNumbering() != null) {
            Element numbering = element.createElement("numbering");
            numbering.setTextContent(sections.getNumbering());
            elementSections.appendChild(numbering);
        }
        if (sections.getDescription() != null) {
            Element description = element.createElement("description");
            description.setTextContent(sections.getDescription());
            elementSections.appendChild(description);
        }
        if (sections.getTitle() != null) {
            Element title = element.createElement("title");
            title.setTextContent(sections.getTitle());
            elementSections.appendChild(title);
        }

        return elementSections;
    }

    public Element createFieldSet(List<FieldSet> fieldSet, Document element) {
        Element elementFieldSets = element.createElement("field-Sets");
        fieldSet.forEach(field -> {
            Element composite = element.createElement("field-Set");
            composite.setAttribute("id", field.getId());
            composite.setAttribute("ordinal", "" + field.getOrdinal());

            if (field.getNumbering() != null) {
                Element numbering = element.createElement("numbering");
                numbering.setTextContent(field.getNumbering());
                composite.appendChild(numbering);
            }
            Element commentField = element.createElement("CommentField");
            commentField.setTextContent("" + field.getHasCommentField());
            composite.appendChild(commentField);

            composite.appendChild(createFields(field.getFields(), element));

            if (field.getMultiplicity() != null) {
                Element multiplicity = element.createElement("multiplicity");
                multiplicity.setAttribute("max", "" + field.getMultiplicity().getMax());
                multiplicity.setAttribute("min", "" + field.getMultiplicity().getMin());
                multiplicity.setAttribute("placeholder", field.getMultiplicity().getPlaceholder());
                composite.appendChild(multiplicity);
            }
            if (field.getTitle() != null && !field.getTitle().isEmpty()) {
                Element title = element.createElement("title");
                title.setTextContent(field.getTitle());
                composite.appendChild(title);
            }
            if (field.getDescription() != null && !field.getDescription().isEmpty()) {
                Element title = element.createElement("description");
                title.setTextContent(field.getDescription());
                composite.appendChild(title);
            }
            if (field.getExtendedDescription() != null && !field.getExtendedDescription().isEmpty()) {
                Element extendedDescription = element.createElement("extendedDescription");
                extendedDescription.setTextContent(field.getExtendedDescription());
                composite.appendChild(extendedDescription);
            }
            if (field.getAdditionalInformation() != null && !field.getAdditionalInformation().isEmpty()) {
                Element additionalInformation = element.createElement("additionalInformation");
                additionalInformation.setTextContent(field.getAdditionalInformation());
                composite.appendChild(additionalInformation);
            }


            elementFieldSets.appendChild(composite);
        });
        return elementFieldSets;
    }


    public Element createFields(List<Field> fields, Document element) {
        Element elementFields = element.createElement("fields");
        fields.forEach(field -> {
            Element elementField = element.createElement("field");
            elementField.setAttribute("id", field.getId());
            elementField.setAttribute("ordinal", "" + field.getOrdinal());

            if (field.getNumbering() != null) {
                Element numbering = element.createElement("numbering");
                numbering.setTextContent(field.getNumbering());
                elementField.appendChild(numbering);
            }
            if (field.getRdaProperty() != null) {
                Element rdaProperty = element.createElement("rdaProperty");
                rdaProperty.setTextContent(field.getRdaProperty());
                elementField.appendChild(rdaProperty);
            }
            if (field.getValidations() != null) {
                Element validations = element.createElement("validations");
                field.getValidations().forEach(validation -> {
                    Element validationChild = element.createElement("validation");
                    validationChild.setAttribute("type", "" + validation);
                    validations.appendChild(validationChild);
                });
                elementField.appendChild(validations);
            }
            if (field.getDefaultValue() != null) {
                Element defaultValue = element.createElement("defaultValue");
                defaultValue.setAttribute("type", field.getDefaultValue().getType());
                defaultValue.setAttribute("value", field.getDefaultValue().getValue());
                elementField.appendChild(defaultValue);
            }
            if (field.getVisible() != null) {
                Element visible = element.createElement("visible");
                visible.setAttribute("style", "" + field.getVisible().getStyle());
                field.getVisible().getRules().forEach(rule -> {
                    Element ruleChild = element.createElement("rule");
                    ruleChild.setAttribute("ruleStyle", "" + rule.getRuleStyle());
                    ruleChild.setAttribute("target", "" + rule.getTarget());
                    ruleChild.setAttribute("type", "" + rule.getRuleType());
                    Element ruleChildValue = element.createElement("value");
                    ruleChildValue.setAttribute("type", "" + rule.getValueType());
                    ruleChildValue.setTextContent(rule.getValue());
                    ruleChild.appendChild(ruleChildValue);
                    visible.appendChild(ruleChild);

                });
                elementField.appendChild(visible);
            }
            if (field.getViewStyle() != null) {
                Element viewStyle = element.createElement("viewStyle");
                viewStyle.setAttribute("cssClass", field.getViewStyle().getCssClass());
                viewStyle.setAttribute("renderStyle", field.getViewStyle().getRenderStyle());
                elementField.appendChild(viewStyle);
            }

            if (field.getData() != null) {
                Element dataOut = element.createElement("data");
                ViewStyle.Type viewStyleType = ViewStyle.Type.fromName(field.getViewStyle().getRenderStyle());
                switch (viewStyleType) {
                    case COMBO_BOX:
                        ComboBoxData comboBoxDataObject = (ComboBoxData) field.getData();
                        if (comboBoxDataObject.getType().equals("wordlist")) {
                            WordListData wordListDataObject = (WordListData) field.getData();
                            dataOut.setAttribute("label", wordListDataObject.getLabel());
                            dataOut.setAttribute("type", wordListDataObject.getType());
                            dataOut.setAttribute("multiList", wordListDataObject.getMultiList().toString());
                            Element options = element.createElement("options");
                            wordListDataObject.getOptions().forEach(optionChildFor -> {
                                Element optionChild = element.createElement("option");
                                optionChild.setAttribute("label", optionChildFor.getLabel());
                                optionChild.setAttribute("value", optionChildFor.getValue());
                                options.appendChild(optionChild);
                            });
                            dataOut.appendChild(options);
                        } else if (comboBoxDataObject.getType().equals("autocomplete")) {
                            AutoCompleteData autoCompleteDataObject = (AutoCompleteData) field.getData();
                            dataOut.setAttribute("label", autoCompleteDataObject.getLabel());
                            dataOut.setAttribute("type", autoCompleteDataObject.getType());
                            dataOut.setAttribute("multiAutoComplete", autoCompleteDataObject.getMultiAutoComplete().toString());
                            for (AutoCompleteData.AutoCompleteSingleData singleData: autoCompleteDataObject.getAutoCompleteSingleDataList()) {
                                Element singleItem = element.createElement("autocompleteSingle");
                                singleItem.setAttribute("optionsRoot", singleData.getOptionsRoot());
                                singleItem.setAttribute("url", singleData.getUrl());
                                singleItem.setAttribute("autoCompleteType", Integer.toString(singleData.getAutocompleteType()));
                                if (singleData.getAutoCompleteOptions() != null) {
                                    Element optionChild = element.createElement("option");
                                    optionChild.setAttribute("label", singleData.getAutoCompleteOptions().getLabel());
                                    optionChild.setAttribute("value", singleData.getAutoCompleteOptions().getValue());
                                    singleItem.appendChild(optionChild);
                                }
                                dataOut.appendChild(singleItem);
                            }
                        }
                        break;
                    case UPLOAD:
                        UploadData uploadDataObject = (UploadData) field.getData();
                        dataOut.setAttribute("label", uploadDataObject.getLabel());
                        dataOut.setAttribute("maxFileSizeInMB", String.valueOf(uploadDataObject.getMaxFileSizeInMB()));
                        Element types = element.createElement("types");
                        uploadDataObject.getTypes().forEach(type -> {
                            Element optionChild = element.createElement("option");
                            optionChild.setAttribute("label", type.getLabel());
                            optionChild.setAttribute("value", type.getValue());
                            types.appendChild(optionChild);
                        });
                        dataOut.appendChild(types);
                        break;
                    case BOOLEAN_DECISION:
                        BooleanDecisionData booleanDecisionDataObject = (BooleanDecisionData) field.getData();
                        dataOut.setAttribute("label", booleanDecisionDataObject.getLabel());
                        break;
                    case RADIO_BOX:
                        RadioBoxData radioBoxDataObject = (RadioBoxData) field.getData();
                        dataOut.setAttribute("label", radioBoxDataObject.getLabel());

                        Element options = element.createElement("options");
                        radioBoxDataObject.getOptions().forEach(optionChildFor -> {
                            Element optionChild = element.createElement("option");
                            optionChild.setAttribute("label", optionChildFor.getLabel());
                            optionChild.setAttribute("value", optionChildFor.getValue());
                            options.appendChild(optionChild);
                        });
                        dataOut.appendChild(options);
                        break;
                    case CHECK_BOX:
                    case FREE_TEXT:
                    case TEXT_AREA:
                    case RICH_TEXT_AREA:
                    case DATE_PICKER:
                    case DATASET_IDENTIFIER:
                    case CURRENCY:
                    case TAGS:
                        FieldData fieldDataObject = (FieldData) field.getData();
                        dataOut.setAttribute("label", fieldDataObject.getLabel());
                        break;
                    case INTERNAL_DMP_ENTRIES:
                        InternalDmpEntitiesData internalDmpEntitiesData = (InternalDmpEntitiesData) field.getData();
                        dataOut.setAttribute("label", internalDmpEntitiesData.getLabel());
                        dataOut.setAttribute("type", internalDmpEntitiesData.getType());
                        switch (internalDmpEntitiesData.getType()) {
                            case "researchers":
                                ResearchersAutoCompleteData researchersAutoCompleteData = (ResearchersAutoCompleteData) internalDmpEntitiesData;
                                dataOut.setAttribute("multiAutocomplete", researchersAutoCompleteData.getMultiAutoComplete().toString());
                                break;
                            case "datasets":
                                DatasetsAutoCompleteData datasetsAutoCompleteData = (DatasetsAutoCompleteData) internalDmpEntitiesData;
                                dataOut.setAttribute("multiAutocomplete", datasetsAutoCompleteData.getMultiAutoComplete().toString());
                                break;
                            case "dmps":
                                DMPsAutoCompleteData dmPsAutoCompleteData = (DMPsAutoCompleteData) internalDmpEntitiesData;
                                dataOut.setAttribute("multiAutocomplete", dmPsAutoCompleteData.getMultiAutoComplete().toString());
                                break;
                        }
                        break;
                    case EXTERNAL_DATASETS:
                        ExternalDatasetsData externalDatasetsData = (ExternalDatasetsData) field.getData();
                        dataOut.setAttribute("label", externalDatasetsData.getLabel());
                        dataOut.setAttribute("multiAutocomplete", externalDatasetsData.getMultiAutoComplete().toString());
                        dataOut.setAttribute("type", externalDatasetsData.getType());
                        break;
                    case DATA_REPOSITORIES:
                    case JOURNAL_REPOSITORIES:
                    case PUB_REPOSITORIES:
                        DataRepositoriesData dataRepositoriesData = (DataRepositoriesData) field.getData();
                        dataOut.setAttribute("label", dataRepositoriesData.getLabel());
                        dataOut.setAttribute("multiAutocomplete", dataRepositoriesData.getMultiAutoComplete().toString());
                        break;
                    case TAXONOMIES:
                        TaxonomiesData taxonomiesData = (TaxonomiesData) field.getData();
                        dataOut.setAttribute("label", taxonomiesData.getLabel());
                        dataOut.setAttribute("multiAutocomplete", taxonomiesData.getMultiAutoComplete().toString());
                        break;
                    case LICENSES:
                        LicensesData licensesData = (LicensesData) field.getData();
                        dataOut.setAttribute("label", licensesData.getLabel());
                        dataOut.setAttribute("multiAutocomplete", licensesData.getMultiAutoComplete().toString());
                        break;
                    case PUBLICATIONS:
                        PublicationsData publicationsData = (PublicationsData) field.getData();
                        dataOut.setAttribute("label", publicationsData.getLabel());
                        dataOut.setAttribute("multiAutocomplete", publicationsData.getMultiAutoComplete().toString());
                        break;
                    case ORGANIZATIONS:
                        OrganizationsData organizationsData = (OrganizationsData) field.getData();
                        dataOut.setAttribute("label", organizationsData.getLabel());
                        dataOut.setAttribute("multiAutocomplete", organizationsData.getMultiAutoComplete().toString());
                        break;
                    case RESEARCHERS:
                        ResearcherData researcherData = (ResearcherData) field.getData();
                        dataOut.setAttribute("label", researcherData.getLabel());
                        dataOut.setAttribute("multiAutocomplete", researcherData.getMultiAutoComplete().toString());
                        break;
                    case REGISTRIES:
                        RegistriesData registriesData = (RegistriesData) field.getData();
                        dataOut.setAttribute("label", registriesData.getLabel());
                        dataOut.setAttribute("multiAutocomplete", registriesData.getMultiAutoComplete().toString());
                        break;
                    case SERVICES:
                        ServicesData servicesData = (ServicesData) field.getData();
                        dataOut.setAttribute("label", servicesData.getLabel());
                        dataOut.setAttribute("multiAutocomplete", servicesData.getMultiAutoComplete().toString());
                        break;

                }
                elementField.appendChild(dataOut);
            }

            elementFields.appendChild(elementField);
        });
        return elementFields;
    }

}
