//   Copyright 2012 Georg-August-Universität Göttingen, Germany
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

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;

/**
 * <p>
 * TODO comment
 * </p>
 * 
 * @author Alexander Deicke
 */
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);
    }
}
