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

import static de.ugoe.cs.autoquest.usability.tasktree.filter.EventTypeFilter.TEXT_INPUT;

import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;

import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskTree;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskTreeNode;
import de.ugoe.cs.autoquest.usability.evaluation.result.UsabilityDefectSeverityLevel;
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.IterativeDFSFilterStrategy;
import de.ugoe.cs.autoquest.usability.tasktree.filter.TaskTreeFilter;

public class TextInputRatioEvaluator extends RuleEvaluator {

    public TextInputRatioEvaluator(UsabilityRule evaluatedUsabilityRule, ITaskTree taskTree) {
        super(evaluatedUsabilityRule, taskTree);
    }

    @Override
    protected FilterStatistic nodesUnderEvaluation(ITaskTree taskTree) {
        Optional<FilterStatistic> cachedNodes = loadFromCache(TEXT_INPUT);
        return cachedNodes.isPresent() ? cachedNodes.get() : cacheAndReturnNodes(taskTree, TEXT_INPUT);
    }

    @Override
    protected FilterStatistic extractNodesFromTaskTree(ITaskTree taskTree) {
        return new TaskTreeFilter(new IterativeDFSFilterStrategy()).filterByEventType(TEXT_INPUT).from(taskTree);
    }

    @Override
    protected float calculateEvaluationMetric() {
        float textInputEvents = this.filteredNodes.nrOfNodesMatchedFilter();
        float nonTextInputEvents = nrOfEventNodesNotMatchedFilter();
        return textInputEvents / (textInputEvents + nonTextInputEvents);
    }
    
    private int nrOfEventNodesNotMatchedFilter() {
        return Iterables.size(
            Iterables.filter(this.filteredNodes.nodesNotMatchedFilter(), new Predicate<ITaskTreeNode>() {
            
                @Override
                public boolean apply(ITaskTreeNode node) {
                    return  (node.getChildren() == null) || (node.getChildren().size() == 0);
                }
            })
        );
    }

    @Override
    protected Optional<UsabilityDefectSeverityLevel> determineSeverityLevel(float evaluationMetric) {
        Optional<UsabilityDefectSeverityLevel> recommendationSeverityLevel = Optional.absent();
        if (evaluationMetric > 0.9) {
            recommendationSeverityLevel = Optional.of(UsabilityDefectSeverityLevel.HIGH);
        }
        else if (evaluationMetric > 0.7) {
            recommendationSeverityLevel = Optional.of(UsabilityDefectSeverityLevel.MEDIUM);
        }
        else if (evaluationMetric > 0.5) {
            recommendationSeverityLevel = Optional.of(UsabilityDefectSeverityLevel.LOW);
        }
        else if (evaluationMetric > 0.3) {
            recommendationSeverityLevel = Optional.of(UsabilityDefectSeverityLevel.INFO);
        }
        return recommendationSeverityLevel;
    }

}
