//   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.plugin.usability2.commands;

import java.util.Collection;
import java.util.List;

import com.google.common.base.Optional;

import de.ugoe.cs.autoquest.CommandHelpers;
import de.ugoe.cs.autoquest.SequenceInstanceOf;
import de.ugoe.cs.autoquest.eventcore.Event;
import de.ugoe.cs.autoquest.usability.UsabilityEvaluator;
import de.ugoe.cs.autoquest.usability.rules.PatternRuleset;
import de.ugoe.cs.autoquest.usability.rules.UsabilityMetricsRuleset;
import de.ugoe.cs.autoquest.usability.rules.UsabilityResult;
import de.ugoe.cs.autoquest.plugin.usability2.rules.CombinedRuleset;
import de.ugoe.cs.autoquest.plugin.usability2.rules.metrics.RedundantScrollingMetric;
import de.ugoe.cs.autoquest.plugin.usability2.rules.metrics.SameTargetEditingMetric;
import de.ugoe.cs.autoquest.plugin.usability2.rules.patterns.PatternProblem;
import de.ugoe.cs.autoquest.plugin.usability2.rules.patterns.SessionPatternProblem;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
import de.ugoe.cs.util.console.Command;
import de.ugoe.cs.util.console.GlobalDataContainer;

/**
 * <p>
 * Command to perform a automatic usability evaluation for a given task model.
 * </p>
 * 
 * @author Alexander Deicke
 */
public class CMDperformUsabilityEvaluation implements Command {

    /**
     * <p>
     * index for name of task model under which it could be retrieved from
     * {@link GlobalDataContainer}
     * </p>
     */
    private final int taskModelParamaterIndex = 0;

    /**
     * <p>
     * index for name under which evaluation result should be stored in {@link GlobalDataContainer}
     * </p>
     */
    private final int evaluationResultParameterIndex = 1;

    /**
     * <p>
     * default name for evaluation result, which is used to store it in {@link GlobalDataContainer}
     * </p>
     */
    private final String defaultEvaluationResultParameterName = "usabilityEvaluationResult";

    /*
     * (non-Javadoc)
     * 
     * @see de.ugoe.cs.util.console.Command#run(java.util.List)
     */
    @Override
    public void run(List<Object> parameters) {
        String nameOfTaskModel = getTaskModelParameter(parameters);
        Optional<ITaskModel> taskModel = getTaskModelFromDataContainer(nameOfTaskModel);
        
        Optional<Collection<List<Event>>> sequences = getSequencesFromDataContainer("sequences");
        
        if (taskModel.isPresent()) {
            // UsabilityRuleset ruleset = new PatternRuleset(taskModel.get());
            CombinedRuleset ruleset =
                new CombinedRuleset(new PatternRuleset(taskModel.get()),
                                    new UsabilityMetricsRuleset(taskModel.get()));
            ruleset.add(new RedundantScrollingMetric(taskModel.get()));
            ruleset.add(new SameTargetEditingMetric(taskModel.get()));
            ruleset.add(new PatternProblem(taskModel.get()));
            ruleset.add(new SessionPatternProblem(taskModel.get(), sequences.get()));
            UsabilityResult result = UsabilityEvaluator.evaluate(taskModel.get()).using(ruleset);
            String evaluationResultParameterName = getEvaluationResultParameter(parameters);
            storeUsabilityResultInDataContainer(evaluationResultParameterName, result);
        }
    }

    /**
     * <p>
     * Gets name of task model from list of parameters.
     * </p>
     * 
     * @param parameters
     *            parameters for the command
     * @return name of task model
     */
    private String getTaskModelParameter(List<Object> parameters) {
        try {
            return (String) parameters.get(taskModelParamaterIndex);
        }
        catch (Exception e) {
            throw new IllegalArgumentException("must provide a task model name");
        }
    }

    /**
     * <p>
     * Gets name under which evaluation result should be stored in {@link GlobalDataContainer} from
     * list of parameters. If not present, the default value {@code usabilityEvaluationResult} is
     * used!
     * </p>
     * 
     * @param parameters
     *            parameters for the command
     * @return name under which evaluation result should be stored
     */
    private String getEvaluationResultParameter(List<Object> parameters) {
        if (parameters.size() == 2) {
            return (String) parameters.get(evaluationResultParameterIndex);
        }
        return defaultEvaluationResultParameterName;
    }

    /**
     * <p>
     * Retrieves task model from {@link GlobalDataContainer}.
     * </p>
     * 
     * @param nameOfTaskModel
     *            name of task model, under which it is stored in {@link GlobalDataContainer}
     * @return if present, task model
     */
    private Optional<ITaskModel> getTaskModelFromDataContainer(String nameOfTaskModel) {
        Object dataObject = GlobalDataContainer.getInstance().getData(nameOfTaskModel);
        if (dataObject != null) {
            if (dataObject instanceof ITaskModel) {
                ITaskModel taskModel = (ITaskModel) dataObject;
                return Optional.of(taskModel);
            }
            else {
                CommandHelpers.objectNotType(nameOfTaskModel, "ITaskModel");
                return Optional.absent();
            }
        }
        CommandHelpers.objectNotFoundMessage(nameOfTaskModel);
        return Optional.absent();
    }

    /**
     * <p>
     * Retrieves task model from {@link GlobalDataContainer}.
     * </p>
     * 
     * @param nameOfTaskModel
     *            name of task model, under which it is stored in {@link GlobalDataContainer}
     * @return if present, task model
     */
    private Optional<Collection<List<Event>>> getSequencesFromDataContainer(String nameOfTaskModel) {
        Object dataObject = GlobalDataContainer.getInstance().getData(nameOfTaskModel);
        if (dataObject != null) {
            if (SequenceInstanceOf.isCollectionOfSequences(dataObject)) {
                @SuppressWarnings("unchecked")
                Collection<List<Event>> sequences = (Collection<List<Event>>) dataObject;
                return Optional.of(sequences);
            }
            else {
                CommandHelpers.objectNotType(nameOfTaskModel, "Sequences");
                return Optional.absent();
            }
        }
        CommandHelpers.objectNotFoundMessage(nameOfTaskModel);
        return Optional.absent();
    }

    
    /**
     * <p>
     * Stores usability evaluation in {@link GlobalDataContainer}.
     * </p>
     * 
     * @param evaluationResultParameterName
     *            name under which usability result should be stored in {@link GlobalDataContainer}
     * 
     */
    private void storeUsabilityResultInDataContainer(String evaluationResultParameterName,
                                                     UsabilityResult result)
    {
        if (GlobalDataContainer.getInstance().addData(evaluationResultParameterName, result)) {
            CommandHelpers.dataOverwritten(evaluationResultParameterName);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see de.ugoe.cs.util.console.Command#help()
     */
    @Override
    public String help() {
        return "performUsabilityEvaluation <taskModel> {evaluationResult}";
    }

}
