Ext.define('LessonRootClass', {
    extend: 'Ext.util.Observable',
    constructor: function(cfgXML, config){
        Ext.apply(this, config);
        this.addEvents({
            "lessonRootLoaded": true,
            "lessonRootCompleted": true
        });
        this.callParent([]);
        this.id = cfgXML.getAttribute('id');
        this.Type = "LESSONROOT";
        this.Name = cfgXML.getAttribute('name');
        this.ShowInReference = true;
        this.NodePath = '0';
        this.LogicalOrder = new OrderClass(this.NodePath, 'LessonRoot');
        this.ChildNode = null;
        this.BackgroundList = new ListClass(cfgXML.getElementsByTagName('list')[0], this.LogicalOrder, {});
        this.ForegroundList = new ListClass(cfgXML.getElementsByTagName('list')[1], this.LogicalOrder, {});
    },
    onStartShowLessonRoot: function(){
        Author.CurrentStateManager.CurrentActionIndex = -1;
        Author.CurrentStateManager.CurrentElementPosition = -1;
        Author.CurrentStateManager.CurrentAction = null;
        Author.CurrentStateManager.CurrentList = null;
        Author.CurrentStateManager.CurrentResponse = null;
        Author.CurrentStateManager.CurrentElement = null;
        Author.CurrentStateManager.CurrentLessonNode = this;
    },
    onNodeCompleted: function(startNodeID, startElementID){
        if (this.hasListener('lessonRootCompleted')) {
            this.fireEvent('lessonRootCompleted', this, startNodeID, startElementID);
        }
    },
    show: function(startNodeID, startElementID){
        this.BackgroundList.Actions.each(function(action, index, length){
            switch (action.ObjectType) {
                case 'BACKGROUND':
                    Author.DisplayManager.BackgroundObject = action;
                    action.processAction(Ext.getBody());
                    break;
                default:
                    action.processAction(Author.DisplayManager.BackgroundObject.getContent());
                    break;
            }
            Author.CurrentStateManager.addAction(action);
        }, this);
        this.ForegroundList.Actions.each(function(action, index, length){
            action.processAction(Author.DisplayManager.BackgroundObject.getContent());
            Author.CurrentStateManager.addAction(action);
        }, this);
        this.onNodeCompleted(startNodeID, startElementID);
    },
    toString: function(){
        return Ext.String.format("LessonRoot  ID: {0}\nType: {1}\n{2}", this.id, this.Type, this.LogicalOrder);
    }
});
LessonNodeHelper = {
    loadLessonNode: function(cfgXML, parentNode, config){
        var nodeType = cfgXML.getAttribute('type');
        switch (nodeType) {
            case 'SEQUENCE':
                return new SequenceNodeClass(cfgXML, parentNode, config);
                break;
            case 'MENU':
                return new MenuNodeClass(cfgXML, parentNode, config);
                break;
            case 'RANDOM':
                return new RandomNodeClass(cfgXML, parentNode, config);
                break;
            default:
                alert("No lessonNode of type: " + nodeType + " is defined.");
                return null;
        }
    }
};
/**
 *
 * @param {Object} cfgXML
 * @param {Object} parentNode
 * @param {Object} config
 */
