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.COMPILED_BCP47_LANG_TAGS_REG_EX;

public class CrisProductV111Profile extends AbstractCrisProfile {

    private static final String[] TYPE_VOCABULARY = {
            "http://purl.org/coar/resource_type/c_e9a0", "http://purl.org/coar/resource_type/c_7ad9",
            "http://purl.org/coar/resource_type/c_ddb1", "http://purl.org/coar/resource_type/c_c513",
            "http://purl.org/coar/resource_type/c_8a7e", "http://purl.org/coar/resource_type/c_12ce",
            "http://purl.org/coar/resource_type/c_ecc8", "http://purl.org/coar/resource_type/c_1843",
            "http://purl.org/coar/resource_type/c_5ce6", "http://purl.org/coar/resource_type/c_393c",
            "http://purl.org/coar/resource_type/c_12cc", "http://purl.org/coar/resource_type/c_12cd",
            "http://purl.org/coar/resource_type/c_18cc", "http://purl.org/coar/resource_type/c_18cd"
    };

    private static final Builders.ElementSpecBuilder TYPE_SPEC = Builders.
            forMandatoryElement("Type", Cardinality.ONE).
            allowedValues(TYPE_VOCABULARY);

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

    private static final Builders.ElementSpecBuilder ARK_SPEC = Builders.
            forOptionalElement("ARK");

    private static final Builders.ElementSpecBuilder CREATORS_SPEC = Builders.
            forOptionalElement("Creators").
            withSubElement(Builders.forOptionalRepeatableElement("Creator").
                    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 PART_OF_SPEC = Builders.
            forOptionalElement("PartOf").
            //TODO: Optional 1 of 3 (Publication, Patent, Product)
            withSubElement(PUBLICATION_SPEC). //TODO: Pass proper spec
            withSubElement(PATENT_SPEC). //TODO: Pass proper spec
            withSubElement(null); //TODO: Pass self spec

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

    private static final Builders.ElementSpecBuilder GENERATED_BY_SPEC = Builders.
            forOptionalRepeatableElement("GeneratedBy").
            withSubElement(EQUIPMENT_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 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(PUBLICATION_SPEC).  //TODO: Pass proper spec
            withSubElement(PATENT_SPEC). //TODO: Pass proper spec
            withSubElement(null); //TODO: Pass self spec

    private static final ElementSpec PRODUCT_SPEC = Builders.
            forMandatoryElement("Product", Cardinality.ONE).
            withMandatoryAttribute("id").
            withSubElement(TYPE_SPEC).
            withSubElement(LANGUAGE_SPEC).
            withSubElement(NAME_SPEC).
            withSubElement(VERSION_INFO_SPEC).
            withSubElement(ARK_SPEC).
            withSubElement(DOI_SPEC).
            withSubElement(HANDLE_SPEC).
            withSubElement(URL_SPEC).
            withSubElement(URN_SPEC).
            withSubElement(CREATORS_SPEC).
            withSubElement(PUBLISHERS_SPEC).
            withSubElement(LICENSE_SPEC).
            withSubElement(DESCRIPTION_SPEC).
            withSubElement(SUBJECT_SPEC).
            withSubElement(KEYWORD_SPEC).
            withSubElement(PART_OF_SPEC).
            withSubElement(ORIGINATES_FROM_SPEC).
            withSubElement(GENERATED_BY_SPEC).
            withSubElement(PRESENTED_AT_SPEC).
            withSubElement(COVERAGE_SPEC).
            withSubElement(REFERENCES_SPEC).
            withSubElement(NS4_ACCESS_SPEC).
            build();

    public CrisProductV111Profile() {
        super("OpenAIRE Guidelines for Product 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;
    }
}
