/*
 * This file allows an MVx client to interact with Pearson's SSO system.
 *
 * It will also define a set of features allowing the results to be
 * stored on an application specific server (via sessions).
 *
 * @author Brian Roy
 * @date 02/07/2011
 *
 */

/*
 * Constructor
 * 
 * Update
 * Update 2
 */

function ajaxEntity() {
    
    this.RESOURCE = 'http://' + window.location.host + '/api/entity/v1/';

    /* 
     * Resource Methods
     */
    
    // Getters
    this.GETSTATUS            = 'cmd=getstatus';
    this.GETVIEWUSERSTATUS    = 'cmd=getviewuserstatus';
    this.GETNEXTACT           = 'cmd=getactivity';
    this.GETHISTORY           = 'cmd=getentityhistory';        
    this.GETVIEWUSERNEXTACT   = 'cmd=getviewuseractivity';    
    this.GETENTITYIMG         = 'cmd=getattrstring';
    this.GETVIEWUSERENTITYIMG = 'cmd=getviewuserattrstring';
    this.GETVIDEOS            = 'cmd=getvideos';
    this.GETVIEWUSERVIDEOS    = 'cmd=getviewuservideos';
    this.GETAGESCHEDULE       = 'cmd=getagerangeschedule';
    this.GETHISTMOMENT        = 'cmd=gethistmoment';    
    this.ISVALIDCOURSEID      = 'cmd=isvalidcourseid';
    this.GETUPDATES           = 'cmd=getupdates';
    this.GETHISTVARS          = 'cmd=gethistvars';
    
    // Setters
    this.UNASSIGNCOURSE        = 'cmd=unassigncourse';
    this.CHANGECOURSEID        = 'cmd=changecourseid';
    this.SAVEASSIGN            = 'cmd=saveassignment';
    this.SAVEQUESTION          = 'cmd=savequestion';
    this.SETVIEWUSER           = 'cmd=setviewuser';   
    this.SAVEEVENT             = 'cmd=saveevent';
    this.GETVIEWUSER           = 'cmd=getviewuser';
    this.RESETINSTRUCTORENTITY = 'cmd=resetinstructorentity';
    this.RESETSTUDENTENTITY    = 'cmd=resetstudententity';
    this.SAVEREPORT   	       = 'cmd=savereport';
    this.SAVEVARIABLE          = 'cmd=setentityvariable';

    // Error Hander
    tErr = new mvcErrorHandler;

    tErr.setObject("ajaxEntity");
}


/*
 * Method getServerData is generic and allows for the fetching of any
 * data from a server side using the JQuery ajax method.
 *
 * @param URL string The URL for the server side API.
 * @param SuccessFunc string The name of the function to call when the result is returned.
 * @param ErrorFunc strinf The name of the function to call when the result is an error.
 * @param DataType string The kind of data interaction (xml, json, etc).
 * @param Method string HTTP method (get, post, put, etc).
 * @param reqData string The request data.
 *
 *
 */

ajaxEntity.prototype.getServerData = function(URL, SuccessFunc, ErrorFunc, DataType, Method, reqData, isAsync) {
    if(typeof(isAsync) == 'undefined') isAsync = true;
    
    
    /*
     * Set default values if optional are empty.
     */
    DataType = typeof(DataType) != 'undefined' ? DataType : "xml";
    Method   = typeof(Method) != 'undefined' ? Method : 'GET';
    reqData  = typeof(reqData) != 'undefined' ? reqData : "";

    $.ajax({
            url: URL,
            type: Method,
            dataType: DataType,
            data: reqData,
            async: isAsync,
            success: function(xml) {
                    SuccessFunc(xml);
            },
            error: function(a,b,c) {
                var msg = ('error', a.status + " message: " + a.statusText + " response text: " + a.responseText);
                tErr.throwError(msg, tErr.SEVERE, tErr.IGNORE, "");
                ErrorFunc(a, b, c);
            }

    });

}

/*
 * Method getEntityStatus gets the current status of this entity
 * (or child in the case of MVC).
 *
 *
 * @param tCallback function The callback function on sucess.
 * @param errorCallback function The callback function on error.
 */
