var _NoError = {"code":"0", "string":"No Error", "diagnostic":"No Error"};
var _GeneralException = {"code":"101", "string":"General Exception", "diagnostic":"General Exception"};

ScormDataModels = {
    ScormVersion:['Scorm 1.2', 'Scorm 2004 3rd'],
    ScormPass:['passed','completed'],
    ScormFailed:['failed','incomplete'],
    AvailableLessonStatusReg:[/(passed|completed|failed|incomplete|not attemped)/, /(completed|incomplete|not attempted|unknown)/],
    AvailableLessonExitReg:[/(time-out|suspend|logout|)/, /(timeout|suspend|logout|normal|)/],
    StudentID:['cmi.core.student_id', 'cmi.learner_id'], //RO
    StudentName:['cmi.core.student_name', 'cmi.learner_name'], //RO
    LessonLocation:['cmi.core.lesson_location', 'cmi.location'], // String (255), RW
    LessonStatus:['cmi.core.lesson_status', 'cmi.completion_status'], //“passed”, “completed”, “failed”, “incomplete”, “browsed”, “not attempted”, RW   ,“completed”, “incomplete”, “not attempted”, “unknown”, RW
    ScoreRaw:['cmi.core.score.raw', 'cmi.score.raw'], //Decimal, RW
    Exit:['cmi.core.exit', 'cmi.exit'] // “time-out”, “suspend”, “logout”, “”, WO
};

