package eu.eudat.logic.services.forms;

import eu.eudat.models.data.user.components.commons.Rule;

import java.util.*;

/**
 * Created by ikalyvas on 3/5/2018.
 */
public class VisibilityRuleServiceImpl implements VisibilityRuleService {
    private final Map<String, Boolean> elementVisibility = new HashMap<>();
    private Map<String, Object> properties;

    public boolean isElementVisible(String id) {
        return !this.elementVisibility.containsKey(id) || this.elementVisibility.get(id);
    }

    public void setProperties(Map<String, Object> properties) {
        this.properties = properties;
        this.properties.entrySet().stream()
                .filter(stringObjectEntry -> stringObjectEntry.getValue() instanceof String && ((String) stringObjectEntry.getValue()).startsWith("[")
                        && ((String) stringObjectEntry.getValue()).endsWith("]"))
                .forEach(stringObjectEntry -> stringObjectEntry.setValue(parseArray((String) stringObjectEntry.getValue())));
    }

    private List<String> parseArray(String original) {
        String parsed = original.replace("[", "").replace("\"", "").replace("]", "");
        return Arrays.asList(parsed.split(","));
    }

    public void buildVisibilityContext(List<Rule> sources) {
        VisibilityContext visibilityContext = new VisibilityContext();
        visibilityContext.buildVisibilityContext(sources);
        visibilityContext.getVisibilityRules().forEach(this::evaluateVisibility);
    }

    private void evaluateVisibility(VisibilityRule rule) {
        List<VisibilityRuleSource> sources = rule.getVisibilityRuleSources();
        for(VisibilityRuleSource source: sources){
            if (properties.containsKey(source.getVisibilityRuleSourceId())
                    && isContained(properties.get(source.getVisibilityRuleSourceId()), source.getVisibilityRuleSourceValue())) {
                this.elementVisibility.put(rule.getVisibilityRuleTargetId(), true);
            } else {
                this.elementVisibility.put(rule.getVisibilityRuleTargetId(),
                        this.elementVisibility.getOrDefault(rule.getVisibilityRuleTargetId(), false));
            }
        }
    }

    private Boolean isContained(Object values, String source) {
        if (values instanceof List) {
            return ((Collection<?>) values).contains(source);
        } else {
            if (values != null) {
                return values.equals(source);
            }
            return false;
        }
    }
}
