AuthorVariableTypes = {
    Numeric: 0,
    Text: 1,
    Boolean: 2
};
AuthorSystemVariables = {
    ANSWER: ["ANSWER", "0000", AuthorVariableTypes.Text, true, null],
    CORRECT: ["CORRECT", "0001", AuthorVariableTypes.Boolean, true, null],
    INCORRECT: ["INCORRECT", "0002", AuthorVariableTypes.Boolean, true, null],
    SELECTEDVALUE: ["SELECTEDVALUE", "0003", AuthorVariableTypes.Text, true, null],
    SELECTEDNAME: ["SELECTEDNAME", "0004", AuthorVariableTypes.Text, true, null],
    ATTEMPT: ["ATTEMPT", "0005", AuthorVariableTypes.Numeric, true, 0],
    OPSCORE: ["OPSCORE", "0006", AuthorVariableTypes.Numeric, true, 0],
    OPTOTAL: ["OPTOTAL", "0007", AuthorVariableTypes.Numeric, true, 0],
    SCORE: ["SCORE", "0008", AuthorVariableTypes.Numeric, true, 0],
    TOTAL: ["TOTAL", "0009", AuthorVariableTypes.Numeric, true, 0],
    PERSENTAGE_SCORE: ["%SCORE", "0010", AuthorVariableTypes.Numeric, true, 0],
    CORRECTANSWER: ["CORRECTANSWER", "0011", AuthorVariableTypes.Text, true, null],
    QUESTIONANSWER: ["QUESTIONANSWER", "0012", AuthorVariableTypes.Text, true, null],
    RESPONSETIME: ["RESPONSETIME", "0013", AuthorVariableTypes.Numeric, true, 0],
    DATE: ["DATE", "0014", AuthorVariableTypes.Text, true, null],
    DAY: ["DAY", "0015", AuthorVariableTypes.Text, true, null],
    MONTH: ["MONTH", "0016", AuthorVariableTypes.Text, true, null],
    YEAR: ["YEAR", "0017", AuthorVariableTypes.Text, true, null],
    TIME: ["TIME", "0018", AuthorVariableTypes.Text, true, 0],
    FIRSTNAME: ["FIRSTNAME", "0019", AuthorVariableTypes.Text, true, null],
    LASTNAME: ["LASTNAME", "0020", AuthorVariableTypes.Text, true, null],
    FULLNAME: ["FULLNAME", "0021", AuthorVariableTypes.Text, true, null],
    USERID: ["USERID", "0022", AuthorVariableTypes.Text, true, null],
    LESSON: ["LESSON", "0023", AuthorVariableTypes.Text, true, null],
    TIMEOUT: ["TIMEOUT", "0025", AuthorVariableTypes.Numeric, true, 0],
    STARTTIME: ["STARTTIME", "0028", AuthorVariableTypes.Numeric, true, 0],
    ELAPSEDTIME: ["ELAPSEDTIME", "0033", AuthorVariableTypes.Numeric, true, 0],
    RUNTOTAL: ["RUNTOTAL", "0034", AuthorVariableTypes.Numeric, true, 0],
    RUNOPTOTAL: ["RUNOPTOTAL", "0035", AuthorVariableTypes.Numeric, true, 0],
    RUNSCORE: ["RUN%SCORE", "0036", AuthorVariableTypes.Numeric, true, 0],
    ELEMENTNUMBER: ["ELEMENTNUMBER", "0037", AuthorVariableTypes.Numeric, true, 0],
    OPTIONTIME: ["OPTIONTIME", "0038", AuthorVariableTypes.Numeric, true, 0],
    SCORM_STUDENT_ID: ["SCORM_STUDENT_ID", "0045", AuthorVariableTypes.Text, true, null],
    SCORM_STUDENT_NAME: ["SCORM_STUDENT_NAME", "0046", AuthorVariableTypes.Text, true, null],
    SCORM_LESSON_LOCATION: ["SCORM_LESSON_LOCATION", "0047", AuthorVariableTypes.Text, true, null],
    SCORM_CREDIT: ["SCORM_CREDIT", "0048", AuthorVariableTypes.Text, true, null],
    SCORM_LESSON_STATUS: ["SCORM_LESSON_STATUS", "0049", AuthorVariableTypes.Text, false, null],
    SCORM_ENTRY: ["SCORM_ENTRY", "0050", AuthorVariableTypes.Text, true, null],
    SCORM_SCORE_RAW: ["SCORM_SCORE_RAW", "0051", AuthorVariableTypes.Text, false, null],
    SCORM_TOTAL_TIME: ["SCORM_TOTAL_TIME", "0052", AuthorVariableTypes.Text, false, null],
    SCORM_LESSON_MODE: ["SCORM_LESSON_MODE", "0053", AuthorVariableTypes.Text, true, null],
    SCORM_EXIT_REASON: ["SCORM_EXIT_REASON", "0054", AuthorVariableTypes.Text, false, null],
    SCORM_SESSION_TIME: ["SCORM_SESSION_TIME", "0055", AuthorVariableTypes.Text, false, null],
    LESSONSCORE: ["LESSONSCORE", "0064", AuthorVariableTypes.Numeric, false, 0],
    LESSONTOTAL: ["LESSONTOTAL", "0065", AuthorVariableTypes.Numeric, false, 0],
    WEBINFO: ["WEBINFO", "0067", AuthorVariableTypes.Text, false, null],
    BROWSERNAME: ["BROWSERNAME", "0070", AuthorVariableTypes.Text, true, null],
    BROWSERVER: ["BROWSERVER", "0071", AuthorVariableTypes.Text, true, null],
    OSNAME: ["OSNAME", "0072", AuthorVariableTypes.Text, true, null],
    OSVER: ["OSVER", "0073", AuthorVariableTypes.Text, true, null],
    HARDWARE: ["HARDWARE", "0074", AuthorVariableTypes.Text, true, null],
    LESSONTIMEOUT: ["LESSONTIMEOUT", "0075", AuthorVariableTypes.Numeric, true, null],
    ELEMENTNAME: ["ELEMENTNAME", "9999", AuthorVariableTypes.Text, true, null],
    PERCENT_COMPLETE: ["%COMPLETE", "0076", AuthorVariableTypes.Numeric, true, 0 ]
};
Ext.define('AuthorVariable', {
    constructor: function () {
        this.id = null;
        this.Name = null;
        this.Type = AuthorVariableTypes.Text;
        this.Value = null;
        this.IsReadOnly = true;
        this.IsBookMark = false;
        this.IsSystemVariable = true;
    },
    initializeAsSystemVariable: function (name, id, type, isReadOnly, defaultValue) {
        this.Name = name;
        this.id = id;
        this.Type = type;
        this.IsReadOnly = isReadOnly;
        this.IsBookMark = false;
        this.IsSystemVariable = true;
        if (typeof(defaultValue) != 'undefined') {
            this.Value = defaultValue;
        }
    },
    initializeAsUserVariable: function (cfgXML) {
        this.id = XmlHelper.getStringAttribute(cfgXML, 'id');
        this.Name = XmlHelper.getStringAttribute(cfgXML, 'name');
        this.Type = XmlHelper.getIntegerAttribute(cfgXML, 'type');
        this.IsBookMark = XmlHelper.getBooleanAttribute(cfgXML, 'bookMark');

        //this.id = XmlHelper.getString(cfgXML, "id");
        // this.Name = XmlHelper.getString(cfgXML, "name");
        // this.Type = XmlHelper.getInteger(cfgXML, "type");
        // this.IsBookMark = XmlHelper.getBoolean(cfgXML, "bookMark");
        this.IsReadOnly = false;
        this.IsSystemVariable = false;
        this.Value = (this.Type == AuthorVariableTypes.Numeric) ? 0 : '';
    },
    setValue: function (newValue) {
        if (this.IsReadOnly && !this.IsSystemVariable) {
            Author.log("Can't set value to a readonly variable: " + this.Name);
            return;
        }
        if (this.Type == AuthorVariableTypes.Numeric && isNaN(newValue)) {
            Author.log("Can't set " + newValue + " to a numeric variable: " + this.Name);
            return;
        }
        this.Value = newValue;
        if (this.IsSystemVariable) {
            if(!Author.LessonManager.IsScorm) {
                return;
            }
            switch (this.Name) {
                case AuthorSystemVariables.SCORM_STUDENT_ID[0]:
                    break;
                case AuthorSystemVariables.SCORM_STUDENT_NAME[0]:
                    break;
                case AuthorSystemVariables.SCORM_LESSON_LOCATION[0]:
                    Author.LessonManager.ScormAdapter.setLessonLocation(newValue);
                    break;
                case AuthorSystemVariables.SCORM_CREDIT[0]:
                    break;
                case AuthorSystemVariables.SCORM_LESSON_STATUS[0]:
                    Author.LessonManager.ScormAdapter.setLessonStatus(newValue);
                    break;
                case AuthorSystemVariables.SCORM_ENTRY[0]:
                    break;
                case AuthorSystemVariables.SCORM_SCORE_RAW[0]:
                    newValue = parseInt(newValue);
                    Author.LessonManager.ScormAdapter.setLessonScore(newValue);
                    Author.LessonManager.ScormAdapter.setLessonStatusBasedOnScorm(newValue, Author.LessonManager.AuthorLesson.PassMark);
                    Author.LessonManager.ScormAdapter.isScoreSet = true;
                    break;
                case AuthorSystemVariables.SCORM_TOTAL_TIME[0]:
                    break;
                case AuthorSystemVariables.SCORM_LESSON_MODE[0]:
                    break;
                case AuthorSystemVariables.SCORM_EXIT_REASON[0]:
                    Author.LessonManager.ScormAdapter.setExitReason(newValue);
                    break;
                case AuthorSystemVariables.SCORM_SESSION_TIME[0]:
                    break;
            }
        }
    },
    getValue: function () {
        var tmpIsCorrect;
        if (this.IsSystemVariable) {
            switch (this.Name) {
                case AuthorSystemVariables.CORRECT[0]:
                    tmpIsCorrect = Author.CurrentStateManager.getCurrentElementResult();
                    return tmpIsCorrect == null ? false : tmpIsCorrect;
                case AuthorSystemVariables.INCORRECT[0]:
                    tmpIsCorrect = Author.CurrentStateManager.getCurrentElementResult();
                    return tmpIsCorrect == null ? false : !tmpIsCorrect;
                case AuthorSystemVariables.OPSCORE[0]:
                    return Author.CurrentStateManager.CurrentLessonNode ? Author.CurrentStateManager.CurrentLessonNode.getOptionScore() : -1;
                case AuthorSystemVariables.OPTOTAL[0]:
                    return Author.CurrentStateManager.CurrentLessonNode ? Author.CurrentStateManager.CurrentLessonNode.getOptionTotal() : -1;
                case AuthorSystemVariables.SCORE[0]:
                    return Author.LessonManager.AuthorLesson.getLessonScore();
                case AuthorSystemVariables.TOTAL[0]:
                    return Author.LessonManager.AuthorLesson.getLessonTotal();
                case AuthorSystemVariables.PERSENTAGE_SCORE[0]:
                    var score = Author.LessonManager.AuthorLesson.getLessonScore();
                    var total = Author.LessonManager.AuthorLesson.getLessonTotal();
                    //Author.log(Ext.String.format('RunScore: {0}, RunTotal: {1}', runScore, runTotal));
                    return total > 0 ? score * 100 / total : 0;
                case AuthorSystemVariables.CORRECTANSWER[0]:
                    return Author.CurrentStateManager.getCurrentElementCorrectAnswer();
                case AuthorSystemVariables.QUESTIONANSWER[0]:
                    return Author.CurrentStateManager.getCurrentElementUserAnswer();
                case AuthorSystemVariables.RESPONSETIME[0]:
                    return Author.CurrentStateManager.CurrentResponse ? Author.CurrentStateManager.CurrentResponse.RespondTime : -1;
                case AuthorSystemVariables.DATE[0]:
                    return Ext.util.Format.date(new Date(), 'j/m/Y');
                case AuthorSystemVariables.DAY[0]:
                    return new Date().getDate();
                case AuthorSystemVariables.MONTH[0]:
                    return new Date().getMonth();
                case AuthorSystemVariables.YEAR[0]:
                    return new Date().getFullYear();
                case AuthorSystemVariables.TIME[0]:
                    return Ext.util.Format.date(new Date(), "g:i:s A");
                case AuthorSystemVariables.LESSON[0]:
                    return Author.LessonManager.AuthorLesson.Name;
                case AuthorSystemVariables.TIMEOUT[0]:
                    return Author.CurrentStateManager.CurrentElement && Author.CurrentStateManager.CurrentElement.IsTimeoutEnabled ? Author.CurrentStateManager.CurrentElement.Timeout : -1;
                case AuthorSystemVariables.LESSONTIMEOUT[0]:
                    return  Author.LessonManager.AuthorLesson.IsTimeoutEnabled ? Author.LessonManager.AuthorLesson.Timeout : 0;
                case AuthorSystemVariables.STARTTIME[0]:
                    return Ext.util.Format.date(new Date(Author.LessonManager.AuthorLesson.StartTime), "g:i:s A");
                case AuthorSystemVariables.ELAPSEDTIME[0]:
                    return (new Date().getTime() - Author.LessonManager.AuthorLesson.StartTime) / 1000.0;
                case AuthorSystemVariables.RUNTOTAL[0]:
                    return Author.LessonManager.AuthorLesson.getLessonTotal(true);
                case AuthorSystemVariables.RUNOPTOTAL[0]:
                    return Author.CurrentStateManager.CurrentLessonNode ? Author.CurrentStateManager.CurrentLessonNode.getOptionScore(true) : -1;
                case AuthorSystemVariables.RUNSCORE[0]:      //RUN%SCORE
                    var runScore = Author.LessonManager.AuthorLesson.getLessonScore(true);
                    var runTotal = Author.LessonManager.AuthorLesson.getLessonTotal(true);
                    //Author.log(Ext.String.format('RunScore: {0}, RunTotal: {1}', runScore, runTotal));
                    return runTotal > 0 ? runScore * 100 / runTotal : 0;
                case AuthorSystemVariables.ELEMENTNUMBER[0]:
                    return Author.CurrentStateManager.CurrentElementPosition + 1;
                case AuthorSystemVariables.OPTIONTIME[0]:
                    return Author.CurrentStateManager.CurrentLessonNode ? (new Date().getTime() - Author.CurrentStateManager.CurrentLessonNode.OptionStartTime) / 1000.0 : -1;
                case AuthorSystemVariables.SCORM_STUDENT_ID[0]:
                    if(!Author.LessonManager.IsScorm) {
                        return "StudentID not available, No SCORM API found";
                    }
                    return Author.LessonManager.ScormAdapter.getStudentID();
                    break;
                case AuthorSystemVariables.SCORM_STUDENT_NAME[0]:
                    if(!Author.LessonManager.IsScorm) {
                        return "StudentName not available, No SCORM API found";
                    }
                    return Author.LessonManager.ScormAdapter.getStudentName();
                    break;
                case AuthorSystemVariables.SCORM_LESSON_LOCATION[0]:
                    if(!Author.LessonManager.IsScorm) {
                        return "LessonLocation not available, No SCORM API found";
                    }
                    return Author.LessonManager.ScormAdapter.getLessonLocation();
                    break;
                case AuthorSystemVariables.SCORM_CREDIT[0]:
                    return "Not Available";
                    break;
                case AuthorSystemVariables.SCORM_LESSON_STATUS[0]:
                    if(!Author.LessonManager.IsScorm) {
                        return "LessonStatus not available, No SCORM API found";
                    }
                    return Author.LessonManager.ScormAdapter.getLessonStatus();
                    break;
                case AuthorSystemVariables.SCORM_ENTRY[0]:
                    return "Not Available";
                    break;
                case AuthorSystemVariables.SCORM_SCORE_RAW[0]:
                    if(!Author.LessonManager.IsScorm) {
                        return "Score not available, No SCORM API found";
                    }
                    return Author.LessonManager.ScormAdapter.getLessonScore();
                    break;
                case AuthorSystemVariables.SCORM_TOTAL_TIME[0]:
                    return "Not Available";
                    break;
                case AuthorSystemVariables.SCORM_LESSON_MODE[0]:
                    return "Not Available";
                    break;
                case AuthorSystemVariables.SCORM_EXIT_REASON[0]:
                    return "Not Available";
                    break;
                case AuthorSystemVariables.SCORM_SESSION_TIME[0]:
                    return "Not Available";
                    break;
                case AuthorSystemVariables.LESSONSCORE[0]:      // Writable
                    return this.Value;
                case AuthorSystemVariables.LESSONTOTAL[0]:      // Writable
                    return this.Value;
                case AuthorSystemVariables.WEBINFO[0]:
                    return this.Value;
                case AuthorSystemVariables.BROWSERNAME[0]:
                    return BrowserDetect.browser;
                case AuthorSystemVariables.BROWSERVER[0]:
                    return BrowserDetect.version;
                case AuthorSystemVariables.OSNAME[0]:
                    return BrowserDetect.OS;
                case AuthorSystemVariables.OSVER[0]:
                    return 'N/A';
                case AuthorSystemVariables.HARDWARE[0]:
                    return BrowserDetect.hardware;
                case AuthorSystemVariables.ELEMENTNAME[0]:
                    return Author.CurrentStateManager.CurrentElement ? Author.CurrentStateManager.CurrentElement.Name : Author.CurrentStateManager.CurrentLessonNode ? Author.CurrentStateManager.CurrentLessonNode.Name : 'N/A';
                case AuthorSystemVariables.PERCENT_COMPLETE[0]:
                    var buttons = Author.LessonManager.AuthorLesson.LessonRoot.ChildNode.MenuInteractionList.Actions.items

                    var total = 0;
                    var completed = 0;

                    for(buttonIndex = 0; buttonIndex < buttons.length; buttonIndex++){
                        var action = buttons[buttonIndex];
                        if (action.ObjectType === "CUSTOMBUTTON" && action.MarkOptionComplete && action.Name !== "Exit")
                        {
                            total++;
                            if (action.IsMasked)
                            {
                                completed++;
                            }
                        }
                    }

                    var score = (completed/total) * 100;
                    return score;
                default:
                    //  showDebugInfo("get System Variable Value: " + this.Name);
                    return this.Value;
            }
        }
        return this.Value;
    },
    toString: function () {
        return Ext.String.format("ID: {0}, Name: {1}, Type: {2}, Value: {3}\nIsReadOnly: {4}\nIsSystemVariable: {5}", this.id, this.Name, this.Type, this.Value, this.IsReadOnly, this.IsSystemVariable);
    }
});
/**
 *
 */
