ElementHelper = {
    loadElement:function (cfgXML, o, epos, parentNode, config) {
        var eType = cfgXML.getAttribute('type');
        switch (eType) {
            case 'INFORMATION':
                return new InformationElementClass(cfgXML, o, epos, parentNode, config);
                break;
            default:
                return new GeneralElementClass(cfgXML, o, epos, parentNode, config);
                break;
        }
    }
};
/**
 *
 * @param {Object} cfgXML
 * @param {Object} o
 * @param {Object} epos
 * @param {Object} config
 */
Ext.define('InformationElementClass', {
    extend:'Ext.util.Observable',
    constructor:function (cfgXML, o, epos, parentNode, config) {
        Ext.apply(this, config);
        this.addEvents({
            "elementLoaded":true,
            "elementCompleted":true,
            "elementTravelled":true
        });
        this.callParent([]);
        this.id = cfgXML.getAttribute('id');
        this.Type = cfgXML.getAttribute('type');
        this.Name = cfgXML.getAttribute('elementName');
        this.ParentNode = parentNode;
        this.HasCondition = cfgXML.getAttribute('hasCondition').toLowerCase() == 'true';
        this.Condition = null;
        this.IsTimeoutEnabled = false;
        this.UserScore = 0;
        if (this.HasCondition) {
            var conditionNode = cfgXML.getElementsByTagName('condition')[0];
            this.Condition = new AuthorCondition(conditionNode);
        }
        this.LogicalOrder = new OrderClass(o.NodePath, 'Element', epos);
        this.ElementPosition = epos;
        this.IsShowInReference = cfgXML.getAttribute('showInReference').toLowerCase() == 'true';
        this.InformationList = new ListClass(cfgXML.getElementsByTagName('list')[0], this.LogicalOrder, {});
    },
    isConditionMatched:function () {
        return this.HasCondition ? this.Condition.isConditionMatched() : true;
    },
    getElementMaxScore:function () {
        return 0;
    },
    travelElement:function () {
        Author.CurrentStateManager.CurrentActionPosition = -1;
        Author.CurrentStateManager.CurrentAction = null;
        Author.CurrentStateManager.CurrentList = null;
        Author.CurrentStateManager.CurrentResponse = null;
        Author.CurrentStateManager.CurrentElement = this;
        this.InformationList.addListener('listTravelled', this.onInformationListTravelled, this);
        this.InformationList.travelList();
    },
    onElementTravelled:function () {
        if (this.hasListener('elementTravelled')) {
            this.fireEvent('elementTravelled', this);
        }
    },
    onInformationListTravelled:function () {
        this.onElementTravelled();
    },
    onStartShowElement:function () {
        Author.CurrentStateManager.CurrentActionPosition = -1;
        Author.CurrentStateManager.CurrentAction = null;
        Author.CurrentStateManager.CurrentList = null;
        Author.CurrentStateManager.CurrentResponse = null;
        Author.CurrentStateManager.CurrentElement = this;
        Author.DisplayManager.clearScreen(this);
        Author.CurrentStateManager.updateProgressBar();
        Author.VariableManager.setSystemVariableValue(AuthorSystemVariables.ATTEMPT, 1);
    },
    onElementCompleted:function () {

        if (Author.LessonManager.ReferenceWindow.isVisible()) {
            Author.LessonManager.ReferenceWindow.highLightCurrentScreen();
        }

        if (Author.DisplayManager.Pause) {
            Author.DisplayManager.pause = null;
        }
        if (this.hasListener('elementCompleted')) {
            this.fireEvent('elementCompleted', this);
        }
    },
    show:function () {
        this.showInformationList();
    },
    showInformationList:function () {
        this.InformationList.addListener('listCompleted', this.onInformationListCompleted, this);
        Author.DisplayManager.showList(this.InformationList);
    },
    onInformationListCompleted:function () {
        this.onElementCompleted();
    },
    toString:function () {
        var str = Ext.String.format("Element ID: {0}\nType: {1}", this.id, this.Type);
        if (this.HasConditon) {
            str += Ext.String.format("\n{0}", this.Condition.toString());
        }
        str += Ext.String.format("\nInformationList:\n{0}", this.InformationList);
        return str;
    }
});
Ext.define('GeneralElementClass', {
    extend:'InformationElementClass',
    constructor:function (cfgXML, o, epos, parentNode, config) {
        this.callParent([ cfgXML, o, epos, parentNode, config]);
        this.Timeout = parseFloat(cfgXML.getAttribute('timeout'));
        this.IsTimeoutEnabled = cfgXML.getAttribute('isTimeoutEnabled').toLowerCase() == 'true';
        this.AnyKey = cfgXML.getAttribute('anyKey').toLowerCase() == 'true';
        this.AnyClick = cfgXML.getAttribute('anyClick').toLowerCase() == 'true';
        this.RandomizeInteraction = cfgXML.getAttribute('randomizeInteraction').toLowerCase() == 'true';
        this.InteractionList = new ListClass(cfgXML.getElementsByTagName('list')[1], this.LogicalOrder, {});
        this.Responses = new Ext.util.MixedCollection();
        this.InteractionListFinishedTimestamp = 0;
        if (this.Type != 'GENERAL') {
            this.AnswerCount = parseInt(cfgXML.getAttribute('answerCount'));
            this.CorrectAnswerString = XmlHelper.tryGetValue(cfgXML, 'correctAnswer', TryGetValueOption.Normal, '');
        }
        this.loadResponses(cfgXML);
    },
    onInformationListTravelled:function () {
        this.InteractionList.addListener('listTravelled', this.onInteractionListTravelled, this);
        this.InteractionList.travelList();
    },
    onInteractionListTravelled:function () {
        this.onElementTravelled();
    },
    show:function () {
        Author.CurrentStateManager.resetList(this.InteractionList);
        this.callParent([]);
    },
    onInformationListCompleted:function () {

        this.showInteractionList();
    },
    showInteractionList:function (startActionPosition) {
        this.InteractionList.addListener('listCompleted', this.onInteractionListCompleted, this);
        Author.DisplayManager.showList(this.InteractionList, startActionPosition);
    },
    startTimeoutTimer:function () {
        // Author.log('StartElementTimeoutTimer');
        if (Author.CurrentStateManager.CurrentElementTimeoutTimer) {
            alert('startTimeoutTimer, Author.CurrentStateManager.CurrentElementTimeoutTimer should not have any value.');
        }
        var that = this;
        Author.CurrentStateManager.CurrentElementTimeoutTimer = setTimeout(function(){
                that.onTimeout(that);
            }, this.Timeout * 1000
        );
    },
    onTimeout:function (element) {
        // Author.log('OnElementTimeout');
        if (element.getResponsesCount() == 0) {
            element.onElementCompleted();
        } else {
            Author.DisplayManager.tryToTriggerResponse(element.Name, 'TIMEOUT', 'TIMEOUT');
        }
    },
    onInteractionListCompleted:function (isFromResponse) {

        if(isFromResponse!==true &&  this.RandomizeInteraction){

           this.randomizeInteractions();
        }

        if (Author.DisplayManager.Pause) {
            // Author.log("onInteractionListCompleted:\n" + Author.DisplayManager.Pause.Source);
        }
        Author.DisplayManager.Pause = this.getAuthorPause();

        this.InteractionListFinishedTimestamp = new Date().getTime();
        this.InteractionList.Actions.each(function (action, index, length) {
           if (action.ObjectType == 'TEXTFIELD') {
               action.setFocus();
               return false;
           }
        });

        if (this.IsTimeoutEnabled) {
            this.startTimeoutTimer();
        } else {
            if (this.getResponsesCount() == 0) {
              //  this.onElementCompleted();
            }
        }
    },

    randomizeInteractions: function () {
       // Author.showCurrentListActions();
        var locations = [],
            itemsToRandomize = [];
        this.InteractionList.Actions.eachKey(function (key, item) {
            if (item.ObjectType != 'HOTSPOT') {
                // if(item.ReArrange){
                itemsToRandomize.push(item);
                locations.push(item.getPosition());
                // }
            }
        });
        for (var i = 0; i < itemsToRandomize.length; i++) {
            var item = itemsToRandomize[i];
            if (locations.length > 0) {
                var rand = Math.floor((Math.random() * locations.length)),
                    loc = locations.splice(rand, 1)[0];
                item.moveTo(loc.Left, loc.Top);
            }
        }
    },

    getCorrectAnswers:function () {
        switch (this.Type) {
            case 'MULTIPLECHOICE':
                return this.CorrectAnswerString.toUpperCase().split('|');
            case 'TRUEFALSE':
            case 'YESNO':
                return this.CorrectAnswerString.toUpperCase();
            case 'SHORTANSWER':
                return this.CorrectAnswerString.split('<|>');
            default:
                return null;
        }
    },
    isAnswerCorrect:function () {
        if (this.Type == 'GENERAL') {
            return null;
        }
        var userAnswers = this.getGeneralAnswer();


        if (!userAnswers || userAnswers.length == 0) {
            if (this.AnswerCount == 1) {
                userAnswers = new Array();
                userAnswers.push(Author.VariableManager.getVariableByName(AuthorSystemVariables.ANSWER[0]).getValue());
            } else {
                return false;
            }
        }


        var correctAnswers, i;
        switch (this.Type) {
            case 'MULTIPLECHOICE':
                if (userAnswers.length != this.AnswerCount) {
                    return false;
                }
                correctAnswers = this.getCorrectAnswers();
                for (i = 0; i < userAnswers.length; i++) {
                    if (correctAnswers.indexOf(userAnswers[i].toUpperCase()) == -1) {
                        return false;
                    }
                }
                return true;
            case 'TRUEFALSE':
            case 'YESNO':
                if (userAnswers.length > 1) {
                    Author.log(Ext.String.format('Too many answers for a {0} element. Answers:\n{1}', this.Type, print(userAnswers)));
                }
                return userAnswers[0].toUpperCase() == this.getCorrectAnswers().toUpperCase();
            case 'SHORTANSWER':
                if (userAnswers.length > 1) {
                    Author.log(Ext.String.format('Too many answers for a {0} element. Answers:\n{1}', this.Type, print(userAnswers)));
                }
                correctAnswers = this.getCorrectAnswers();
                for (i = 0; i < correctAnswers.length; i++) {
                    var check = correctAnswers[i];
                    check = check.replace(/\*/g, ".*");
                    check = check.replace(/\?/g, ".{1}");
                    var checkRegex = new RegExp(check, 'gi');
                    if (userAnswers[0].search(checkRegex) >= 0) {
                        return true;
                    }
                }
                return false;
            default:
                alert("isAnswerCorrect.error");
                return null;
        }
    },
    getGeneralAnswer:function () {
        var precedentActionType = null;
        var tmpAnswer = null;
        Author.CurrentStateManager.CurrentActionList.each(function (action, index, length) {
            if (action.IsVisible && this.InteractionList.containsAction(action) && (action.ObjectType != 'DDBUTTON' || action.ObjectType == 'CUSTOMBUTTON' && action.IsToggleButton)) {
                // Author.log(Ext.String.format("GetAnswer: checking action:\n {0}", action.getShortDescription()));
                if (action.ObjectType != precedentActionType) {
                    precedentActionType = action.ObjectType;
                    tmpAnswer = new Array();
                }
                var actionValue = action.getInteractionValue();
                switch (action.ObjectType) {
                    case "CUSTOMBUTTON":
                        if (action.IsChecked) {
                            tmpAnswer.push(action.Name);
                        }
                        break;
                    case "TEXTFIELD":
                        tmpAnswer.push(action.getInteractionValue());
                        break;
                    case "RADIOBUTTON":
                        if (action.IsChecked) {
                            tmpAnswer.push(action.Name);
                        }
                        break;
                    case "COMBOBOX":
                        tmpAnswer.push(action.getInteractionValue());
                        break;
                    case "CHECKBOX":
                        if (action.IsChecked) {
                            tmpAnswer.push(action.Name);
                        }
                        break;
                    case "HOTSPOT":
                        tmpAnswer.push(action.getInteractionValue());
                        break;
                }
            }
        }, this);
        return null || tmpAnswer;
    },
    onSkippedByUser:function (skipEvent) {
        if (Author.DisplayManager.Pause) {
            if (Author.DisplayManager.Pause.Source.id = this.id) {
                Author.DisplayManager.Pause = null;
            }
        }
        var selectedName = null, selectedValue = null, answer = null, elementAnswers;
        switch (skipEvent.Trigger) {
            case SkipEventTriggers.Action:
                selectedName = skipEvent.EventObject.Name;
                selectedValue = skipEvent.EventObject.Value;
                elementAnswers = this.getGeneralAnswer();
                answer = ((elementAnswers) ? elementAnswers.join(',') : null) || selectedValue;
                break;
            case SkipEventTriggers.Keyboard:
                answer = skipEvent.EventObject.Key;
                break;
            case SkipEventTriggers.Mouse:
                answer = skipEvent.EventObject.Key;
                break;
        }


        Author.CurrentStateManager.checkAndShowResponse(selectedName, selectedValue, answer);
    },
    getAuthorPause:function () {
        var cancelType = CancelTypes.None;
        if (this.AnyClick) {
            cancelType = CancelTypes.MouseClickOnly;
        }
        if (this.AnyKey) {
            cancelType = CancelTypes.AnyKey;
        }
        if (this.AnyKey && this.AnyClick) {
            cancelType = CancelTypes.MouseClickOrAnyKey;
        }
        //Author.CurrentStateManager.fixZIndexes();
        // Author.log(Author.CurrentStateManager.getCurrentActions());
        return new AuthorPause(this, WaitModes.WaitForUser, 3600 * 24 * 1000, cancelType, null, null);
    },
    onRepeat:function () {
        Author.DisplayManager.showElement(this);
    },
    checkAndShowResponse:function () {
        //  alert("Element:checkAndShowResponse");
        if (this.getResponsesCount() == 0) {
            this.onElementCompleted();
        }
        else {
            var firstMatchedResponse = null;
            this.Responses.each(function (response, index, length) {
                // Author.log("Checking response: "+response.toString());
                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;
                this.UserScore = firstMatchedResponse.Score;
                Author.DisplayManager.showResponse(firstMatchedResponse);
            }
            else {
               // Author.log("No Response Matched, complete this Element");
                this.onElementCompleted();
            }
        }
    },
    getElementMaxScore:function () {
        var maxScore = 0;
        this.Responses.each(function (response, index, length) {
            if (response.Score > maxScore) {
                maxScore = response.Score;
            }
        }, this);
        return maxScore;
    },
    onResponseCompleted:function (response) {
        //alert("ResponseCompleted:\n" + response);
        //Check Remove or not
        //response.FeedbackOption = FeedbackOptions.RemoveBeforeNextResponse;
        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, 1);
            Author.VariableManager.setSystemVariableValue(AuthorSystemVariables.ATTEMPT, (curAttempt + 1));
        }
        //  response.ResetInteraction=true;
        if (response.ResetInteraction) {
            Author.CurrentStateManager.resetList(this.InteractionList);
        }
        switch (response.RepeatType) {
            case RepeatTypes.RepeatFromInformation:
                // Author.log("repeat From Information");
                this.InteractionList.removeListActions();
                this.InformationList.removeListActions();
                this.showInformationList();
                break;
            case RepeatTypes.RepeatFromInteraction:
               // Author.log("repeat From interaction");
                //this.InteractionList.removeListActions();
                //this.showInteractionList();
                Author.CurrentStateManager.CurrentActionPosition = this.InteractionList.Actions.length;
                Author.CurrentStateManager.CurrentAction = null;
                Author.CurrentStateManager.CurrentList = this.InteractionList;
                this.onInteractionListCompleted(true);
                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 base = this.callParent([]);
        return Ext.String.format("{0}\nInteractionList:\n{4}\nAnyKey: {1}\nAnyClick: {2}\nTimeout: {3} ", base, this.AnyKey, this.AnyClick, this.Timeout, this.InteractionList);
    }
});