Ext.define('LessonNodeClass', {
    extend: 'Ext.util.Observable',
    constructor: function(cfgXML, parentNode, config){
        Ext.apply(this, config);
        this.addEvents({
            "lessonNodeCompleted": true,
            "lessonNodeTravelled": true
        });
        this.callParent([]);
        this.id = cfgXML.getAttribute('id');
        this.Type = cfgXML.getAttribute('type');
        this.Name = cfgXML.getAttribute('name');
        this.ShowInReference = cfgXML.getAttribute('showInReference').toLowerCase() == 'true';
        this.ShowIntroductionListOnce = cfgXML.getAttribute('showIntroductionOnce').toLowerCase() == 'true';
        this.ShowEndListOnExit = cfgXML.getAttribute('showEndOnExitLesson').toLowerCase() == 'true';
        this.ShowEndListOnBack = cfgXML.getAttribute('showEndOnGoBack').toLowerCase() == 'true';
        this.ShowEndListOnCompleted = cfgXML.getAttribute('showEndOnCompletion').toLowerCase() == 'true';
        this.ShowingEndList = false;
        this.OptionStartTime = 0;
        var endListTriggerCount = 0;
        endListTriggerCount += (this.ShowEndListOnExit) ? 1 : 0;
        endListTriggerCount += (this.ShowEndListOnBack) ? 1 : 0;
        endListTriggerCount += (this.ShowEndListOnCompleted) ? 1 : 0;
        // this.ShowIntroductionListOnce = true;
        if (endListTriggerCount > 1) {
            alert("End list can only show on one trigger");
        }
        this.ParentNode = parentNode;
        this.NodePath = parentNode.NodePath + "|" + this.id;
        this.LogicalOrder = new OrderClass(this.NodePath, 'LessonNode-' + this.Type);
        this.ChildrenNodes = new Ext.util.MixedCollection();
        var listNode = cfgXML.getElementsByTagName('list');
        this.IntroductionList = new ListClass(listNode[0], this.LogicalOrder, {});
        this.EndList = new ListClass(listNode[listNode.length - 1], this.LogicalOrder, {});
        this.IsIntroductionListShown = false;
        this.IsCompleted = false;
        if (parentNode.Type == 'LESSONROOT') {
            parentNode.ChildNode = this;
        }
        else {
            parentNode.addChildNode(this);
        }
    },
    isCompleted: function(){
        return this.IsCompleted;
    },
    getOptionScore: function(){
        return 0;
    },
    getOptionTotal: function(){
        return 0;
    },
    onStartShowNode: function(){
        this.OptionStartTime = new Date().getTime();
        Author.CurrentStateManager.CurrentActionIndex = -1;
        Author.CurrentStateManager.CurrentElementPosition = -1;
        Author.CurrentStateManager.CurrentAction = null;
        Author.CurrentStateManager.CurrentList = null;
        Author.CurrentStateManager.CurrentResponse = null;
        Author.CurrentStateManager.CurrentElement = null;
        Author.CurrentStateManager.CurrentLessonNode = this;
        Author.DisplayManager.clearScreen(this);
        this.ShowingEndList = false;
    },
    onRepeat: function(){
        Author.DisplayManager.showLessonNode(this);
    },
    onNodeCompleted: function(){
        if (!this.isCompleted()) {
            //  Author.log("lessonNodeClass.onNodeCompleted:\n" + this);
            this.doOnNodeComplete();
        }
        //check if able to go to upper level
        if (this.ParentNode.Type == 'LESSONROOT' && this.Type != 'MENU') {
            this.onExitLesson();
            return;
        }
        if (this.Type != 'MENU') {
            //alert("Going back to " + this.ParentNode);
            this.onGoBackToParentNode();
        }
    },
    doGoBackToMainMenu: function(){
        // alert('doGoBackToMainMenu');
        this.ParentNode.onGoBackToMainMenu(this);
    },
    onGoBackToMainMenu: function(childNode){
        // alert("onGoBackToMainMenu");
        if (childNode) {
            //alert(childNode);
            this.onBackFromChildNode(childNode);
        }
        if (this.ParentNode.Type == 'MENU') {
            if (this.ShowEndListOnBack) {
                this.showEndList(this.onEndListCompleted_OnGoBackToMainMenu);
            }
            else {
                this.doGoBackToMainMenu();
            }
        }
        else {
            Author.DisplayManager.showLessonNode(this);
        }
    },
    doGoBackToParentNode: function(){
        this.ParentNode.onGoBackToParentNode(this);
    },
    onGoBackToParentNode: function(childNode){
        if (childNode) {
            this.onBackFromChildNode(childNode);
            Author.DisplayManager.showLessonNode(this);
            return;
        }
        if (this.ShowEndListOnBack) {
            this.showEndList(this.onEndListCompleted_OnGoBack);
        }
        else {
            this.doGoBackToParentNode();
        }
    },
    onExitLesson: function(lessonTimeout){
        if (Author.CurrentStateManager.CurrentLessonNode.id != this.id) {
            Author.CurrentStateManager.CurrentLessonNode = this;
            Author.CurrentStateManager.CurrentElement = null;
            Author.CurrentStateManager.CurrentResponse = null;
        }
        if(lessonTimeout && this.ShowingEndList){
            return;
        }
        if (this.ShowEndListOnExit ) {
            this.ShowingEndList = true;
            this.showEndList(this.onEndListCompleted_OnExitLesson);
        }
        else {
            Author.LessonManager.onExitLesson();
        }
    },
    doOnNodeComplete: function(){
        if (this.ShowEndListOnCompleted) {
            this.showEndList(this.onEndListCompleted_OnNodeCompleted);
        }
        else {
            this.IsCompleted = true;
            if (this.hasListener('lessonNodeCompleted')) {
                this.fireEvent('lessonNodeCompleted');
            }
        }
    },
    //Start Travel related functions
    onStartTravelNode: function(){
        Author.CurrentStateManager.CurrentActionIndex = -1;
        Author.CurrentStateManager.CurrentElementPosition = -1;
        Author.CurrentStateManager.CurrentAction = null;
        Author.CurrentStateManager.CurrentList = null;
        Author.CurrentStateManager.CurrentResponse = null;
        Author.CurrentStateManager.CurrentElement = null;
        Author.CurrentStateManager.CurrentLessonNode = this;
        Author.DisplayManager.clearScreen(this);
    },
    travel: function(){
        if (!(this.IsIntroductionListShown && this.ShowIntroductionListOnce)) {
            this.IntroductionList.addListener('listTravelled', this.onIntroductionListTravelled, this);
            this.IntroductionList.travelList();
        }
        else {
            this.travelNode();
        }
    },
    travelNode: function(){
        this.onNodeTravelled();
    },
    onIntroductionListTravelled: function(){
        this.IsIntroductionListShown = true;
        this.travelNode();
    },
    onNodeTravelled: function(){
        if (this.hasListener('lessonNodeTravelled')) {
            this.fireEvent('lessonNodeTravelled', this);
        }
    },
    //End Travel Related functions.
    show: function(){
           // Author.log(this.IsIntroductionListShown);
        if (!(this.IsIntroductionListShown && this.ShowIntroductionListOnce)) {
            //Author.log("show introduction");
            this.showIntroductionList();
        }
        else {
            this.showNode();
        }
    },
    showNode: function(){
    },
    showIntroductionList: function(){
        this.IntroductionList.addListener('listCompleted', this.onIntroductionListCompleted, this);
        Author.DisplayManager.showList(this.IntroductionList);
    },
    onIntroductionListCompleted: function(){
        this.IsIntroductionListShown = true;
        this.showNode();
    },
    showEndList: function(handler){
        Author.DisplayManager.clearScreen(this.EndList);
        this.EndList.addListener('listCompleted', handler, this);
        Author.DisplayManager.showList(this.EndList);
    },
    onEndListCompleted_OnNodeCompleted: function(){
        this.IsCompleted = true;
        if (this.hasListener('lessonNodeCompleted')) {
            this.fireEvent('lessonNodeCompleted');
        }
        this.onNodeCompleted();
    },
    onEndListCompleted_OnGoBackToMainMenu: function(){
        this.doGoBackToMainMenu();
    },
    onEndListCompleted_OnGoBack: function(){
        this.doGoBackToParentNode();
    },
    onEndListCompleted_OnExitLesson: function(){
        Author.LessonManager.onExitLesson();
    },
    getChildrenNodeCount: function(){
        return this.ChildrenNodes.getCount();
    },
    addChildNode: function(cNode){
        if (this.ChildrenNodes.containsKey(cNode.id)) {
            alert("node " + this.id + " already has a child node of id: " + cNode.id);
        }
        else {
            this.ChildrenNodes.add(cNode.id, cNode);
        }
    },
    toString: function(){
        return Ext.String.format("LessonNode ID: {0}\nType: {1}\nName: {3}\nNodePath: {2}", this.id, this.Type, this.NodePath, this.Name);
    }
});
Ext.define('MenuNodeClass', {
    extend: 'LessonNodeClass',
    constructor: function(cfgXML, parentNode, config){
        this.callParent([cfgXML, parentNode, config]);
        var listNode = cfgXML.getElementsByTagName('list');
        this.MenuInformationList = new ListClass(listNode[1], this.LogicalOrder, {});
        this.MenuInteractionList = new ListClass(listNode[2], this.LogicalOrder, {});
        this.Responses = new Ext.util.MixedCollection();
        this.InteractionListFinishedTimestamp = 0;
        this.loadResponses(cfgXML);
    },
    getOptionScore: function(visitedElementsOnly){
        var optionScore = 0;
        this.ChildrenNodes.each(function(node, index, length){
            optionScore += node.getOptionScore(visitedElementsOnly);
        }, this);
        return optionScore;
    },
    getOptionTotal: function(visitedElementsOnly){
        var optionTotal = 0;
        this.ChildrenNodes.each(function(node, index, length){
            optionTotal += node.getOptionTotal(visitedElementsOnly);
        }, this);
        return optionTotal;
    },
    isCompleted: function(){
        return this.checkCompletion();
    },
    onBackFromChildNode: function(childNode){
        // alert("onBackFromChildNode:\nChildNode:\n" + childNode);
        if (this.isCompleted()) {
            this.onNodeCompleted();
        }
    },
    checkCompletion: function(){
        //check each child's completion state
        //if all completed ( only marks) fire onNodeCompleted Event;
        return false;
    },
    //MenuNode Start Travel Related functions
    travelNode: function(){
        this.MenuInformationList.addListener('listTravelled', this.onMenuInformationListTravelled, this);
        this.MenuInformationList.travelList();
    },
    onMenuInformationListTravelled: function(){
        this.MenuInteractionList.addListener('listTravelled', this.onMenuInteractionListTravelled, this);
        this.MenuInteractionList.travelList();
    },
    onMenuInteractionListTravelled: function(){
        this.onNodeTravelled();
    },
    //MenuNode End Travel Related functions
    showNode: function(){
        Author.DisplayManager.clearScreen(this.MenuInformationList);
        Author.CurrentStateManager.resetList(this.MenuInteractionList);
        this.showMenuInformationList();
    },
    showMenuInformationList: function(){
        this.MenuInformationList.addListener('listCompleted', this.onMenuInformationListCompleted, this);
        Author.DisplayManager.showList(this.MenuInformationList);
    },
    onMenuInformationListCompleted: function(){
        this.showMenuInteractionList();
    },
    showMenuInteractionList: function(){
        this.MenuInteractionList.addListener('listCompleted', this.onMenuInteractionListCompleted, this);
        Author.DisplayManager.showList(this.MenuInteractionList);
    },
    onMenuInteractionListCompleted: function(){
        if (this.MenuInteractionList.getActionsCount() == 0) {
            Author.log(Ext.String.format("[MENU] {0} has no action in Menuinteraction.", this.Name));
        }
        this.InteractionListFinishedTimestamp = new Date().getTime();
        //  Author.log("MenuNodeClass.onMenuInteractionListCompleted:\n" + this.MenuInteractionList);
        //  Author.log(Author.CurrentStateManager.getCurrentActions());
    },
    checkAndShowResponse: function(){
        //  alert("Element:checkAndShowResponse");
        if (this.getResponsesCount() != 0) {
            var firstMatchedResponse = null;
            this.Responses.each(function(response, index, length){
                if (response.isConditionMatched()) {
                    firstMatchedResponse = response;
                    return false;
                }
            }, this);
            if (firstMatchedResponse) {
                firstMatchedResponse.addListener('responseCompleted', this.onResponseCompleted, this);
                firstMatchedResponse.RespondTime = (new Date().getTime() - this.InteractionListFinishedTimestamp) / 1000.0;
                Author.DisplayManager.showResponse(firstMatchedResponse);
            }
        }
    },
    onResponseCompleted: function(response){
        if (response.FeedbackOption == FeedbackOptions.Remove) {
            response.removeResponse();
        }
        if (response.RepeatType == RepeatTypes.DoNotRepeat) {
            this.onElementCompleted();
            return;
        }
        if (!response.DoNotCountAttempt) {
            var curAttempt = Author.VariableManager.getSystemVariableValue(AuthorSystemVariables.ATTEMPT, 0);
            Author.VariableManager.setSystemVariableValue(AuthorSystemVariables.ATTEMPT, (curAttempt + 1));
        }
        response.RepeatType = RepeatTypes.RepeatFromInformation;
        if (response.ResetInteraction) {
            Author.CurrentStateManager.resetList(this.MenuInteractionList);
        }
        switch (response.RepeatType) {
            case RepeatTypes.RepeatFromInformation:
                // alert("repeat From Information");
                this.MenuInformationList.removeListActions();
                this.MenuInteractionList.removeListActions();
                this.showMenuInformationList();
                break;
            case RepeatTypes.RepeatFromInteraction:
                //  alert("repeat From interaction");
             //   this.MenuInteractionList.removeListActions();
              //  this.showMenuInteractionList();
               // Author.log("repeat From interaction");
                //this.InteractionList.removeListActions();
                //this.showInteractionList();
                Author.CurrentStateManager.CurrentActionPosition = this.MenuInteractionList.Actions.length;
                Author.CurrentStateManager.CurrentAction = null;
                Author.CurrentStateManager.CurrentList = this.MenuInteractionList;
                this.onInteractionListCompleted();
                break;
        }
    },
    getResponsesCount: function(){
        return this.Responses.getCount();
    },
    loadResponses: function(cfgXML){
        var responses = cfgXML.getElementsByTagName('response');
        for (var i = 0; i < responses.length; i++) {
            var r = new ResponseClass15(responses[i], this.LogicalOrder, {});
            this.Responses.add(r.id, r);
        }
    },
    toString: function(){
        var baseStr = this.callParent([]);
        return Ext.String.format("{0}\nChildrenCount: {1}", baseStr, this.getChildrenNodeCount());
    }
});
/**
 *
 * @param {Object} cfgXML
 * @param {Object} parentNode
 * @param {Object} config
 */
