package eu.dnetlib.validator2.engine.builtins;

import eu.dnetlib.validator2.engine.contexts.TermsProperty;
import eu.dnetlib.validator2.engine.contexts.XMLContextWithVocabulary;
import org.w3c.dom.NodeList;

import java.util.Map;
import java.util.function.Predicate;

public class XMLVocabularyRule extends XMLRule<XMLContextWithVocabulary> {

    protected XMLVocabularyRule(XMLContextWithVocabulary context) {
        super(context, (NodeList nodes) -> {
            TermsProperty terms = context.getTermsProperty();
            boolean result = context.getNodeListActionProperty().test(nodes, (Predicate<String>) terms::termExists);

            String termsType = context.getTermsTypeProperty().getValue().toLowerCase();

            //TODO: Check original implementation for blacklist/whitelist. It looks weird.
            if (termsType.equals("blacklist")) return !result;
            return result;
        });
    }

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder extends AbstractRuleBuilder<XMLVocabularyRule, XMLContextWithVocabulary> {

        private Builder() {
            super(new StandardXMLContextWithVocabulary());
        }

        public Builder setId(String id) {
            context.getIdProperty().setValue(id);
            return this;
        }

        public Builder setXPathExpression(String xpath) {
            context.getXPathExpressionProperty().setValue(xpath);
            return this;
        }

        public Builder setNodeListAction(String nodeListAction) throws RuntimeException {
            context.getNodeListActionProperty().setValue(nodeListAction);
            return this;
        }

        public Builder setVocabularyTerms(String terms) {
            context.getTermsProperty().setValue(terms);
            return this;
        }

        public Builder setVocabularyTermsAndTermsType(String terms, String termsType) {
            context.getTermsProperty().setValue(terms);
            context.getTermsTypeProperty().setValue(termsType);
            return this;
        }

        private void initializeOptionalTermsTypeProperty() {
            if (context.getTermsTypeProperty().getValue() == null) {
                context.getTermsTypeProperty().setValue("blacklist");
            }
        }

        public XMLVocabularyRule build() {
            initializeOptionalTermsTypeProperty();
            ensureContextIsValid();
            return new XMLVocabularyRule(context);
        }

        @Override
        public XMLVocabularyRule buildFrom(Map<String, String> map) {
            context.readFrom(map);
            initializeOptionalTermsTypeProperty();
            ensureContextIsValid();
            return new XMLVocabularyRule(context);
        }
    }

}
