//   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;

import static org.junit.Assert.*;

import java.util.List;

import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptional;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstanceList;
import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;

/**
 * <p>
 * TODO comment
 * </p>
 * 
 * @author Patrick Harms
 */
public class TaskTreeValidator {

    /**
     * 
     */
    public void validate(List<IUserSession> userSessions) {
        for (IUserSession userSession : userSessions) {
            validate(userSession);
        }
    }

    /**
     * 
     */
    public void validate(ITaskInstanceList taskInstances) {
        for (ITaskInstance taskInstance : taskInstances) {
            validate(taskInstance);
        }
    }

    /**
     * 
     */
    public void validate(ITaskInstance taskInstance) {
        assertNotNull("task model of task instance must not be null", taskInstance.getTask());
        
        if (taskInstance.getTask() instanceof ISequence) {
            ISequence task = (ISequence) taskInstance.getTask();
            
            assertEquals("number of children of sequence instance must match sequence model",
                         taskInstance.size(), task.getChildren().size());
            
            for (int i = 0; i < taskInstance.size(); i++) {
                assertNotNull("sequence instance child " + i + " was null", taskInstance.get(i));
                ITask childTask = taskInstance.get(i).getTask();
                assertSame("task of sequence child " + i + " does not match sequence model",
                           childTask, task.getChildren().get(i));
            }
        }
        else if (taskInstance.getTask() instanceof ISelection) {
            ISelection task = (ISelection) taskInstance.getTask();
            
            assertEquals
                ("number of children of selection instance must be 1", 1, taskInstance.size());
            assertTrue
                ("number of children of selection must be larger 0", task.getChildren().size() > 0);
            
            boolean found = false;
            for (ITask childTask : task.getChildren()) {
                assertNotNull("child of selection model must not be null", childTask);
                assertFalse("child of selection model must not be a selection",
                            childTask instanceof ISelection);
                assertFalse("child of selection model must not be an optional",
                            childTask instanceof IOptional);
                if (childTask.equals(taskInstance.get(0).getTask())) {
                    found = true;
                    break;
                }
            }
            
            assertTrue("no child of the selection model matches the model of child of the " +
                       "selection instance", found);
        }
        else if (taskInstance.getTask() instanceof IIteration) {
            ITask childTask = ((IIteration) taskInstance.getTask()).getMarkedTask();
            assertNotNull("child task of iteration model must not be null", childTask);
            assertFalse("child of iteration model must not be an iteration",
                        childTask instanceof IIteration);
            assertFalse("child of iteration model must not be an optional",
                        childTask instanceof IOptional);
            
            for (int i = 0; i < taskInstance.size(); i++) {
                assertNotNull("iteration instance child " + i + " was null", taskInstance.get(i));
                assertSame("task of iteration child " + i + " does not match iteration model",
                           childTask, taskInstance.get(i).getTask());
            }
        }
        else if (taskInstance.getTask() instanceof IOptional) {
            ITask childTask = ((IOptional) taskInstance.getTask()).getMarkedTask();
            assertNotNull("child task of optional model must not be null", childTask);
            assertFalse("child of optional model must not be an optional",
                        childTask instanceof IOptional);
            
            assertEquals
                ("number of children of optional instance must be 1", 1, taskInstance.size());
            
            assertEquals("task of optional child does not match optional model",
                         childTask, taskInstance.get(0).getTask());
        }
        else if (taskInstance.getTask() instanceof IEventTask) {
            IEventTask task = (IEventTask) taskInstance.getTask();
            assertNotNull("event task model must not be null", task);
            assertNotNull("event type of event task model must not be null", task.getEventType());
            assertNotNull
                ("event target of event task model must not be null", task.getEventTarget());

            assertEquals("event task instance must not have children", 0, taskInstance.size());
        }
        else {
            fail("unknown task model: " + taskInstance.getTask());
        }
        
        for (ITaskInstance child : taskInstance) {
            validate(child);
        }
    }
}
