
package de.ugoe.cs.autoquest.usability.evaluation.rule.evaluator;

import java.util.Map;

import com.google.common.base.Optional;
import com.google.common.collect.Maps;

import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskTree;
import de.ugoe.cs.autoquest.usability.evaluation.result.UsabilityDefect;
import de.ugoe.cs.autoquest.usability.evaluation.result.UsabilityDefectFactory;
import de.ugoe.cs.autoquest.usability.evaluation.result.UsabilityDefectSeverityLevel;
import de.ugoe.cs.autoquest.usability.evaluation.result.UsabilityDefectXmlDescriptionResolver;
import de.ugoe.cs.autoquest.usability.evaluation.rule.set.UsabilityRule;
import de.ugoe.cs.autoquest.usability.tasktree.filter.FilterStatistic;
import de.ugoe.cs.autoquest.usability.tasktree.filter.FilterStatisticCache;
import de.ugoe.cs.autoquest.usability.tasktree.filter.TaskTreeNodeFilter;

public abstract class RuleEvaluator {

    protected final UsabilityRule evaluatedUsabilityRule;

    protected final FilterStatistic filteredNodes;

    protected Map<String, String> defectDescriptionMessageParameterValues = Maps.newHashMap();

    public RuleEvaluator(UsabilityRule evaluatedUsabilityRule, ITaskTree taskTree) {
        this.evaluatedUsabilityRule = evaluatedUsabilityRule;
        this.filteredNodes = nodesUnderEvaluation(taskTree);
    }

    protected abstract FilterStatistic nodesUnderEvaluation(ITaskTree taskTree);

    @SuppressWarnings("rawtypes")
    protected Optional<FilterStatistic> loadFromCache(TaskTreeNodeFilter nodeFilter) {
        return FilterStatisticCache.instance().getFilterStatistic(nodeFilter);
    }

    @SuppressWarnings("rawtypes")
    protected FilterStatistic cacheAndReturnNodes(ITaskTree taskTree, TaskTreeNodeFilter nodeFilter) {
        FilterStatistic textInputEvents = extractNodesFromTaskTree(taskTree);
        FilterStatisticCache.instance().addFilterStatistic(nodeFilter, textInputEvents);
        return textInputEvents;
    }

    protected abstract FilterStatistic extractNodesFromTaskTree(ITaskTree taskTree);

    public Optional<UsabilityDefect> evaluationResult() {
        Optional<UsabilityDefect> ruleEvaluationResult = Optional.absent();
        float evaluationMetric = calculateEvaluationMetric();
        Optional<UsabilityDefectSeverityLevel> severityLevel =
            determineSeverityLevel(evaluationMetric);
        if (severityLevel.isPresent()) {
            ruleEvaluationResult =
                Optional.of(createRuleEvaluationResult(severityLevel.get()));
        }
        return ruleEvaluationResult;
    }

    protected abstract float calculateEvaluationMetric();
    
    protected void storeEvaluationMetricForDefectDescription(String key, String value) {
        defectDescriptionMessageParameterValues.put(key, value);
    }

    protected abstract Optional<UsabilityDefectSeverityLevel> determineSeverityLevel(float evaluationMetric);

    public UsabilityDefect createRuleEvaluationResult(UsabilityDefectSeverityLevel severityLevelOfDefect) {
        return new UsabilityDefectFactory(UsabilityDefectXmlDescriptionResolver.instance())
            .createUsabilityGuidlineRecommendation(severityLevelOfDefect,
                                                   evaluatedUsabilityRule,
                                                   defectDescriptionMessageParameterValues);
    }
}
