package de.ugoe.cs.quest.tasktrees.manager;

import java.util.logging.Logger;

import de.ugoe.cs.quest.eventcore.Event;
import de.ugoe.cs.quest.eventcore.IEventTarget;
import de.ugoe.cs.quest.eventcore.gui.KeyInteraction;
import de.ugoe.cs.quest.eventcore.gui.KeyboardFocusChange;
import de.ugoe.cs.quest.tasktrees.treeifc.IEventTask;
import de.ugoe.cs.quest.tasktrees.treeifc.ISequence;
import de.ugoe.cs.quest.tasktrees.treeifc.ITaskTree;
import de.ugoe.cs.quest.tasktrees.treeifc.ITaskTreeBuilder;
import de.ugoe.cs.quest.tasktrees.treeifc.ITaskTreeNode;
import de.ugoe.cs.quest.tasktrees.treeifc.ITaskTreeNodeFactory;

/**
 * TODO comment
 * 
 * @version $Revision: $ $Date: $
 * @author 2011, last modified by $Author: $
 */
public class TaskTreeManager {
    
    /** */
    private static final int MAX_EVENTS_TILL_RULE_APPLICATION = 100;

    /** */
    private static Logger LOG = Logger.getLogger(TaskTreeManager.class.getName());

    /** */
    private ITaskTreeBuilder taskTreeBuilder = ComponentManager.getDefaultTaskTreeBuilder();

    /** */
    private ITaskTreeNodeFactory taskTreeNodeFactory =
        ComponentManager.getDefaultTaskTreeNodeFactory();

    /** */
    private int eventsTillRuleApplication = MAX_EVENTS_TILL_RULE_APPLICATION;

    /** */
    private ISequence rootSequence;

    /** */
    private IEventTarget currentKeyboardFocusGUIElement;

    /**
     * TODO: comment
     * 
     */
    public TaskTreeManager() {
        rootSequence = taskTreeNodeFactory.createNewSequence();
    }

    /**
     *
     */
    public void handleNewEvent(Event event) {
        if (event.getType() instanceof KeyInteraction) {
            if (currentKeyboardFocusGUIElement == null) {
                currentKeyboardFocusGUIElement = event.getTarget();
            }

            addEventTask
              (taskTreeNodeFactory.createNewEventTask
                 (event.getType(), currentKeyboardFocusGUIElement));
        }
        else {
            addEventTask
              (taskTreeNodeFactory.createNewEventTask(event.getType(), event.getTarget()));
        }
    }

    /**
     *
     */
    public synchronized ITaskTree getTaskTree() {
        LOG.info("applying rules temporal relationship generation rules");

        ISequence currentRootSequence = rootSequence.clone();
        ComponentManager.getTemporalRelationshipRuleManager().applyRules
          (currentRootSequence, taskTreeBuilder, taskTreeNodeFactory, true);

        return taskTreeNodeFactory.createTaskTree(currentRootSequence);
    }

    /**
     * @param task
     */
    private synchronized void addEventTask(IEventTask task) {
        handleEventTask(task);
    }

    /**
     * adds the task to the current or the new sequence. The decision depends on the type of task.
     * If the task finishes the current sequence, the sequence is marked as finished If the task
     * does not start a new sequence, it is added to the current sequence, before it is marked s
     * finished. Otherwise it is added to a new sequence.
     */
    private void handleEventTask(IEventTask eventTask) {
        if (eventTask.getEventType() instanceof KeyboardFocusChange) {
            currentKeyboardFocusGUIElement = eventTask.getEventTarget();
        }
        else {
            LOG.info("handling event task \"" + eventTask + "\"");
            addTaskToSequence(eventTask, currentKeyboardFocusGUIElement);
        }
    }

    /**
     *
     */
    private void addTaskToSequence(ITaskTreeNode task, IEventTarget currentKeyboardFocusGUIElement)
    {
        taskTreeBuilder.addChild(rootSequence, task);

        if (--eventsTillRuleApplication == 0) {
            eventsTillRuleApplication = MAX_EVENTS_TILL_RULE_APPLICATION;

            LOG.info("applying rules temporal relationship generation rules");
            ComponentManager.getTemporalRelationshipRuleManager().applyRules(rootSequence,
                                                                             taskTreeBuilder,
                                                                             taskTreeNodeFactory,
                                                                             false);
        }
    }

}