Ext.define('AuthorScromAdapter', {
    constructor:function (scormType) {
        this.ShowDebug = false;
        this.ScormType = scormType;
        this.IsInitialized = false;
        this.ApiHandle = null;
        this.MaxFindApiTries = 10;
    },
    onLessonExit:function () {
      this.scormFinish();
    },
    getStudentID:function () {
        return this.scormGetValue(ScormDataModels.StudentID[this.ScormType]);
    },
    getStudentName:function () {
        return this.scormGetValue(ScormDataModels.StudentName[this.ScormType]);
    },
    getLessonLocation:function () {
        return this.scormGetValue(ScormDataModels.LessonLocation[this.ScormType]);
    },
    getLessonStatus:function () {
        return this.scormGetValue(ScormDataModels.LessonStatus[this.ScormType]);
    },
    getLessonScore:function () {
        return this.scormGetValue(ScormDataModels.ScoreRaw[this.ScormType]);
    },
    setLessonLocation:function (location) {
        if (this.scormSetValue(ScormDataModels.LessonLocation[this.ScormType], location) && this.scormCommit()) {
            return true;
        } else {
            return false;
        }
    },
    setLessonScore:function (score) {
        if (this.scormSetValue(ScormDataModels.ScoreRaw[this.ScormType], score) && this.scormCommit()) {
            return true;
        } else {
            return false;
        }
    },
    setLessonStatusBasedOnScorm:function(score, passmark){
        Author.LessonManager.ScormAdapter.setLessonStatus(score >= passmark ? ScormDataModels.ScormPass[this.ScormType] : ScormDataModels.ScormFailed[this.ScormType]);
    } ,
    setLessonStatus:function (status) {
        status = status.toLowerCase();
        var match = status.match(ScormDataModels.AvailableLessonStatusReg[this.ScormType]);
        if (match) {
            if (this.scormSetValue(ScormDataModels.LessonStatus[this.ScormType], status) && this.scormCommit()) {
                return true;
            } else {
                return false;
            }
        } else {
            if (Author.log) {
                alert(Ext.String.format("{0} is not a valid lesson status for {1}.", status, ScormDataModels.ScormVersion[this.ScormType]));
            }
            return false;
        }
    },
    setExitReason:function (reason) {
        reason = reason.toLowerCase();
        var match = reason.match(ScormDataModels.AvailableLessonExitReg[this.ScormType]);
        if (match) {
            if (this.scormSetValue(ScormDataModels.Exit[this.ScormType], status) && this.scormCommit()) {
                return true;
            } else {
                return false;
            }
        } else {
            if (Author.log) {
                alert(Ext.String.format("{0} is not a valid exit reason for {1}.", status, ScormDataModels.ScormVersion[this.ScormType]));
            }
            return false;
        }
    },
    scormInitialize:function () {
        if (this.IsInitialized) return "true";
        var api = this.getAPIHandle();
        if (api == null) {
            if (this.ShowDebug) {
                Author.log("Unable to locate the LMS's API Implementation.\nLMSInitialize was not successful.");
            }
            return false;
        }
        var result = 'false';
        switch (this.ScormType) {
            case ScormTypes.Scorm12:
                result = api.LMSInitialize("");
                break;
            case ScormTypes.Scorm20043Rd:
                result = api.Initialize("");
                break;
        }
        if (result.toString() != "true") {
            if (this.ShowDebug) {
                Author.log("ScormInitialize failed");
            }
        }
        else {
            this.IsInitialized = true;
        }
        return result.toString().toLowerCase() == 'true';
    },
    scormFinish:function () {
        if (!this.IsInitialized) return "true";
        var api = this.getAPIHandle();
        if (api == null) {
            if (this.ShowDebug) {
                Author.log("Unable to locate the LMS's API Implementation.\nScormFinish was not successful.");
            }
            return false;
        }
        else {
            var result = 'false';
            switch (this.ScormType) {
                case ScormTypes.Scorm12:
                    result = api.LMSFinish("");
                    break;
                case ScormTypes.Scorm20043Rd:
                    result = api.Terminate("");
                    break;
            }
            if (result.toString() != "true") {
                if (this.ShowDebug) {
                    Author.log("ScormFinish failed.");
                }
            }
        }
        this.IsInitialized = false;
        return result.toString().toLowerCase() == 'true';

    },
    scormGetValue:function (name) {
        var api = this.getAPIHandle();
        var result = "";
        if (api == null) {
            if (this.ShowDebug) {
                Author.log("Unable to locate the LMS's API Implementation.\nScormGetValue was not successful.");
            }
        }
        else if (!this.IsInitialized && !this.scormInitialize().toLowerCase() == 'true') {
            if (this.ShowDebug) {
                Author.log("scormGetValue failed - Could not initialize communication with the LMS.");
            }
        }
        else {
            switch (this.ScormType) {
                case ScormTypes.Scorm12:
                    result = api.LMSGetValue(name);
                    break;
                case ScormTypes.Scorm20043Rd:
                    result = api.GetValue(name);
                    break;
            }
            var error = this.scormErrorHandler();
            if (error.code != _NoError.code) {
                if (this.ShowDebug) {
                    Author.log("ScormGetValue(" + name + ") failed.\nError code:" + error.code);
                }
                result = "";
            }
        }
        return result.toString();
    },
    scormSetValue:function (name, value) {
        var api = this.getAPIHandle();
        var result = "false";
        if (api == null) {
            if (this.ShowDebug) {
                Author.log("Unable to locate the LMS's API Implementation.\nScormSetValue was not successful.");
            }
        }
        else if (!this.IsInitialized && !this.scormInitialize().toLowerCase() == 'true') {
            if (this.ShowDebug) {
                Author.log("ScormSetValue failed - Could not initialize communication with the LMS.");
            }
        }
        else {
            switch (this.ScormType) {
                case ScormTypes.Scorm12:
                    result = api.LMSSetValue(name, value);
                    break;
                case ScormTypes.Scorm20043Rd:
                    result = api.SetValue(name, value);
                    break;
            }
            if (result.toString() != "true") {
                if (this.ShowDebug) {
                    Author.log("ScormSetValue(" + name + ", " + value + ") failed. ");
                }
            }
        }
        return result.toString().toLowerCase() == 'true';
    },
    scormCommit:function () {
        var api = this.getAPIHandle();
        var result = "false";
        if (api == null) {
            if (this.ShowDebug) {
                Author.log("Unable to locate the LMS's API Implementation.\nScormCommit was not successful.");
            }
        }
        else if (!this.IsInitialized && !this.scormInitialize().toLowerCase() == 'true') {
            if (this.ShowDebug) {
                Author.log("ScormCommit failed - Could not initialize communication with the LMS.");
            }
        }
        else {
            switch (this.ScormType) {
                case ScormTypes.Scorm12:
                    result = api.LMSCommit("");
                    break;
                case ScormTypes.Scorm20043Rd:
                    result = api.Commit("");
                    break;
            }
            if (result != "true") {
                if (this.ShowDebug) {
                    Author.log("ScormCommit failed.");
                }
            }
        }
        return result.toString().toLowerCase() == 'true';
    },
    getTargetScormAPIWrapper:function (win) {
        switch (this.ScormType) {
            case ScormTypes.Scorm12:
                return win.API;
            case ScormTypes.Scorm20043Rd:
                return win.API_1484_11;
        }
    },
    findAPI:function (win) {
        var findAPITries = 0;
        while ((this.getTargetScormAPIWrapper(win) == null) && (win.parent != null) && (win.parent != win)) {
            if (++findAPITries > this.MaxFindApiTries) {
                if (this.ShowDebug) {
                    Author.log("Error finding API -- too deeply nested.");
                }
                return null;
            }
            win = win.parent;
        }
        return this.getTargetScormAPIWrapper(win);
    },
    getAPI:function () {
        var theAPI = this.findAPI(window);
        if ((theAPI == null) && (window.opener != null) && (typeof(window.opener) != "undefined")) {
            theAPI = this.findAPI(window.opener);
        }
        if (theAPI == null) {
            if (this.ShowDebug) {
                Author.log("Unable to find an API adapter");
            }
        }
        return theAPI;
    },
    //Same for both.
    getAPIHandle:function () {
        if (this.ApiHandle == null) {
            this.ApiHandle = this.getAPI();
        }
        return this.ApiHandle;
    },
    scormGetLastErrorCode:function (apiWrapper) {
        switch (this.ScormType) {
            case ScormTypes.Scorm12:
                return  apiWrapper.LMSGetLastError().toString();
                break;
            case ScormTypes.Scorm20043Rd:
                return  apiWrapper.GetLastError().toString();
                break;
        }
    },
    scormErrorHandler:function () {
        var error = {"code":_NoError.code, "string":_NoError.string, "diagnostic":_NoError.diagnostic};
        var api = this.getAPIHandle();
        if (api == null) {
            if (this.ShowDebug) {
                Author.log("Unable to locate the LMS's API Implementation.\nCannot determine LMS error code.");
            }
            error.code = _GeneralException.code;
            error.string = _GeneralException.string;
            error.diagnostic = "Unable to locate the LMS's API Implementation. Cannot determine LMS error code.";
            return error;
        }
        error.code = this.scormGetLastErrorCode(api);
        if (error.code != _NoError.code) {
            error.string = "An error has happened."
            error.diagnostic = "Not available."
        }
        return error;
    }
});



