package eu.dnetlib.validator2.validation.guideline.openaire.cris;

import eu.dnetlib.validator2.validation.guideline.Builders;
import eu.dnetlib.validator2.validation.guideline.Cardinality;
import eu.dnetlib.validator2.validation.guideline.ElementSpec;
import eu.dnetlib.validator2.validation.guideline.Guideline;
import eu.dnetlib.validator2.validation.utils.RegexValuePredicate;
import org.w3c.dom.Document;

import java.util.Collection;

import static eu.dnetlib.validator2.validation.utils.SupportedRegExs.*;

public class CrisPublicationV111Profile extends AbstractCrisProfile {

    private static final String[] TYPE_VOCABULARY = {
            "http://purl.org/coar/resource_type/c_18cf", "http://purl.org/coar/resource_type/c_1162",
            "http://purl.org/coar/resource_type/c_86bc", "http://purl.org/coar/resource_type/c_2f33",
            "http://purl.org/coar/resource_type/c_3248", "http://purl.org/coar/resource_type/c_c94f",
            "http://purl.org/coar/resource_type/c_f744", "http://purl.org/coar/resource_type/c_5794",
            "http://purl.org/coar/resource_type/c_6670", "http://purl.org/coar/resource_type/c_18cp",
            "http://purl.org/coar/resource_type/c_18co", "http://purl.org/coar/resource_type/c_8544",
            "http://purl.org/coar/resource_type/c_0857", "http://purl.org/coar/resource_type/c_2659",
            "http://purl.org/coar/resource_type/c_0640", "http://purl.org/coar/resource_type/c_3e5a",
            "http://purl.org/coar/resource_type/c_6501", "http://purl.org/coar/resource_type/c_dcae04bc",
            "http://purl.org/coar/resource_type/c_2df8fbb1", "http://purl.org/coar/resource_type/c_b239",
            "http://purl.org/coar/resource_type/c_beb9", "http://purl.org/coar/resource_type/c_545b",
            "http://purl.org/coar/resource_type/c_816b", "http://purl.org/coar/resource_type/c_93fc",
            "http://purl.org/coar/resource_type/c_ba1f", "http://purl.org/coar/resource_type/c_18ww",
            "http://purl.org/coar/resource_type/c_18wz", "http://purl.org/coar/resource_type/c_18wq",
            "http://purl.org/coar/resource_type/c_186u", "http://purl.org/coar/resource_type/c_18op",
            "http://purl.org/coar/resource_type/c_18hj", "http://purl.org/coar/resource_type/c_18ws",
            "http://purl.org/coar/resource_type/c_18gh", "http://purl.org/coar/resource_type/c_baaf",
            "http://purl.org/coar/resource_type/c_efa0", "http://purl.org/coar/resource_type/c_ba08",
            "http://purl.org/coar/resource_type/c_71bd", "http://purl.org/coar/resource_type/c_8042",
            "http://purl.org/coar/resource_type/c_46ec", "http://purl.org/coar/resource_type/c_7a1f",
            "http://purl.org/coar/resource_type/c_db06", "http://purl.org/coar/resource_type/c_bdcc",
            "http://purl.org/coar/resource_type/c_18cw"
    };

    private static final String[] ISSN_MEDIA_LIST = {
            "http://issn.org/vocabularies/Medium#Print", "http://issn.org/vocabularies/Medium#Online",
            "http://issn.org/vocabularies/Medium#DigitalCarrier", "http://issn.org/vocabularies/Medium#Other"
    };

    //TODO: Add namespace in builder? e.g. fromNamespace("namespace")
    private static final Builders.ElementSpecBuilder TYPE_SPEC = Builders.
            forMandatoryElement("Type", Cardinality.ONE).
            allowedValues(TYPE_VOCABULARY);

    private static final Builders.ElementSpecBuilder LANGUAGE_SPEC = Builders.
            forOptionalElement("Language").
            allowedValues(new RegexValuePredicate(COMPILED_BCP47_LANG_TAGS_REG_EX));