ajaxEntity.prototype.getEntityStatus = function(tCallback, errorCallback) {
    tErr.setMethod("getEntityStatus");
    var params = this.GETSTATUS;          
    this.getServerData(this.RESOURCE, tCallback, errorCallback, 'JSON', 'GET', params, false);
    return false;
}

ajaxEntity.prototype.getEntityViewUserStatus = function(tCallback, errorCallback, uid) {
    tErr.setMethod("getEntityViewUserStatus");
    var params = this.GETVIEWUSERSTATUS + '&uid=' + uid;              
    this.getServerData(this.RESOURCE, tCallback, errorCallback, 'JSON', 'GET', params, false);
    return false;
}

/*
 * Method statusResult recieves the json response and does the callback.
 *
 * @param json object The recieved content (json/xml).
 *
 */

ajaxEntity.prototype.statusResult = function(json) {
    var stat = json.name + " " + json.age_months + " months old, " + json.gender.toLowerCase();
    this.targetId.empty();
    this.targetId.append(stat);
}

/**
 * Method getHistory gets the list of entity actions that have been completed.
 */
ajaxEntity.prototype.getHistory = function(eId, successCallback, errorCallback, uid) {
    tErr.setMethod("getHistory");
    var params = this.GETHISTORY + "&eid=" + eId;    
    if ((typeof uid != 'undefined') && (uid != 0)) {
        params += '&uid=' + uid;
    }    
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'GET', params);
    return false;
}



/**
 * Method getTimelineMonths defines and returns the months visible in the 
 * timeline bar.
 * 
 */
ajaxEntity.prototype.getTimelineMonths = function() {
    var timelinebar = new Array();
    timelinebar[1] = 0;
    timelinebar[2] = 3;
    timelinebar[3] = 8;
    timelinebar[4] = 12;
    timelinebar[5] = 15;
    timelinebar[6] = 18;
    timelinebar[7] = 19;
    timelinebar[8] = 24;
    timelinebar[9] = 36;
    timelinebar[10] = 48;
    timelinebar[11] = 60;
    timelinebar[12] = 72;
    timelinebar[13] = 96;
    timelinebar[14] = 120;
    timelinebar[15] = 132;
    timelinebar[16] = 144;
    timelinebar[17] = 156;
    timelinebar[18] = 168;
    timelinebar[19] = 180;
    timelinebar[20] = 192;
    timelinebar[21] = 204;
    timelinebar[22] = 216;

    return timelinebar;
}

ajaxEntity.prototype.getNextTimelineMonths = function(curr) {
    var tl = this.getTimelineMonths();        
    var j = 0;
    var isFound = false;
    for(var i in tl) {
        if(isFound) {
            return tl[i];
            break;
        }
        if(tl[i] == curr) isFound = true;
        if(tl[i] > curr) return tl[i];
    }
    return false;
}

ajaxEntity.prototype.isAgeInTimeline = function(aMonths) {
    var tlT = this.getTimelineMonths();
    
    for(var i in tlT) {
        if(tlT[i] == aMonths) return true;
    }
    return false;
}


/**
 * Method formatAge formats an timeline age for display
 *
 * @param mths int Age in Months
 * @param kind string Either "age" or "units" - to return.
 *
 */
ajaxEntity.prototype.formatAge = function(mths, kind) {
    if(mths < 24) {
        if(kind == "age") return mths;
        if(kind == "unit") return "months";
    }

    var modMths = mths%12;
    
    if(modMths != 0) {
        //return false;
        mths = mths - modMths;
    }

    var yrs = mths/12;
    if(kind == "age") return yrs;
    if(kind == "unit") return "years";

    return false;
}

/**
 * Method getNextActivity returns the next timeline activity for
 * the entity.
 *
 *
 * @param successCallback function The callback function on sucess.
 * @param errorCallback function The callback function on error.
 */
ajaxEntity.prototype.getNextActivity = function(successCallback, errorCallback) {
    tErr.setMethod("getNextActivity");
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'GET', this.GETNEXTACT);
    return false;
}