Ext.define('SequenceNodeClass', {
    extend: 'LessonNodeClass',
    constructor: function(cfgXML, parentNode, config){
        this.callParent([cfgXML, parentNode, config]);
        this.addEvents({
            "elementsCompleted": true
        });
        this.Elements = new Ext.util.MixedCollection();
        var elementNodes = cfgXML.getElementsByTagName('element');
        for (var i = 0; i < elementNodes.length; i++) {
            var element = ElementHelper.loadElement(elementNodes[i], this.LogicalOrder, i, this, {});
            this.addElement(element);
        }
    },
    getOptionScore: function(visitedElementsOnly){
        visitedElementsOnly = visitedElementsOnly || false;
        var optionScore = 0;
        this.Elements.each(function(element, index, length){
            if (!visitedElementsOnly || visitedElementsOnly && Author.LessonManager.isElementVisited(element)) {
                optionScore += element.UserScore;
            }
        }, this);
        return optionScore;
    },
    getOptionTotal: function(visitedElementsOnly){
        visitedElementsOnly = visitedElementsOnly || false;
        var optionTotal = 0;
        this.Elements.each(function(element, index, length){
            if (!visitedElementsOnly || visitedElementsOnly && Author.LessonManager.isElementVisited(element)) {
                optionTotal += element.getElementMaxScore();
            }
        }, this);
        return optionTotal;
    },
    travelElements: function(startElementID){
        Author.CurrentStateManager.CurrentElementPosition = -1;
        if (!this.hasElement(startElementID)) {
            return false;
        }
        Author.CurrentStateManager.CurrentElementPosition++;
        while (Author.CurrentStateManager.CurrentElementPosition < this.getElementCount()) {
            var curElement = this.getCurrentElement();
            if (curElement.id != startElementID) {
                curElement.travelElement();
                Author.CurrentStateManager.CurrentElementPosition++;
            } else {
                return curElement;
            }
        }
        return false;
    },
    showNode: function(){
        this.showNextElement();
    },
    showPreviousElement: function(){
        Author.CurrentStateManager.CurrentElementPosition--;
        if (Author.CurrentStateManager.CurrentElementPosition >= 0) {
            var curElement = this.getCurrentElement();
            if (curElement && curElement.isConditionMatched()) {
                curElement.addListener('elementCompleted', this.onElementCompleted, this);
                Author.DisplayManager.showElement(curElement);
            } else {
                this.showPreviousElement();
            }
        }
        else {
            this.onGoBackToParentNode();
        }
    },
    showNextElement: function(){
        Author.CurrentStateManager.CurrentElementPosition++;
        if (Author.CurrentStateManager.CurrentElementPosition < this.getElementCount()) {
            var curElement = this.getCurrentElement();
            if (curElement && curElement.isConditionMatched()) {
                curElement.addListener('elementCompleted', this.onElementCompleted, this);
                Author.DisplayManager.showElement(curElement);
            } else {
                this.showNextElement();
            }
        }
        else {
            this.onElementsCompleted();
        }
    },
    onSkipElement: function(){
        this.showNextElement();
    },
    onElementCompleted: function(element){
        //Author.LessonManager.log(element.Name +"\nCompleted;");
        this.showNextElement();
    },
    onElementsCompleted: function(){
        // Author.LessonManager.log("elementsCompleted:");
        this.onNodeCompleted();
    },
    hasElement: function(eID){
        return this.Elements.containsKey(eID);
    },
    getElementByElementID: function(eID){
        if (this.hasElement(eID)) {
            return this.Elements.getByKey(eID);
        }
        return null;
    },
    addElement: function(e){
        if (this.Elements.containsKey(e.id)) {
            alert("element " + e.id + " already exists.");
        }
        else {
            this.Elements.add(e.id, e);
        }
    },
    getElementCount: function(){
        return this.Elements.getCount();
    },
    getCurrentElement: function(){
        if (Author.CurrentStateManager.CurrentElementPosition < this.getElementCount()) {
            return this.Elements.getAt(Author.CurrentStateManager.CurrentElementPosition);
        }
        return null;
    },
    toString: function(){
        var baseStr = this.callParent([]);
        return Ext.String.format("{0}\nELementCount: {1}", baseStr, this.getElementCount());
    }
});
/**
 *
 * @param {Object} cfgXML
 * @param {Object} parentNode
 * @param {Object} config
 */