    private static final Builders.ElementSpecBuilder SUBTITLE_SPEC = Builders.
            forOptionalRepeatableElement("Subtitle");

    private static final Builders.ElementSpecBuilder PUBLISHED_IN_SPEC = Builders.
            forOptionalElement("PublishedIn").
            withSubElement(null); //TODO: Pass self

    private static final Builders.ElementSpecBuilder PART_OF_SPEC = Builders.
            forOptionalElement("PartOf").
            withSubElement(null); //TODO: Pass self

    private static final Builders.ElementSpecBuilder PUBLICATION_DATE_SPEC = Builders.
            forOptionalElement("PublicationDate").
            allowedValues(new RegexValuePredicate(COMPILED_YYYY_MM_DD_REGEX)); //TODO: add proper regex

    private static final Builders.ElementSpecBuilder NUMBER_SPEC = Builders.
            forOptionalElement("Number");

    private static final Builders.ElementSpecBuilder VOLUME_SPEC = Builders.
            forOptionalElement("Volume");

    private static final Builders.ElementSpecBuilder ISSUE_SPEC = Builders.
            forOptionalElement("Issue");

    private static final Builders.ElementSpecBuilder EDITION_SPEC = Builders.
            forOptionalElement("Edition");

    private static final Builders.ElementSpecBuilder START_PAGE_SPEC = Builders.
            forOptionalElement("StartPage");

    private static final Builders.ElementSpecBuilder END_PAGE_SPEC = Builders.
            forOptionalElement("EndPage");

    private static final Builders.ElementSpecBuilder PMCID_SPEC = Builders.
            forOptionalElement("PMCID");

    private static final Builders.ElementSpecBuilder ISI_NUMBER_SPEC = Builders.
            forOptionalElement("ISI-Number");

    private static final Builders.ElementSpecBuilder SCP_NUMBER_SPEC = Builders.
            forOptionalElement("SCP-Number");

    private static final Builders.ElementSpecBuilder ISSN_SPEC = Builders.
            forOptionalRepeatableElement("ISSN").
            allowedValues(new RegexValuePredicate(COMPILED_ISSN_REG_EX)).
            withOptionalAttribute("medium", ISSN_MEDIA_LIST);

    private static final Builders.ElementSpecBuilder ISBN_SPEC = Builders.
            forOptionalRepeatableElement("ISBN").
            allowedValues(new RegexValuePredicate(COMPILED_ISBN_REG_EX)).
            withOptionalAttribute("medium", ISSN_MEDIA_LIST);

    private static final Builders.ElementSpecBuilder AUTHORS_SPEC = Builders.
            forOptionalElement("Authors").
            withSubElement(Builders.
                    forOptionalRepeatableElement("Author").
                    withSubElement(Builders.
                            forOptionalElement("DisplayName")).
                    //TODO: Optional 1 of 2 (Person with Affiliation(s), or OrgUnit)
                    withSubElement(PERSON_SPEC). //TODO: Pass proper spec
                    withSubElement(Builders.
                            forOptionalRepeatableElement("Affiliation")).
                    withSubElement(ORG_UNIT_SPEC)); //TODO: Pass proper spec

    private static final Builders.ElementSpecBuilder EDITORS_SPEC = Builders.
            forOptionalElement("Editors").
            withSubElement(Builders.
                    forOptionalRepeatableElement("Editor").
                    withSubElement(Builders.
                            forOptionalElement("DisplayName")).
                    //TODO: Optional 1 of 2 (Person with Affiliation(s), or OrgUnit)
                    withSubElement(PERSON_SPEC). //TODO: Pass proper spec
                    withSubElement(Builders.
                            forOptionalRepeatableElement("Affiliation")).
                    withSubElement(ORG_UNIT_SPEC)); //TODO: Pass proper spec

    private static final Builders.ElementSpecBuilder PUBLISHERS_SPEC = Builders.
            forOptionalElement("Publishers").
            withSubElement(Builders.
                    forOptionalRepeatableElement("Publisher").
                    withSubElement(Builders.
                            forOptionalElement("DisplayName")).
                    //TODO: Optional 1 of 2 (Person or OrgUnit)
                    withSubElement(PERSON_SPEC). //TODO: Pass proper spec
                    withSubElement(ORG_UNIT_SPEC)); //TODO: Pass proper spec