ajaxEntity.prototype.getViewUserNextActivity = function(successCallback, errorCallback, uid) {
    tErr.setMethod("getViewUserNextActivity");
    var data = this.GETVIEWUSERNEXTACT + '&uid=' + uid;        
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'GET', data);
    return false;
}

/**
 *
 * @param aId int The answer id associated with the event.
 * @param sId int The schedule id answered.
 * @param successCallback function The callback function on sucess.
 * @param errorCallback function The callback function on error.
 */
ajaxEntity.prototype.saveEvent = function(aId, sId, successCallback, errorCallback) {
    tErr.setMethod("saveEvent");
    var data = this.SAVEEVENT + "&aid=" + aId + "&sid=" + sId;
    this.getServerData(this.RESOURCE, successCallback, errorCallback, "JSON", "POST", data);
    return false;
}

/**
 *
 * @param aId int The answer id selected.
 * @param sId int The schedule id answered.
 * @param successCallback function The callback function on sucess.
 * @param errorCallback function The callback function on error.
 */
ajaxEntity.prototype.saveQuestion = function(aId, sId, successCallback, errorCallback) {
    tErr.setMethod("saveQuestion");
    var data = this.SAVEQUESTION + "&aid=" + aId + "&sid=" + sId;
    this.getServerData(this.RESOURCE, successCallback, errorCallback, "JSON", "POST", data);
    return false;
}

/**
 *
 * @param rId int The report id.
 * @param sId int The schedule id answered.
 * @param successCallback function The callback function on sucess.
 * @param errorCallback function The callback function on error.
 */
ajaxEntity.prototype.saveReport = function(rId, sId, successCallback, errorCallback) {
    tErr.setMethod("saveReport");
    var data = this.SAVEREPORT + "&rid=" + rId + "&sid=" + sId;
    this.getServerData(this.RESOURCE, successCallback, errorCallback, "JSON", "POST", data);
    return false;
}

/**
 * Gets parameters need it to render the Entity Image
 * 
 * @param successCallback function Called on Success 
 * @param errorCallback   function Called on Error
 * @param uid             integer  Optional User Id
 */
ajaxEntity.prototype.entityImgDef = function(successCallback, errorCallback) {
    tErr.setMethod("entityImgDef");
    var params = this.GETENTITYIMG;
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'GET', params);
    return false;
}

ajaxEntity.prototype.entityViewUserImgDef = function(successCallback, errorCallback, uid) {
    tErr.setMethod("entityViewUserImgDef");
    var params = this.GETVIEWUSERENTITYIMG + '&uid=' + uid;    
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'GET', params);
    return false;
}


/**
 *  Method entityAgeVideos gets the appropriate videos for the age of the
 *  current entity.
 *
 * @param successCallback function The callback function on sucess.
 * @param errorCallback   function The callback function on error.
 * @param fakingAge       integer  Current age in the timeline.
 * @param uid             integer  User ID 
 */
ajaxEntity.prototype.entityAgeVideos = function(successCallback, errorCallback, fakingAge) {
    tErr.setMethod("entityAgeVideos");
    var data = this.GETVIDEOS;
    
    if (fakingAge != -1) {
        data += '&age=' + fakingAge;
    }
            
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'GET', data);
    return false;
}

ajaxEntity.prototype.entityViewUserAgeVideos = function(successCallback, errorCallback, fakingAge, uid) {
    tErr.setMethod("entityViewUserAgeVideos");
    var data = this.GETVIDEOS + '&uid=' + uid;
    
    if (fakingAge != -1) {
        data += '&age=' + fakingAge;
    }
            
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'GET', data);
    return false;
}

/**
 *  Method entityHistMoment gets a specific moment in the entity's history by
 *  the history id.
 *
 * @param hId             int      History (moment) id.
 * @param successCallback function Callback function on sucess.
 * @param errorCallback   function Callback function on error.
 * @param uid             integer  Optional User Id
 */
