//   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.rules.operator.wrapper;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance;
import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptional;
import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptionalInstance;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequenceInstance;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;

/**
 * <p>
 * Utility Class that does the instance based setup for a Node of a TaskWrapper Tree.
 * </p>
 * 
 * @author Konni Hartmann
 */
public class InstanceUtility {

    /**
     * <p>
     * Generate lists of filtered instances. For a set of root task instances generate a list containing
     * all instances of the current task that are children of the said root instances.
     * The root instances are either taken from the parent task or if the current task is the root
     * task are all instances of the task. 
     * </p>
     *
     * @param task
     */
    public static void setupInstances(ITaskWrapper task) {
        ITaskWrapper parent = task.getParent();
        if(parent == null) {
            // If task is root of this tree use all instances and exit
            Collection<ITaskInstance> instances = task.getInstances();
            for (ITaskInstance instance : instances) {
                task.addFilteredInstance(instance, instance);
            }
            return;            
        }
        
        ITask reference = task.getParent().getReference();
        while (reference instanceof ITaskEntry) {
            reference = ((ITaskEntry) reference).getReference();
        }
        
        if (reference instanceof IEventTask) {
            event(task);
        }
        else if (reference instanceof IIteration) {
            iteration(task);
        }
        else if (reference instanceof IOptional) {
            optional(task);
        }
        else if (reference instanceof ISelection) {
            selection(task);
        }
        else if (reference instanceof ISequence) {
            sequence(task);
        }
    }

    public static void setupSequence(TaskWrapper task, int id) {
        Map<ITaskInstance, List<ITaskInstance>> instances = task.getParent().getFilteredInstances();

        
        for (Entry<ITaskInstance, List<ITaskInstance>> entry : instances.entrySet()) {
            ITaskInstance filter = entry.getKey();
            @SuppressWarnings("unchecked")
            List<ISequenceInstance> instanceList = (List<ISequenceInstance>)(List<?>) entry.getValue();

            for (ISequenceInstance sequence : instanceList) {

                if (id >= sequence.size()) {
                    System.err.printf("\nNo #%d in sequence: %s\n", id, sequence);
                    continue;
                }

                ITaskInstance instance = sequence.get(id);                
                task.addFilteredInstance(filter, instance);
            }
        }        
    }

    private static void sequence(ITaskWrapper task) {
//        Map<ITaskInstance, List<ITaskInstance>> instances = task.getParent().getFilteredInstances();
//        
//        for (Entry<ITaskInstance, List<ITaskInstance>> entry : instances.entrySet()) {
//            ITaskInstance filter = entry.getKey();
//            List<ISequenceInstance> instanceList = (List<ISequenceInstance>)(List<?>) entry.getValue();
//            
//            for (ISequenceInstance sequence : instanceList) {
//                List<ITaskInstance> sequenceInstances = sequence.getChildren();
//
//                //TODO: Should be possible to index the current task!
//                for (ITaskInstance instance : sequenceInstances) {
//                    if (instance.getTask().equals(task.getReference()))
//                    {
//                        task.addFilteredInstance(filter, instance);
//                        break;
//                    }
//                }                    
//            }
//        }
        throw new RuntimeException("parent of task is a sequence without telling us the position this node occupies");        
    }

    private static void selection(ITaskWrapper task) {
        Map<ITaskInstance, List<ITaskInstance>> instances = task.getParent().getFilteredInstances();
        
        for (Entry<ITaskInstance, List<ITaskInstance>> entry : instances.entrySet()) {
            ITaskInstance filter = entry.getKey();
            @SuppressWarnings("unchecked")
            List<ISelectionInstance> instanceList = (List<ISelectionInstance>)(List<?>) entry.getValue();
            
            for (ISelectionInstance selection : instanceList) {
                ITaskInstance instance = selection.getChild();
                
                //TODO: Should be possible to name the selected task!
                if(instance != null && instance.getTask().equals(task.getReference()))
                    task.addFilteredInstance(filter, instance);
            }
        }
    }

    private static void iteration(ITaskWrapper task) {
        Map<ITaskInstance, List<ITaskInstance>> instances = task.getParent().getFilteredInstances();
        
        for (Entry<ITaskInstance, List<ITaskInstance>> entry : instances.entrySet()) {
            ITaskInstance filter = entry.getKey();
            @SuppressWarnings("unchecked")
            List<IIterationInstance> instanceList = (List<IIterationInstance>)(List<?>) entry.getValue();
            
            for (IIterationInstance iteration : instanceList) {
                List<ITaskInstance> iterationInstances = iteration.getChildren();
                
                for (ITaskInstance instance : iterationInstances) {
                    task.addFilteredInstance(filter, instance);                    
                }
            }
        }
    }

    private static void optional(ITaskWrapper task) {
        Map<ITaskInstance, List<ITaskInstance>> instances = task.getParent().getFilteredInstances();
        
        for (Entry<ITaskInstance, List<ITaskInstance>> entry : instances.entrySet()) {
            ITaskInstance filter = entry.getKey();
            @SuppressWarnings("unchecked")
            List<IOptionalInstance> instanceList = (List<IOptionalInstance>)(List<?>) entry.getValue();
            
            for (IOptionalInstance optional : instanceList) {
                ITaskInstance instance = optional.getChild();
                if(instance != null)
                    task.addFilteredInstance(filter, instance);
            }
        }
    }

    private static void event(ITaskWrapper task) {
        throw new RuntimeException("a parent of a task can never be an event (these are leafs!)");
    }

}
