/**
 * Page
 * @author Jae Cho
 * This is a parent class to all of the page objects. Each page will subclass
 * from this class and add concrete implementations.
 * This class acts as the central controller to modules that are included in
 * a page.
 *
 * Note that this class should be exnteded directly by it's implementation.
 * Because of JavaScripts inheritance-mimicing via prototype, the following
 * model does not work very well: Page extended by BasePage, BasePage extended by ProfilePage.
 * it's very tricky to have class ProfilePage work properly with all attributes of Page
 *
 * @dependencies StringUtil
 *
 */
function Page() {

  /** request parameter that contains the page action */
    this.REQ_PARAM_PAGE_ACTION = "pageAction";

    /** set up URL to use for the service */
    this._DEF_AJAX_PATH = "/dynamic/xservices";

    /** action that should be taken when page is loaded
     * for example, displaying login dialog as soon as page is completely loaded
     */
    this.pageAction = null;

    /** map of response object types and array of modules that can handle it */
    this.resModuleMap = new Object();

    /** map of action parameter to array of modules that can handle it
    * The handlePageAction() method of module is called if pageAction is present in request*/
    this._actionModuleMap = new Object();

    /** map of request parameters - all values are string */
    this.reqParams = null;

    this._curReqId = 0;

    /** parameter for required login*/
    this._loginRequired = false;

    /** map of ajax path to list of requests
     * The page can take in a list of parameters to different ajax paths.
     * page will separate the list by the ajax paths and make separater requests
     */
    this._ajaxPathToReqs = new Object();

    /** callback method for ajax response */
    this._ajaxResHandler = null;

    /** map of module name to module - used for testing */
    this.modules = new Object();

    this.moduleReqInfos = new Array();

    /** error module */
    this.errorModule = new ErrorModule();

    /** initialize with configuration.
     * THIS HAS TO BE CALLED BEFORE ANY OTHER METHOD IS CALLED
     */
    this.init = function()
    {
        // create handler for call back
        this._ajaxResHandler = bindContext(this, this._handleResObjects);

        for (var moduleName in this.modules) {
            this.modules[moduleName].initialize();
        }

        this.reqParams = StringUtil.getQueryParams(window.location.search);
        this.pageAction = this.reqParams[this.REQ_PARAM_PAGE_ACTION];

        this.errorModule.initialize();
        this.handlePageAction();
        this.makeInitAjaxCall();

    };

    /** register request for a module */
    this._registerModuleReq = function(module, requests)
    {
        var modReqInfo = new Object();
        modReqInfo.module = module;
        modReqInfo.reqIds = new Array();

        for (var i = 0; requests && i < requests.length; i++) {
            var req = requests[i];
            req.id = this._curReqId;

            var ajaxPath = this._DEF_AJAX_PATH;
            if (req.ajaxPath) {
                var ajaxPath = req.ajaxPath;
                delete(req.ajaxPath);
            }

            if (!this._ajaxPathToReqs[ajaxPath])this._ajaxPathToReqs[ajaxPath] = new Array();

            this._ajaxPathToReqs[ajaxPath].push(req);

            modReqInfo.reqIds.push(this._curReqId);
            this._curReqId++;
        }

        this.moduleReqInfos.push(modReqInfo);
    };

    /**
     * register a module with this page
     * @param module
     */
    this.registerModule = function(module)
    {
        this.modules[module.getName()] = module;
        module.setPage(this);

        // add the module to the request action to module map
        var reqActionNames = module.getPageActionNames();
        for (var i = 0; reqActionNames && i < reqActionNames.length; i++) {
            var reqActionName = reqActionNames[i];
            if (this._actionModuleMap[reqActionName] == null) {
                this._actionModuleMap[reqActionName] = new Array();
            }
            var actionModules = this._actionModuleMap[reqActionName];
            actionModules[actionModules.length] = module;
        }
    };

    /**
     * callback method for handling ajax response from the server
     * @param responseListStr
     */
    this._handleResObjects = function(responseListStr)
    {
        responseListStr = responseListStr.replace(/\n/g, "");

        var responseList = eval("(" + responseListStr + ")");
        responseList = responseList["response-array"];

        // if response is not object, it's an error
        if (!responseList) {
            this.errorModule.addError(responseListStr);
        }

        // construct a map of request ID to response object
        var resObjectMap = new Object();

        for (var i = 0; i < responseList.length; i++) {

            var curResponse = responseList[i];

            if (curResponse.returnCode == "Error") {
                this.errorModule.addError(curResponse.errorMessage);
            } else {
                resObjectMap[curResponse.id] = curResponse;
            }
        }

        // iterate through modules and pass in response objects
        for (i = 0; i < this.moduleReqInfos.length; i++) {
            var moduleReqInfo = this.moduleReqInfos[i];
            var moduleResArray = new Array();
            for (var j = 0; j < moduleReqInfo.reqIds.length; j++) {
                var res = resObjectMap[moduleReqInfo.reqIds[j]];
                if (res) moduleResArray.push(res);
            }
            if (moduleResArray.length > 0) {
                moduleReqInfo.comleted = true;
                moduleReqInfo.module.handleResObjects(moduleResArray);
            }
        }

        this.errorModule.showErrors();
    };


    /** make AJAX call from a module */
    this.makeModuleAjaxCall = function(module, requests) {
        this._registerModuleReq(module, requests);
        this._makeAjaxCall();
    };

    /**
     * make initial AJAX call when the page loads
     */
    this.makeInitAjaxCall = function() {
      if (this._loginRequired && !this.getLoggedInUserUuid()){
            ag.widget.user.LoginPopup.showPopup();
        }else{
            for (var i in this.modules) {
                var module = this.modules[i];

                // set initial AJAX request
                var initReqs = module.getInitRequests();

                // register initialize
                if (initReqs && initReqs.length > 0) this._registerModuleReq(module, initReqs);
            }

            this._makeAjaxCall();
        }
    };

    /**
     * make AJAX call when the login state changes.
     */
    this.updateForLoginChange = function() {

        for (var i in this.modules) {
            var module = this.modules[i];

            // set initial AJAX request
            var reqs = module.updateAndGetLoginChangeRequests();

            // register initialize
            if (reqs && reqs.length > 0) this._registerModuleReq(module, reqs);
        }
        this._makeAjaxCall();
    };

    /** @return module with corresponding name */
    this.getModule = function(moduleName) {
        return this.modules[moduleName];
    };

    /** return array of modules that can handle this response */
    this.getModulesForResName = function(resName) {
        return this.resModuleMap[resName];
    };

    /** return an array of modules that can handle request action */
    this._getModulesForPageAction = function(actionName) {
        return this._actionModuleMap[actionName];
    };

    /** handle page request */
    this.handlePageAction = function() {
        if (this.pageAction != null) {
            var moduleList = this._getModulesForPageAction(this.pageAction);

            if (!moduleList) return;

            for (var i = 0; i < moduleList.length; i++) {
                var module = moduleList[i];
                module.handlePageAction(this.pageAction, this.reqParams);
            }
        }
    };

    /** make AJAX call */
    this._makeAjaxCall = function()
    {
        if (!this._ajaxPathToReqs) return;

        for (var ajaxPath in this._ajaxPathToReqs)
        {
            // serialize the command into string
            var stringCommand = JSON.stringify(
                { "request-array" : { request : this._ajaxPathToReqs[ajaxPath] }});

            // make actual call
            $.ajax({
               url: ajaxPath,
               type: 'POST',
               data: stringCommand,
               dataType: 'text',
               success: this._ajaxResHandler
           });
        }

        // empty module request so that we don't send duplicate request
        // we can't set this to null since JS doesn't let you modify value of a prototype
        this._ajaxPathToReqs = new Object();
    };

    /** @return user id of the logged in user. null if not logged in */
    this.getLoggedInUserId = function() {
        var cookieUtil = new CookieUtil();
        var userId = cookieUtil.readCookie("aguseridsc");
        userId = parseInt(userId);
        return userId;
    };

    /** @return user uuid of the logged in user. null if not logged in */
    this.getLoggedInUserUuid = function() {
        var cookieUtil = new CookieUtil();
        var uuid = cookieUtil.readCookie("aguseruuidsc");
        return uuid;
    };

    this.setLoginRequired = function (){
        this._loginRequired = true;
    };

    this.getLoginRequired = function (){
        return this._loginRequired;
    };

    /** open error dialog */
    this.displayError = function(error, redirectPath) {
        if (redirectPath) this.errorModule.setRedirectPath(redirectPath);
        this.errorModule.addError(error);
        this.errorModule.showErrors();
    };

    
    var loginRedirectModule = new LoginRedirectModule();
    this.registerModule(loginRedirectModule);

}
