package eu.dnetlib.validator2.engine.builtins;

import eu.dnetlib.validator2.engine.Rule;
import eu.dnetlib.validator2.engine.RuleContext;
import eu.dnetlib.validator2.engine.RuleEvaluationException;
import eu.dnetlib.validator2.engine.contexts.XMLContextWithNotConfusedFields;
import eu.dnetlib.validator2.engine.contexts.XPathExpressionProperty;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class XMLNotConfusedFieldsRule implements Rule<Document> {

    private final XMLContextWithNotConfusedFields context;

    protected XMLNotConfusedFieldsRule(XMLContextWithNotConfusedFields context) {
        this.context = context;
    }

    @Override
    public RuleContext getContext() {
        return context;
    }

    @Override //TODO Is a bit different from original evaluation. Needs revisit probably.
    public boolean test(Document doc) throws RuleEvaluationException {
        XPathExpressionProperty xpathExprProp = context.getXPathExpressionProperty();
        Set<String> allNodeValues = new HashSet<>();
        try {
            for (String xpath : context.getFieldsProperty().getXpaths()) {
                xpathExprProp.setValue(xpath);
                NodeList nodesReturned = xpathExprProp.evaluate(doc);
                boolean nodesReturnedAreUnique = context.getNodeListActionProperty().test(nodesReturned, (String v) -> {
                    String val = v.trim().toLowerCase();
                    return allNodeValues.add(val);
                });
                if (!nodesReturnedAreUnique) return false;
            }
            return true;
        } catch (Throwable t) {
            throw new RuleEvaluationException(t.getMessage(), t);
        }
    }

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

    public static class Builder extends AbstractRuleBuilder<XMLNotConfusedFieldsRule, XMLContextWithNotConfusedFields> {

        Builder() {
            super(new StandardXMLContextWithNotConfusedFields());
            initialize();
        }

        private void initialize() {
            context.getXPathExpressionProperty().setValue("notNull");
            context.getNodeListActionProperty().setValue("all");
        }

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

        public Builder setFields(String fields) {
            context.getFieldsProperty().setValue(fields);
            return this;
        }

        @Override
        public XMLNotConfusedFieldsRule build() {
            ensureContextIsValid();
            return new XMLNotConfusedFieldsRule(context);
        }

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

    }

}