    private static final Builders.ElementSpecBuilder ORIGINATES_FROM_SPEC = Builders.
            forOptionalRepeatableElement("OriginatesFrom").
            //TODO: Optional 1 of (Project or Funding).
            withSubElement(PROJECT_SPEC). //TODO: Pass proper spec
            withSubElement(FUNDING_SPEC); //TODO: Pass proper spec

    private static final Builders.ElementSpecBuilder PRESENTED_AT_SPEC = Builders.
            forOptionalRepeatableElement("PresentedAt").
            withSubElement(EVENT_SPEC); //TODO: Pass proper spec

    private static final Builders.ElementSpecBuilder OUTPUT_FROM_SPEC = Builders.
            forOptionalRepeatableElement("OutputFrom").
            withSubElement(EVENT_SPEC); //TODO: Pass proper spec

    private static final Builders.ElementSpecBuilder COVERAGE_SPEC = Builders.
            forOptionalRepeatableElement("Coverage").
            withSubElement(EVENT_SPEC); //TODO: Pass proper spec

    private static final Builders.ElementSpecBuilder REFERENCES_SPEC = Builders.
            forOptionalRepeatableElement("References").
            //TODO: Optional 1 of 3 (Publication, Patent, Product)
            withSubElement(null).  //TODO: Pass self
            withSubElement(PATENT_SPEC). //TODO: Pass proper spec
            withSubElement(PRODUCT_SPEC); //TODO: Pass proper spec

    private static final ElementSpec PUBLICATION_SPEC = Builders.
            forMandatoryElement("Publication", Cardinality.ONE).
            withMandatoryAttribute("id").
            withSubElement(TYPE_SPEC).
            withSubElement(LANGUAGE_SPEC).
            withSubElement(TITLE_SPEC).
            withSubElement(SUBTITLE_SPEC).
            withSubElement(PUBLISHED_IN_SPEC).
            withSubElement(PART_OF_SPEC).
            withSubElement(PUBLICATION_DATE_SPEC).
            withSubElement(NUMBER_SPEC).
            withSubElement(VOLUME_SPEC).
            withSubElement(ISSUE_SPEC).
            withSubElement(EDITION_SPEC).
            withSubElement(START_PAGE_SPEC).
            withSubElement(END_PAGE_SPEC).
            withSubElement(DOI_SPEC).
            withSubElement(HANDLE_SPEC).
            withSubElement(PMCID_SPEC).
            withSubElement(ISI_NUMBER_SPEC).
            withSubElement(SCP_NUMBER_SPEC).
            withSubElement(ISSN_SPEC).
            withSubElement(ISBN_SPEC).
            withSubElement(URL_SPEC).
            withSubElement(URN_SPEC).
            withSubElement(AUTHORS_SPEC).
            withSubElement(EDITORS_SPEC).
            withSubElement(PUBLISHERS_SPEC).
            withSubElement(LICENSE_SPEC).
            withSubElement(SUBJECT_SPEC).
            withSubElement(KEYWORD_SPEC).
            withSubElement(ABSTRACT_SPEC).
            withSubElement(STATUS_SPEC).
            withSubElement(ORIGINATES_FROM_SPEC).
            withSubElement(PRESENTED_AT_SPEC).
            withSubElement(OUTPUT_FROM_SPEC).
            withSubElement(COVERAGE_SPEC).
            withSubElement(REFERENCES_SPEC).
            withSubElement(NS4_ACCESS_SPEC).
            build();

    public CrisPublicationV111Profile() {
        super("OpenAIRE Guidelines for Publication element of CRIS Managers v1.1.1");
    }

    @Override
    public Collection<? extends Guideline<Document>> guidelines() {
        return null;
    }

    @Override
    public Guideline<Document> guideline(String guidelineName) {
        return null;
    }

    @Override
    public int maxScore() {
        return 0;
    }
}