Ext.define('VariableManager', {
    constructor: function () {
        this.Variables = new Ext.util.MixedCollection();
        this.VariableNameToIDMap = new Ext.util.MixedCollection();
        this.ConstantVariables = new Ext.util.MixedCollection();
        this.initialize();
    },
    initialize: function () {
        this.initializeSystemVariables();
        this.initializeUserVariables();
    },
    hasVariable: function (id) {
        return this.Variables.containsKey(id);
    },
    hasVariableName: function (name) {
        return this.VariableNameToIDMap.containsKey(name.toLowerCase());
    },
    getVariableIDByName: function (name) {
        return this.VariableNameToIDMap.getByKey(name.toLowerCase());
    },
    getVariableByID: function (id) {
        return this.Variables.getByKey(id);
    },
    getVariableByName: function (name) {
        if (this.hasVariableName(name.toLowerCase())) {
            var vid = this.getVariableIDByName(name.toLowerCase());
            return this.hasVariable(vid) ? this.getVariableByID(vid) : null;
        }
        return null;
    },
    getValueByVariableID: function (id) {
        if (this.hasVariable(id)) {
            return this.getVariableByID(id).getValue();
        }
        return null;
    },
    getNumericVariableValueByName: function (name, defaultValue) {
        if (name == null) {
            return defaultValue;
        }
        var v = this.getValueByVariableName(name.toLowerCase());

        if (v !== null && !isNaN(v)) {
            return parseFloat(v);
        } else {
            return defaultValue;
        }
    },
    getValueByVariableName: function (name) {
        if (this.hasVariableName(name.toLowerCase())) {
            var vid = this.getVariableIDByName(name.toLowerCase());
            return this.hasVariable(vid) ? this.getValueByVariableID(vid) : null;
        }
        return null;
    },
    getActionValueByActionName: function (name) {
        var action = Author.CurrentStateManager.getActionByName(name.toLowerCase());

        if (action != null && typeof(action.getInteractionValue) == 'function') {
            //  Author.log("Get interaction value of "+action.Name);
            return action.getInteractionValue();
        }
        else {
            return null;
        }
    },
    getActionValueByActionID: function (actionID) {
        if (Author.CurrentStateManager.hasAction(actionID)) {
            var action = Author.CurrentStateManager.getActionByID(actionID);
            if (typeof(action.getInteractionValue) == 'function') {
                return action.getInteractionValue();
            }
            else {
                return null;
            }
        }
        else {
            return null;
        }
    },
    initializeSystemVariables: function () {
        for (var systemVariable in AuthorSystemVariables) {
            var v = AuthorSystemVariables[systemVariable];
            this.loadASystemVariable(v[0], v[1], v[2], v[3], v[4]);
        }
    },
    loadASystemVariable: function (name, id, type, isReadOnly, defaultValue) {
        var aVar = new AuthorVariable();
        aVar.initializeAsSystemVariable(name, id, type, isReadOnly, defaultValue);
        this.registerVariable(aVar);
    },
    getSystemVariableValue: function (v, defaultValue) {
        var vID = v[1];
        if (this.hasVariable(vID)) {
            var value = this.getVariableByID(vID).getValue();
            if (value == null) {
                return defaultValue;
            } else {
                return value;
            }
        }
        else {
            alert(v + " does not exist!");
            return defaultValue;
        }
    },
    setSystemVariableValue: function (v, value) {
        var vID = v[1];
        if (this.hasVariable(vID)) {
            this.getVariableByID(vID).setValue(value);
        }
        else {
            alert(v + " does not exist!");
        }
    },
    initializeUserVariables: function () {
        var userVariablesNode = Author.lessonXMLDoc.getElementsByTagName("userVariables")[0];
        var userVariablesCount = parseInt(userVariablesNode.getAttribute("count"));
        if (userVariablesCount > 0) {
            var userVariables = userVariablesNode.getElementsByTagName("variable");
            var userVarCount = userVariables.length;
            for (var i = 0; i < userVarCount; i++) {
                this.loadAUserVariable(userVariables[i]);
            }
        }
    },
    loadAUserVariable: function (cfgXML) {
        var aVar = new AuthorVariable();
        aVar.initializeAsUserVariable(cfgXML);
        this.registerVariable(aVar);
    },
    registerVariable: function (aVar) {
        this.Variables.add(aVar.id, aVar);
        this.VariableNameToIDMap.add(aVar.Name.toLowerCase(), aVar.id);
    },
    initializeConstantVariables: function () {
        alert("initializeConstantVariables not implemented");
    },
    hasConstant: function (key) {
        return this.ConstantVariables.containsKey(key);
    },
    getConstant: function (key) {
        if (this.hasConstant(key)) {
            return this.ConstantVariables.getByKey(key);
        }
        return 'undefined';
    },
    loadAConstant: function (cfgXML) {
        var key = cfgXML.getAttribute('key').toUpperCase();
        var value = cfgXML.getAttribute('value');
        this.ConstantVariables.add(key, value);
    },
    saveBookMarkVariables: function () {
        var bookMarkVariables = new Array();
        this.Variables.each(function (variable, index, length) {
            if (!variable.IsSystemVariable && variable.IsBookMark) {
                bookMarkVariables.push({
                    id: variable.id,
                    Value: variable.Value
                });
            }
        }, this);
        //alert(print(bookMarkVariables));
        return bookMarkVariables;
    },
    loadBookMarkVariables: function (savedVariables) {
        if (typeof (savedVariables) == 'undefined') {
            return;
        }
        if (!Ext.isArray(savedVariables)) {
            return;
        }
        Ext.Array.forEach(savedVariables, function (item, index, allItems) {
            if (this.hasVariable(item.id)) {
                var v = this.getVariableByID(item.id);
                v.setValue(item.Value);
                // Author.log(Ext.String.format("Loaded bookmark variable {0}[{2}], value: {1}.", v.Name, item.Value, v.id));
            } else {
                Author.log(Ext.String.format("Variable {0} does not exists.", item.id));
            }
        }, this);
    }
});


