//   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.tasktrees.treeifc;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * A task path is a path through a task tree. Conceptually, it is a list of task objects. But the
 * plain information about the tasks is not enough for a task path. The reason is, that multiple
 * paths through a task tree may be identical because the tasks in the paths are identical. This
 * happens, e.g., if a sequence has three children, where the first and the last are the same. Then
 * based on the plain task information, it would not be possible to define separate task paths for
 * the first and the last child of the sequence. Hence, we also add for each path element the index
 * of the element in the list of children of the parent. This index is also considered, when
 * comparing task paths. 
 * </p>
 * 
 * @author Patrick Harms
 */
public class TaskPath {

    /** */
    private List<Entry> taskList;
    
    /**
     *
     *
     */
    public TaskPath() {
        super();
        taskList = new ArrayList<Entry>();
    }

    /**
     *
     */
    public TaskPath(TaskPath path) {
        this();
        taskList.addAll(path.taskList);
    }

    /**
     * 
     */
    public TaskPath subPath(int fromIndex, int toIndex) {
        TaskPath result = new TaskPath();
        result.taskList.addAll(taskList.subList(fromIndex, toIndex));
        return result;
    }

    /**
     * 
     */
    public ITask removeLast() {
        Entry last = taskList.remove(taskList.size() - 1);
        if (last != null) {
            return last.getTask();
        }
        else {
            return null;
        }
    }

    /**
     * 
     */
    public ITask getLast() {
        Entry last = taskList.get(taskList.size() - 1);
        if (last != null) {
            return last.getTask();
        }
        else {
            return null;
        }
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return taskList.toString();
    }

    /**
     *
     */
    public int size() {
        return taskList.size();
    }

    /**
     *
     */
    public boolean isEmpty() {
        return taskList.isEmpty();
    }
    
    /**
     * 
     */
    public void add(ITask task, int index) {
        taskList.add(new Entry(task, index));
    }

    /**
     *
     */
    public ITask getTask(int index) {
        Entry last = taskList.get(index);
        if (last != null) {
            return last.getTask();
        }
        else {
            return null;
        }
    }

    /**
     *
     */
    public Entry get(int index) {
        return taskList.get(index);
    }

    
    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        ITask last = getLast();
        if (last != null) {
            return last.hashCode();
        }
        else {
            return 0;
        }
    }

    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        else if (obj instanceof TaskPath) {
            TaskPath other = (TaskPath) obj;
            if (this.size() == other.size()) {
                for (int i = 0; i < this.size(); i++) {
                    if (!this.get(i).equals(other.get(i))) {
                        return false;
                    }
                }
                return true;
            }
        }
        
        return false;
    }


    /**
     * 
     */
    public static class Entry {
        
        /** */
        private ITask task;
        
        /** */
        private int index;
        
        /**
         * 
         */
        private Entry(ITask task, int index) {
            this.task = task;
            this.index = index;
        }

        /* (non-Javadoc)
         * @see java.lang.Object#toString()
         */
        @Override
        public String toString() {
            return "(" + task + "," + index + ")";
        }

        /**
         * @return the task
         */
        public ITask getTask() {
            return task;
        }

        /**
         * @return the index
         */
        public int getIndex() {
            return index;
        }

        /* (non-Javadoc)
         * @see java.lang.Object#hashCode()
         */
        @Override
        public int hashCode() {
            return task.hashCode();
        }

        /* (non-Javadoc)
         * @see java.lang.Object#equals(java.lang.Object)
         */
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            else if (obj instanceof TaskPath.Entry) {
                return (this.getIndex() == ((TaskPath.Entry) obj).getIndex()) &&
                    (this.getTask().equals(((TaskPath.Entry) obj).getTask()));
            }
            
            return false;
        }
        
        
    }
    
}
