
package de.ugoe.cs.autoquest.plugin.usability2.statistics;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

import org.apache.commons.collections15.map.HashedMap;

import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance;
import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptionalInstance;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequenceInstance;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;

public class StatisticNode {

    private static class StatisticData {
        StatisticData parent = null;
        ITaskInstance instance = null;

        int getCount(int index) {
            return 1;
        }
    }

    private static class StatisticDataVarying extends StatisticData {
        int[] counts;

        @Override
        int getCount(int index) {
            return counts[index];
        }
    }

    private Map<ITaskInstance, StatisticData> map;

    private final ITask root;

    public StatisticNode(ITask root) {
        this.root = root;
        map = new HashedMap<ITaskInstance, StatisticData>();
        analyse();
    }

    private void analyse() {
        Collection<ITaskInstance> instances = root.getInstances();
        analyseNode(instances, null);
    }

    private void analyseNode(Collection<ITaskInstance> nodes, StatisticData parent) {
        if (nodes == null)
            return;

        for (ITaskInstance node : nodes) {
            analyseNode(node, parent);
        }
    }

    public ITaskInstance findCommonParent(ITaskInstance i1, ITaskInstance i2) {
        if (i1 == i2)
            return i1;

        StatisticData d1 = map.get(i1);
        StatisticData d2 = map.get(i2);

        if (d1 == null || d2 == null)
            return null;

        LinkedList<StatisticData> list1 = new LinkedList<StatisticData>();
        while ((d1 = d1.parent) != null) {
            list1.push(d1);
        }

        LinkedList<StatisticData> list2 = new LinkedList<StatisticData>();
        while ((d2 = d2.parent) != null) {
            list2.push(d2);
        }

        ITaskInstance result = null;

        try {
            while ((d1 = list1.pop()) == (d2 = list2.pop())) {
                result = d1.instance;
            }
        }
        catch (NoSuchElementException e) {
            // ignore
        }

        return result;
    }

    public Collection<ITaskInstance> findAllInstances(ITask task) {
        List<ITaskInstance> matches = new ArrayList<ITaskInstance>();

        for (ITaskInstance instance : map.keySet()) {
            if (instance.getTask().equals(task))
                matches.add(instance);
        }

        return matches;
    }

    private void analyseNode(ITaskInstance node, StatisticData parent) {
        if (node == null)
            return;

        StatisticData data = new StatisticData();
        data.parent = parent;
        data.instance = node;
        map.put(node, data);

        if (node instanceof IOptionalInstance) {
            ITaskInstance child = ((IOptionalInstance) node).getChild();
            analyseNode(child, parent);
        }
        else if (node instanceof ISelectionInstance) {
            ITaskInstance child = ((ISelectionInstance) node).getChild();
            analyseNode(child, parent);
        }
        else if (node instanceof IIterationInstance) {
            List<ITaskInstance> children = ((IIterationInstance) node).getChildren();
            analyseNode(children, parent);
        }
        else if (node instanceof ISequenceInstance) {
            List<ITaskInstance> children = ((ISequenceInstance) node).getChildren();
            analyseNode(children, parent);
        }

    }
}