Ext.define('RandomNodeClass', {
    extend: 'SequenceNodeClass',
    constructor: function(cfgXML, parentNode, config){
        this.callParent([cfgXML, parentNode, config]);
        this.RandomSetting = new RandomSettingClass(cfgXML, this);
        this.RandomizedElementList = new Ext.util.MixedCollection();
        this.RandomizeEveryTime = true;
    },
    randomizeElements: function(eID){
        this.RandomizedElementList.clear();
        var idArray = this.RandomSetting.getRandomizedElementsIDArray(eID);
        for (var i = 0; i < idArray.length; i++) {
            var e = this.getElementByElementID(idArray[i]);
            if (e && !this.RandomizedElementList.containsKey(e.id)) {
                this.RandomizedElementList.add(e.id, e);
            }
        }
    },
    showNode: function(){
        this.randomizeElements();
        this.showNextElement();
    },
    getOptionTotal: function(visitedElementsOnly){
        visitedElementsOnly = visitedElementsOnly || false;
        var optionTotal = 0;
        this.RandomizedElementList.each(function(element, index, length){
            if (!visitedElementsOnly || visitedElementsOnly && Author.LessonManager.isElementVisited(element)) {
                optionTotal += element.getElementMaxScore();
            }
        }, this);
        return optionTotal;
    },
    getElementCount: function(){
        return this.RandomizedElementList.getCount();
    },
    getCurrentElement: function(){
        if (Author.CurrentStateManager.CurrentElementPosition < this.getElementCount()) {
            return this.RandomizedElementList.getAt(Author.CurrentStateManager.CurrentElementPosition);
        }
        return null;
    },
    toString: function(){
        var baseStr = this.callParent([]);
        return Ext.String.format("{0}", baseStr);
    }
});