ajaxEntity.prototype.entityHistMoment = function(hid, successCallback, errorCallback, uid) {
    tErr.setMethod("entityHistMoment");
    hid = typeof(hid) != 'undefined' ? hid : 0;    
    var params = this.GETHISTMOMENT + '&hid=' + hid;    
    if ((typeof uid != 'undefined') && (uid != 0)) {
        params += '&uid=' + uid;
    }
        
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'GET', params);
    return false;
}

ajaxEntity.prototype.getHistVars = function(hid, successCallback, errorCallback) {
    tErr.setMethod("entityGetHistVar");

    var params = this.GETHISTVARS + '&hid=' + hid;

    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'GET', params);
    return false;
}

/**
 *  
 *
 * @param startAge int the starting age
 * @param endAge int The ending age (not included)
 * @param successCallback function The callback function on sucess.
 * @param errorCallback function The callback function on error.
 */
ajaxEntity.prototype.entityAgeRangeSchedule = function(startAge, endAge, successCallback, errorCallback) {
    tErr.setMethod("entityAgeRangeSchedule");
    
    var data = this.GETAGESCHEDULE + '&agestart=' + startAge + '&ageend=' + endAge;
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'GET', data);
    return false;
}

/**
 *
 * @param aId int The assignment id.
 * @param sId int The schedule id answered.
 * @param json of answers.
 * @param successCallback function The callback function on sucess.
 * @param errorCallback function The callback function on error.
 */
ajaxEntity.prototype.saveAssignment = function(aId, sId, answers, successCallback, errorCallback) {
    tErr.setMethod("saveAssigment");
    
    var data = this.SAVEASSIGN + "&aid=" + aId + "&sid=" + sId;

    for (var i in answers) {         
        var a = answers[i];
        data +=  '&' + a.name + '[' + a.id +']=' + a.value;
    }
            
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'POST', data);
    return false;
}


ajaxEntity.prototype.registrationInfo = {
    'tos': null,
    'classID': null,
    'gender': null,
    'race': null,
    'skintone': null,
    'eyecolor': null,
    'haircolor': null,
    'personality': null,
    'personalityTest': null,
    'cognitiveTest': null,
    'eGender': null,
    'name': null
};

ajaxEntity.prototype.getNeededRegistrationInfo = function() {
    for (var field in this.registrationInfo) {
        if (this.registrationInfo[field] === null) {
            return field;
        }
    }
    return 'completed';
}


ajaxEntity.prototype.traitAPICalls = {
        race: 'getraces',
        skintone: 'getskintones',
        eyecolor: 'geteyecolors',
        haircolor: 'gethaircolors',
        personality: 'getpersonalitytype',
        personalityTest: 'getmptest',
        cognitiveTest: 'getcatest'
    };

ajaxEntity.prototype.getTraitOptions =  function(type, successCallback, errorCallback){

    var data = {cmd:this.traitAPICalls[type]};
    

    // This can be changed to be more dynamic if needed
    if (type == 'skintone' || type == 'eyecolor' || type == 'haircolor') {
        data.race = this.registrationInfo.race;
    }
    $.ajax({
        url: this.RESOURCE,
        type: 'GET',
        dataType: 'json',
        data: data,
        success: function(json) {
                successCallback(json, type);
        },
        error: function(a,b,c) {
                errorCallback(a, b, c);
        }
    });
    
}

ajaxEntity.prototype.saveNewRegistration = function() {
    tErr.setMethod("saveNewRegistration");
    var entity = this;

    var serverData = {
        cmd: 'saveassessment',
        name: entity.registrationInfo.name,
        race: entity.registrationInfo.race,
        ec: entity.registrationInfo.eyecolor,
        st: entity.registrationInfo.skintone,
        hc: entity.registrationInfo.haircolor,
        pt: entity.registrationInfo.personality,
        egender: entity.registrationInfo.eGender,
        sgender: entity.registrationInfo.gender,
        pgender: entity.registrationInfo.partner_gender
    };
    if (entity.registrationInfo.classID != 'none') {
        serverData.cid = entity.registrationInfo.classID;
    }

    for (var answer in entity.registrationInfo.personalityTest) {
        serverData[answer] = entity.registrationInfo.personalityTest[answer];
    }
    for (var answer in entity.registrationInfo.cognitiveTest) {
        serverData[answer] = entity.registrationInfo.cognitiveTest[answer];
    }

    // Now that we have all the data, save it
    entity.getServerData(this.RESOURCE, newRegistrationSaveSuccess, newRegistrationSaveFailure, 'json', 'POST', serverData)
    
}


/**
 * @param courseId The new course id
 * @param successCallback function The callback function on sucess.
 * @param errorCallback function The callback function on error.
 */
ajaxEntity.prototype.changeCourseId = function(courseId, successCallback, errorCallback) {
    tErr.setMethod("changeCourseId");
    var data = this.CHANGECOURSEID + "&courseid=" + courseId;
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'POST', data);
    return false;
}

ajaxEntity.prototype.isValidCourseId = function(courseId, successCallback, errorCallback) {
    tErr.setMethod("isValidCourseId");
    var data = this.ISVALIDCOURSEID + "&courseid=" + courseId;
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'POST', data);
    return false;
}


/**
 * @param successCallback function The callback function on sucess.
 * @param errorCallback function The callback function on error.
 */
ajaxEntity.prototype.unassignCourse = function(successCallback, errorCallback) {
    tErr.setMethod("unassignCourse");
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'POST', this.UNASSIGNCOURSE);
    return false;
}

/**
 * @param successCallback function The callback function on sucess.
 * @param errorCallback function The callback function on error.
 */
ajaxEntity.prototype.resetInstructorEntity = function(successCallback, errorCallback) {
    tErr.setMethod('resetInstructorEntity');
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'POST', this.RESETINSTRUCTORENTITY, false);
    return false;
}

/**
 * @param entityId        integer   Entity Id to reset
 * @param successCallback function The callback function on sucess.
 * @param errorCallback   function The callback function on error.
 */
ajaxEntity.prototype.resetStudentEntity = function(uId, successCallback, errorCallback) {
    tErr.setMethod('resetStudentEntity');
    var data = this.RESETSTUDENTENTITY + '&uid=' + uId;
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'POST', data, false);
    return false;
}

/**
 * @param id
 * @param successCallback function The callback function on sucess.
 * @param errorCallback function The callback function on error.
 */
ajaxEntity.prototype.setViewUser = function(uid, successCallback, errorCallback) {
    tErr.setMethod("setViewUser");
    var data = this.SETVIEWUSER + '&uid=' + uid;    
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'POST', data);
    return false;
}


ajaxEntity.prototype.getViewUser = function(successCallback, errorCallback) {
    tErr.setMethod("getViewUser");
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'GET', this.GETVIEWUSER, false);
    return false;
}

/**
 * Get the assignments list for a user previous set with setViewUser
 * @param successCallback function Callback for success
 * @param errorCallback function Callback for error
 */
ajaxEntity.prototype.getAssignments = function(successCallback, errorCallback) {
    tErr.setMethod("getAssignments");
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'GET', 'cmd=getassignments', false);
}

/**
 * Get the feedback for a student
 * @param sID int The student id
 * @param successCallback function Callback for success
 * @param errorCallback function Callback for error
 */
ajaxEntity.prototype.getFeedback = function(sID, successCallback, errorCallback) {
    tErr.setMethod("getAssignments");
    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'GET', 'cmd=getfeedback&sid=' + sID, false);
}

/**
 *
 * @param varName string The variable name to set
 * @param varValue string/int The variable data
 * @param varType string "number" or "text" - The type of value provided.
 * @param successCallback function callback for success
 * @param errorCallback function callback for error
 */
ajaxEntity.prototype.setVariable = function(varName, varValue, varType, successCallback, errorCallback) {
    tErr.setMethod("setVariable");
    var tdata = this.SAVEVARIABLE;
    tdata += "&val=" + encodeURIComponent(varValue) + "&var=" + varName + "&vartype=" + varType;

    this.getServerData(this.RESOURCE, successCallback, errorCallback, 'JSON', 'POST', tdata, false);
}
