﻿if (cs==undefined||cs.forms==undefined)
    alert("Missing cs.forms library.");
else
{

    // Definition of generic module handlers
    cs.forms.ModuleHandlers_103 = function(){};
    cs.forms.ModuleHandlers_103.prototype["loginrequired"] = function(context, res){
        if (context.btncontrols!=undefined)
        {
            for (var i=0; i<context.btncontrols.length; i++)
            {
                context.btncontrols[i].setState("normal", true);
            }
        }

        if (context.msgcontrols!=undefined)
        {
            for (var i=0; i<context.msgcontrols.length; i++)
            {
                if (context.msgcontrols[i].setValue!=undefined)
                {
                    context.msgcontrols[i].setValue(res.ResponseBody.Message);
                }
            }
        }

    };
        
    cs.forms.ModuleHandlers_200 = function(){};
    cs.forms.ModuleHandlers_200.prototype["any"] = function(context, res){

        if (context.btncontrols!=undefined)
        {
            for (var i=0; i<context.btncontrols.length; i++)
            {
                context.btncontrols[i].setState("normal", true);
            }
        }
        
        if (context.msgcontrols!=undefined)
        {
            for (var i=0; i<context.msgcontrols.length; i++)
            {
                if (context.msgcontrols[i].setValue!=undefined)
                {
                    context.msgcontrols[i].setValue("Unknown Response Action:" + res.ResponseAction);
                }
            }
        }

        context.module.showMessageBox({type:"alert", message:"Unknown Response Action:" + res.ResponseAction, showduration:1000});
        
    };
    
    /*
    ---------------------------------
        Authentication Handler
    ---------------------------------
    */
    cs.forms.ModuleHandlers_200.prototype["invalidsession"] = function(context, res){
        
        // Indicate that session is required
        
        // Try to create a reply of the call after getting the session
        if (context.acompleteevent==undefined)
            context.acompleteevent = new Array();
        
        var postModule = context.postModule;
        var postCommand = context.postCommand;
        var postData = context.postData;
        
        context.acompleteevent.push(function(){
            ScoutServer.CallServer(postModule, postCommand, postData, context);
        });
        
        ScoutServer.CallServer("authentication", "getsession", {action:"getsession"}, context);
        
        cs.forms.Common.bulksetControl(context.btncontrols, "setState", "normal", true);
        cs.forms.Common.bulksetControl(context.msgcontrols, "setValue", res.ResponseBody.Message);
        
    };
    
    cs.forms.ModuleHandlers_200.prototype["newsession"] = function(context, res){
        
        // Set the SessionID for this instance of server
        ScoutServer.setSessionID(res.ResponseBody.Message);
        
        // Check and execute the attached event chain
        if (context.acompleteevent!=undefined)
        {
            while (context.acompleteevent.length > 0)
            {
                var completeevent = context.acompleteevent.pop();
                if (completeevent.constructor == Function)
                    completeevent();
            }
        }
    };
    
    cs.forms.ModuleHandlers_200.prototype["authsuccess"] = function(context, res){
    
        
        // Retrieve the ticket from the response and set it to the Server Instance
        ScoutServer.setAjaxAuthCode(res.ResponseBody.authresult.authkey);
        
        // Store the Login ID to local cookie for 1000 hours
        cs.common.Document.setCookie("lastloginid", context.postData.username, 1000);
        
        // Store the authentication key for this session only
        cs.common.Document.setCookie("authkey", res.ResponseBody.authresult.authkey);
        
        cs.forms.Common.bulksetControl(context.btncontrols, "setState", "normal", true);
        cs.forms.Common.bulksetControl(context.msgcontrols, "setValue", res.ResponseBody.authresult.message);
        
        // Close the login window once authentication had finished
        if (window.global_awindowform!=undefined)
        {
            while (window.global_awindowform.length>0)
            {
                window.global_awindowform[0].destroy();
            }
        }        
        
        // Show a overlay and display the login successfully message
        context.module.showMessageBox({type:"flash", message:res.ResponseBody.authresult.message, flashduration:1000});
        
        // TODO: Check the pipeline for processing
        // Unable to execute pipeline before the modules finished loading
        // Thus, just display a message for now
        var aPipeline = cs.common.Array.createArrayFromEntry(res.ResponseBody.authresult.pipeline);
        for (var i=0; i<aPipeline.length; i++)
        {
            context.module.showMessageBox({type:"flash", message:aPipeline[i].name});
        }
        
        if (window.loadingmodule==undefined)
            window.loadingmodule = new Array();
        
        // Iterate thru the module list return by the server and load them appropriately
        var aModule = cs.common.Array.createArrayFromEntry(res.ResponseBody.authresult.module);
        for (var i=0; i<aModule.length; i++)
        {
            window.loadingmodule.push(aModule[i].name);
            cs.loadJS(aModule[i].url);
        }

        // Set a thread to monitor the loading of js modules
        // Populate the menu only when all the js modules loaded finish
        var thread = {};
        thread.id = setInterval(function(){
            if (window.loadingmodule.length==0)
            {
                clearInterval(thread.id);
                populateMenu();
            }
        }, 100);

        // Check and execute the attached event chain
        if (context.acompleteevent!=undefined)
        {
            while (context.acompleteevent.length > 0)
            {
                var completeevent = context.acompleteevent.pop();
                if (completeevent.constructor == Function)
                    completeevent();
            }
        }
                
    };
    
    /*
    ---------------------------------
        Other Generic Handler
    ---------------------------------
    */
    cs.forms.ModuleHandlers_200.prototype["compositeresult"] = function(context, res){
        
        var aResponsePacket = cs.common.Array.createArrayFromEntry(res.ListOfResponsePacket.ResponsePacket);
        for (var i=0; i<aResponsePacket.length; i++)
        {
            var resEntry = aResponsePacket[i];
            context.module.handler.default_handler(context, resEntry);
        }
    };

    cs.forms.ModuleHandlers_200.prototype["openmodule"] = function(context, res){
        
        var minfo = res.ResponseBody.module;
        global_module[minfo.guid].service[minfo.itemno].ActionFunction();
        
    };
        
    cs.forms.ModuleHandlers_200.prototype["displayexit"] = function(context, res){
        
        var mod = new global_module["$mguid$"]();
        var eleOverlayDIV = mod.createOverlayMask();
        
        // Show the message
        
        
    };
    
    cs.forms.ModuleHandlers_200.prototype["display"] = function(context, res){

        cs.forms.Common.bulksetControl(context.btncontrols, "setState", "normal", true);
        cs.forms.Common.bulksetControl(context.msgcontrols, "setValue", res.ResponseBody.Message);
        
        if (context.msgcontrols==undefined)
        {
            // TODO: Temporarily alert the message to the user
            alert(res.ResponseBody.Message);
        }
        
    };

    cs.forms.ModuleHandlers_200.prototype["alertandclose"] = function(context, res){
        
        cs.forms.Common.bulksetControl(context.btncontrols, "setState", "normal", true);
        cs.forms.Common.bulksetControl(context.msgcontrols, "setValue", res.ResponseBody.Message);

        alert(res.ResponseBody.Message);
        context.module.windowform.close();
        
    };
    
    cs.forms.ModuleHandlers_200.prototype["confirmation"] = function(context, res){
    
        // Error Checking
        if (context.module.tpt.confirmation==undefined)
        {
            cs.debugalert("Confirmation Template is missing.");
            return;
        }
        
        // Create a floating DIV and show the confirmation
        var eleNewFloat = window.document.createElement("DIV");
        eleNewFloat.style.position="absolute";

        // Position this to the middle of the screen
        eleNewFloat.style.left=(parseInt(document.body.offsetWidth)/2 - 200) + "px";
        eleNewFloat.style.top=(parseInt(document.body.offsetHeight)/4) + "px";
        eleNewFloat.style.display="inline";
        window.document.body.appendChild(eleNewFloat);

        // Transform response to bo for binding
        var bo = {};

        var resBody = res.ResponseBody;
        for (eleName in resBody)
        {
            if (eleName[0]!="#")
            {
                bo[eleName] = new cs.forms.Span();
                bo[eleName].setValue(resBody[eleName]);
            }
        }
        bo["btnConfirm"] = new cs.forms.Button({onclick: function(){
                                                    context.module.clientaction.confirm({module: context.module, jsonData: resBody});
                                                    window.document.body.removeChild(eleNewFloat);
                                                },
                                                defaultvalue: "Confirm"});

        // RootForm is hardcoded and fixed, see if there's a way to workaround this.
        var opt = {bindingParent:{RootForm: bo}, populatingData:true};
        var boForm = pc.appendJCSDOMtoJSDOM(context.module.tpt.confirmation, eleNewFloat, opt);
    };
    
    /*
    ----------------------------------------------
        All the action results from the server
    ----------------------------------------------
    */
    cs.forms.ModuleHandlers_200.prototype["updateresult"] = function(context, res){
        // Result return by a Update call
        /*
            ResponseBody
            .Message = Message to display to user.
        */
        cs.forms.Common.bulksetControl(context.btncontrols, "setState", "normal", true);
        cs.forms.Common.bulksetControl(context.msgcontrols, "setValue", res.ResponseBody.Message);
    };
    
    cs.forms.ModuleHandlers_200.prototype["searchresult"] = function(context, res){
        
        cs.forms.Common.bulksetControl(context.btncontrols, "setState", "normal", true);
        cs.forms.Common.bulksetControl(context.msgcontrols, "setValue", "Populating result...");
        
        var wResult = cs.common.Window.CreateWindow({title:"Search Result"});
        //alert(res.ResponseBody);
        //alert(cs.Debug.inspect(res.ResponseBody.Message, {depth:4}).join(""));
        //wResult.contentdiv.innerHTML = "<pre>" + res.ResponseBody.Message.replace(/\</gi, "&lt;") + "</pre>";

        var xmlDoc = XML.parse(res.ResponseBody.Message);
        
        // Look for the summary node
        var xmlSummaryNodes = XML.selectNodes(xmlDoc, "DataSet/diffgr:diffgram/ResultDataSet/Summary");
            
        if (xmlSummaryNodes.length==0)
        {
            cs.forms.Common.bulksetControl(context.msgcontrols, "setValue", "Error in retrieving result.");
        }
        else
        {
            var jsonSummaryList = XML.XMLNodeArraytoJSONArray(xmlSummaryNodes);
            if (jsonSummaryList == undefined)
            {
                cs.forms.Common.bulksetControl(context.msgcontrols, "setValue", "Error in parsing result from server.");
            }
            else
            {
                // TODO: current only pick up the first summary entry
                var jsonSummary = jsonSummaryList[0];
                cs.forms.Common.bulksetControl(context.msgcontrols, "setValue", jsonSummary.Comment);

                // Check if there's specific format
                var strPresentationTable = jsonSummary.PresentationTables.split(",")[0];
                var strDataTable = jsonSummary.DataTable;
                
                var xmlSearchResultFormatNodes = XML.selectNodes(xmlDoc, "DataSet/diffgr:diffgram/ResultDataSet/" + strPresentationTable);
                var ajsonSearchResultFormat = XML.XMLNodeArraytoJSONArray(xmlSearchResultFormatNodes);
                
                var xmlBulkActionNodes = XML.selectNodes(xmlDoc, "DataSet/diffgr:diffgram/ResultDataSet/BulkAction");
                var ajsonBulkAction = XML.XMLNodeArraytoJSONArray(xmlBulkActionNodes);

                var xmlSearchResultNodes = XML.selectNodes(xmlDoc, "DataSet/diffgr:diffgram/ResultDataSet/" + strDataTable);
                if (xmlSearchResultNodes!=undefined)
                {
                    var jsonResult = XML.XMLNodeArraytoJSONArray(xmlSearchResultNodes);

                    // Array of element of items (checkboxes)
                    /*
                    var eleItemArray = new Array();
                    */
                    
                    var tmpModule = new cs.forms.ModuleBase(context.module.servermoduleid, context.module.servermodulename);
                    
                    // for 200 ok result:
                    tmpModule.handlers[200]["removeresult"] = function(context, res){
                            // get the row bo and the row id from the context and delete it
                            context.localref.row.removeDOM();
                            context.module.bo.ResultRow.removeFormByIndex(context.localref.rowindex);
                        };
                        
                    // for 250 ok with attention result:
                    if (tmpModule.handlers[250]==undefined)
                        tmpModule.handlers[250] = {};
                        
                    tmpModule.handlers[250]["removeresult"] = function(context, res){
                            context.localref.row.highlightDOM("#FFDDDD");
                            var cbxTick = context.localref.row.getElementByName("selection");
                            cbxTick.setValue(false);
                            cbxTick.setEnable(false);
                            // TODO: Need to remove all the single actions that is associated with this item too.
                            alert(res.ResponseBody.Message);
                        };
                        
                    var jcsdomResultTable = {tag:"table", html:[]};
                    tmpModule.tpt = {result:jcsdomResultTable};
                    tmpModule.bo = {};
                    
                    /*
                    --------------------------------------------
                        Populate the Bulk Action Buttons
                    --------------------------------------------
                    */
                    var jcsdomBulkActionRow = {tag:"tr"};
                    var jcsdomBulkActionTD = {tag:"td", colspan:ajsonSearchResultFormat.length + 1, html:[]};
                    jcsdomBulkActionRow.html = [jcsdomBulkActionTD];
                    jcsdomResultTable.html.push(jcsdomBulkActionRow);
                    
                    for (var intBulkAction=0; intBulkAction<ajsonBulkAction.length; intBulkAction++)
                    {
                        var jsonBulkAction = ajsonBulkAction[intBulkAction];
                        if (jsonBulkAction.RefPresentationTable==strPresentationTable)
                        {
                            var intBulkActionCopy = intBulkAction;
                            
                            // This is a fake return value because it is a Bulk Action
                            // thus it needs access to the Module object itself
                            // so that changes can be made to the UI as well.
                            var funcCollectSelectedParam = function() {
                                return {module:tmpModule, action:jsonBulkAction.Action};
                            };
                            
                            // Attach event handler to the button
                            var objButtonArg = {defaultvalue: ajsonBulkAction[intBulkAction].Label,
                                             statevalue: {click:"Submitting...", wait:"Processing..."}};
                            objButtonArg.onclick = cs.CreateFunctionCallBack(tmpModule.clientaction[jsonBulkAction.Action],
                                                                 funcCollectSelectedParam);
                                             
                            var btnBulkAction = new cs.forms.Button(objButtonArg);
                            
                            tmpModule.bo[ajsonBulkAction[intBulkAction].Action] = btnBulkAction;
                            
                            // Add to the template also
                            jcsdomBulkActionTD.html.push(new cs.forms.FormTemplateItem("MainResult",ajsonBulkAction[intBulkAction].Action));
                        }
                    }
                    
                    // Prepare the table header
                    var jcsdomResultHeader = {tag:"tr", html:[]};
                    jcsdomResultTable.html.push(jcsdomResultHeader);
                    
                    // Inject the checkbox if there is bulk action
                    if (ajsonBulkAction.length>0)
                    {
                        jcsdomResultHeader.html.push({tag:"th", html:new cs.forms.FormTemplateItem("MainResult","SelectAllCheckBox")});
                    }
                    
                    for (var i=0; i<ajsonSearchResultFormat.length; i++)
                    {
                        var jcsdomResultGridHeader = {tag:"th"};
                        jcsdomResultGridHeader.html = ajsonSearchResultFormat[i].ColumnLabel;
                        jcsdomResultHeader.html.push(jcsdomResultGridHeader);
                    }
                    
                    // The result listing items

                    // Formulate the item template here
                    var jcsdomItemRowTemplate = {tag:"tr", html:[]};
                    if (ajsonBulkAction.length>0)
                    {
                        jcsdomItemRowTemplate.html.push({tag:"td", html:new cs.forms.FormTemplateItem("ResultRow","selection")});
                    }

                    for (var iCol=0; iCol<ajsonSearchResultFormat.length; iCol++)
                    {
                        var jsonSearchResultFormatItem = ajsonSearchResultFormat[iCol];
                        var jcsdomItemCell = {tag:"td", html:new cs.forms.FormTemplateItem("ResultRow","Col"+iCol)};
                        jcsdomItemRowTemplate.html.push(jcsdomItemCell);
                    }
                    
                    jcsdomResultTable.html.push(new cs.forms.FormTemplateItem("MainResult","ResultRow","ResultRow",jcsdomItemRowTemplate));
                    
                    // Formulate the Business Object
                    
                    // Need to create a form bo model first
                    var boItemModel = {};
                    
                    // Add in the checkbox for the model
                    if (ajsonBulkAction.length>0)
                    {
                        boItemModel["selection"] = new cs.forms.CheckBox({
                            onChange : function(){
                                    tmpModule.bo["SelectAllCheckBox"].setValue(false);
                                }
                            });
                        tmpModule.bo["SelectAllCheckBox"] = new cs.forms.CheckBox({
                            onChange : function(){
                                    var intFormCount = tmpModule.bo["ResultRow"].getFormCount();
                                    for (var intFormIndex=0; intFormIndex<intFormCount; intFormIndex++)
                                    {
                                        tmpModule.bo["ResultRow"].getForm(intFormIndex).getElementByName("selection").setValue(this.checked);
                                    }
                                }
                            });
                    }
                    
                    for (var iCol=0; iCol<ajsonSearchResultFormat.length; iCol++)
                    {
                        boItemModel["Col"+iCol] = new cs.forms.Anchor();
                    }
                    
                    for (var intBulkAction=0; intBulkAction<ajsonBulkAction.length; intBulkAction++)
                    {
                        boItemModel["BulkAction_" + ajsonBulkAction[intBulkAction].Action] = new cs.forms.JSHiddenField();
                    }
                    
                    tmpModule.bo.ResultRow = new cs.forms.FormArray(boItemModel);
                    
                    for (var intItemNo=0; intItemNo<jsonResult.length; intItemNo++)
                    {
                        // Item Row
                        var boItem = tmpModule.bo.ResultRow.addNew();
                        
                        // Bulk Action Setting of Action Parameter Value
                        for (var intBulkAction=0; intBulkAction<ajsonBulkAction.length; intBulkAction++)
                        {
                            var jsonBulkActionItem = ajsonBulkAction[intBulkAction];
                            
                            if (jsonBulkActionItem.RefPresentationTable==strPresentationTable)
                            {
                                // Check the bulk action param fields
                                var jsonBulkActionParamValue = {};
                                var astrBulkActionParamName = jsonBulkActionItem.ActionParamFields.split(",");
                                
                                for (var intActParam=0; intActParam<astrBulkActionParamName.length; intActParam++)
                                    jsonBulkActionParamValue[astrBulkActionParamName[intActParam]]=jsonResult[intItemNo][astrBulkActionParamName[intActParam]];
                                
                                boItem.getElementByName("BulkAction_" + jsonBulkActionItem.Action).setValue(jsonBulkActionParamValue);
                            }
                        };
                        
                        
                        // Interpreting the Result Grid
                        for (var iCol=0; iCol<ajsonSearchResultFormat.length; iCol++)
                        {
                            var jsonSearchResultFormatItem = ajsonSearchResultFormat[iCol];
                            
                            var strParamValueArray = new Array();
                            var strParamNameArray = jsonSearchResultFormatItem.DisplayParamFields.split(",");
                            
                            for (var intParamIndex=0; intParamIndex < strParamNameArray.length; intParamIndex++)
                                strParamValueArray.push(jsonResult[intItemNo][strParamNameArray[intParamIndex]]);
                                
                            var astrHintValueArray = new Array();
                            var astrHintNameArray = jsonSearchResultFormatItem.HintParamFields.split(",");
                            
                            for (var intHintParamIndex=0; intHintParamIndex < astrHintNameArray.length; intHintParamIndex++)
                                astrHintValueArray.push(jsonResult[intItemNo][astrHintNameArray[intHintParamIndex]]);
                            
                            var strValue = cs.formatString(jsonSearchResultFormatItem.ColumnFormatString, strParamValueArray);
                            
                            /*
                            -------------------------------------------
                                 Single Item Action for Record Row
                            -------------------------------------------
                            */

                            if (jsonSearchResultFormatItem.SingleItemAction!=undefined && 
                                jsonSearchResultFormatItem.SingleItemAction!="")
                            {
                                var boItemCurrent = boItem.getElementByName("Col"+iCol);
                                boItemCurrent.setValue(strValue);
                                
                                var astrActionParamValue = new Array();
                                var astrActionParamName = jsonSearchResultFormatItem.ActionParamFields.split(",");
                                
                                for (var intActParam=0; intActParam<astrActionParamName.length; intActParam++)
                                    astrActionParamValue.push(jsonResult[intItemNo][astrActionParamName[intActParam]]);
                                    
                                // Extract the CustomData from jsonSearchResultFormatItem
                                //cs.debugalert(cs.Debug.inspect(jsonSearchResultFormatItem.SingleItemActionCustomData).join(""));
                                
                                var xmlCustomData = XML.parse(jsonSearchResultFormatItem.SingleItemActionCustomData);
                                
                                var ajsonCustomData = XML.XMLNodetoJSON(xmlCustomData);
                                //cs.debugalert(cs.Debug.inspect(ajsonCustomData, {depth:2}).join(""));
                                
                                var customData = {};
                                customData.edititemconfig = ajsonCustomData;
//                                        customData.edititemconfig.editortemplate = ajsonCustomData.editortemplate;
//                                        customData.edititemconfig.bo = ajsonCustomData.bo;
//                                        customData.edititemconfig.bo = {
//                                            Category : new cs.forms.TextBox({width:"100px"}),
//                                            Identifier : new cs.forms.TextBox({width:"100px"}),
//                                            StringContent : new cs.forms.TextArea({width:"200px"})
//                                        };

                                var strHint = cs.formatString(jsonSearchResultFormatItem.HintFormatString, astrHintValueArray);
                                
                                // look up the global module for the function to be called and pass in the parameters
                                if (tmpModule.clientaction[jsonSearchResultFormatItem.SingleItemAction]!=undefined)
                                {
                                    boItemCurrent.setHref("hint: " + strHint);
                                    var funcCallBack = cs.CreateFunctionCallBack(
                                                            tmpModule.clientaction[jsonSearchResultFormatItem.SingleItemAction],
                                                            {module:tmpModule, adata:astrActionParamValue, customdata:customData});
                                                                         
                                    var funcWrap = cs.CreateFunctionReturnFalse(funcCallBack);
                                    boItemCurrent.setOnClick(funcWrap);
                                }
                                else
                                {
                                    boItemCurrent.setHref("hint: " + strHint);
                                    boItemCurrent.setOnClick(function(){cs.debugalert("this function is missing.");return false;});
                                }
                                                                      
                            }
                            else
                            {
                                boItem.getElementByName("Col"+iCol).setValue(strValue);
                            }
                        }
                    }

                    // Bind the result in!
                    tmpModule.tpt.result = new cs.forms.FormTemplate("MainResult", tmpModule.tpt.result);
                    var tptForm = {MainResult: tmpModule.bo};
                    var opt = {bindingParent: tptForm, populatingData:true};
                    var boForm = pc.appendJCSDOMtoJSDOM(tmpModule.tpt.result, wResult.contentdiv, opt);
                }
            }
        }
        
    };

    /* -----------------------
        500 Series
    -------------------------*/
    cs.forms.ModuleHandlers_500 = function(){};
    cs.forms.ModuleHandlers_500.prototype["any"] = function(context, res){
        
        cs.forms.Common.bulksetControl(context.btncontrols, "setState", "normal", true);
        cs.forms.Common.bulksetControl(context.msgcontrols, "setValue", res.ResponseBody.Message);
        alert("Some error occured, please try to re-submit your request again.");

    };
    
    cs.forms.ModuleHandlers = function(){
    
        this[103] = new cs.forms.ModuleHandlers_103();
        this[200] = new cs.forms.ModuleHandlers_200();
        this[500] = new cs.forms.ModuleHandlers_500();
        
    };
    
    // Modulebase class

    cs.forms.ModuleBase = function(){
    
        if (arguments.length > 1)
        {
            this.servermoduleid = arguments[0];
            this.servermodulename = arguments[1];
        }
        
        this.handlers = new cs.forms.ModuleHandlers();
        
    };

    // The default structure must exists
    cs.forms.ModuleBase.prototype.bo = {};
    cs.forms.ModuleBase.prototype.tpt = {};
        
    cs.forms.ModuleBase.prototype.initInheritedModule = function(){
        this.bo = cs.cloneObject(this.bo);
        this.tpt = cs.cloneObject(this.tpt);
        this.handlers = cs.cloneObject(this.handlers);
    };
        
    cs.forms.ModuleBase.prototype.clone = function(){
        return new this.constructClass();
    };
    
    cs.forms.ModuleBase.prototype.createWindow = function(config){
        if (config.target!=undefined)
        {
            // Check if the target still exist
            if (window.atargetwindow==undefined)
                window.atargetwindow = {};
            
            if (window.atargetwindow[config.target]==undefined || window.atargetwindow[config.target].destroyed==true)
            {
                window.atargetwindow[config.target] = cs.common.Window.CreateWindow(config);
            }
            else
            {
                window.atargetwindow[config.target].contentdiv.innerHTML = "";
            }
                
            this.windowform = window.atargetwindow[config.target];
            
            if (this.windowform.tab!=undefined)
                this.windowform.tab.activate();
            else
                this.windowform.makeactive();
        }
        else
        {
            this.windowform = cs.common.Window.CreateWindow(config);
            this.windowform.makeactive();
        }
        return this.windowform;
    };
    
    cs.forms.ModuleBase.prototype.closeWindow = function(){
        this.windowform.close();
    };
    
    cs.forms.ModuleBase.prototype.showProgressBar = function(config){
    
        // TODO: Need to document this down
        if (this.aprogresswindow == undefined)
            this.aprogresswindow = new Array();
        
        this.aprogresswindow.push(this.showMessageBox(config));
    };
    
    cs.forms.ModuleBase.prototype.destroyProgressBar = function(){
    
        // Iterate thru the progress window array and destroy them
        if (this.aprogresswindow!=undefined)
        {
            while (this.aprogresswindow.length > 0)
            {
                //cs.debugalert("destroying progress bar..");
                var pwindow = this.aprogresswindow.pop();
                pwindow.mask.destroy();
            }
        }
    };
    
    cs.forms.ModuleBase.prototype.showMessageBox = function(config){
        
        /*
            Configuration Variation:
            1) type: "alert", "decision", "flash" // Ignored at this moment
            2) message: // Message to show to user
            3) flashduration: // If defined, the message box will be destroyed in the specified ms.
            4) options: [Array:{value, onclick}] // Array of options for user to make decision
            
            Example:
            --------
            config = {type:"alert", message:"Testing Message", flashduration:1000};
            config = {type:"decision", message:"Confirm Deletion?",
                    options:[
                        {value:"Yes", onclick:function(){alert("Cool!");}},
                        {value:"No", onclick:function(){alert("Not cool!");}}
                    ]};
        */
        
        var mask = this.createOverlayMask();
        var mbox = this.createMessageBox();
        
        if (config.onclick!=undefined)
            mbox.jcsdom_closecell.onclick = function(){
                mask.destroy();
                config.onclick();
            }
        else
        {
            mbox.jcsdom_closecell.onclick = function() {
                mask.destroy();
            };
        }
        
        // If showduration is defined, set to destroy the window after the duration
        if (!isNaN(config.flashduration))
        {
            setTimeout(mask.destroy, parseInt(config.flashduration));
        }
        
        // Formulate the Template
        mbox.jcsdom_content.push(new cs.forms.FormTemplateItem("RootForm", "message"));
        mbox.jcsdom_content.push({tag:"BR"});

        // Formulate the Business Object
        var bo = {
            message: new cs.forms.Span()
        };
        bo.message.setValue(config.message);
        
        // Dynamically customize the option template and business object
        if (config.options != undefined)
        {
            for (var i=0; i<config.options.length; i++)
            {
                mbox.jcsdom_content.push(new cs.forms.FormTemplateItem("RootForm", "option" + i));
                bo["option" + i] = new cs.forms.Button({defaultvalue:"Option " + i});
                for (strName in config.options[i])
                {
                    switch (strName)
                    {
                        case "onclick":
                            bo["option" + i].setOnClick(config.options[i][strName]);
                            break;
                            
                        case "value":
                            bo["option" + i].setValue(config.options[i][strName]);
                            break;
                            
                    }
                }
            }
        }
        
        var template = new cs.forms.FormTemplate("RootForm", mbox.jcsdom_container);
        var opt = {bindingParent: {RootForm: bo}, populatingData:true};
        var boForm = pc.appendJCSDOMtoJSDOM(template, mask.content, opt);
        
        return {mask:mask, mbox:mbox};
    };
    
    cs.forms.ModuleBase.prototype.createMessageBox = function(){
        
        var jcsdomContent = new Array();
        var jcsdomCloseCell = {tag:"td", className:"top_right"};
        var jcsdomContainer = {tag:"CENTER",
            html:[
                {tag:"table", className:"msgbox", style:"z-index:"+cs.getNextHighestDepth(),
                    border:0, cellspacing:0, cellpadding:0,
                    html:[
                        {tag:"tr", html:[
                            {tag:"td", className:"top_left"},
                            {tag:"td", className:"top_center"},
                            jcsdomCloseCell
                        ]},
                        {tag:"tr", html:[
                            {tag:"td", className:"mid_left"},
                            {tag:"td", className:"mid_center",
                                style:"text-align: center; vertical-align: middle",
                                html:jcsdomContent},
                            {tag:"td", className:"mid_right"}
                        ]},
                        {tag:"tr", html:[
                            {tag:"td", className:"btm_left"},
                            {tag:"td", className:"btm_center"},
                            {tag:"td", className:"btm_right"}
                        ]}
                    ]
                }
            ]
        };
        
        return {jcsdom_container:jcsdomContainer, jcsdom_content:jcsdomContent, jcsdom_closecell:jcsdomCloseCell}
    };
    
    cs.forms.ModuleBase.prototype.createOverlayMask = function(){
        
        var maskID = "mask" + Math.random();
        var containerID = "container" + Math.random();
        var contentID = "content" + Math.random();
        
        var jcsdomMask = {tag:"DIV",
            id:maskID,
            style:"position:fixed; width:100%; height:100%; opacity:0.5; background-color:#AAFFAA; left:0px; top:0px; z-index:" + cs.getNextHighestDepth(),
            html:""
        };
        
        if (document.all)
        {
            // If it is IE
            jcsdomMask.style += ";filter: alpha(opacity = 50)";
        }
        
        var jcsdomContainer = {tag:"table",
            id:containerID,
            style:"position:fixed; width:100%; height:100%; top:0px; left:0px; z-index:" + cs.getNextHighestDepth(),
            html:{tag:"TR",
                    html:{tag:"TD",
                        id:contentID,
                        style:"text-align:center; vertical-align:middle"
                    }
                }
        };
        
        pc.appendJCSDOMtoJSDOM(jcsdomMask, window.document.body);
        pc.appendJCSDOMtoJSDOM(jcsdomContainer, window.document.body);
        
        var obj = {};
        obj.div = document.getElementById(maskID);
        obj.content = document.getElementById(contentID);
        obj.destroy = function(){
            var m = document.getElementById(maskID);
            var n = document.getElementById(containerID);
            if (m!=undefined)
                window.document.body.removeChild(m);
            if (n!=undefined)
                window.document.body.removeChild(n);
        };
        return obj;
            
    };
    
    cs.forms.ModuleBase.prototype.clientaction = {
    
        //  TODO: Got to check if btnsubmit and txtmessage is declared!
        confirm : function(arg){
            var mod = arg.module;
            var jsonData = arg.jsonData;
            var context = {handler:mod.handler.default_handler, module:mod, btncontrols:[mod.bo.btnsubmit], msgcontrols:[mod.bo.txtmessage]};
            ScoutServer.CallServer(mod.servermodulename, "addnew", jsonData, context);
        },
        addnew : function(arg){
            var mod = arg.module;
            var context = {handler:mod.handler.default_handler, module:mod, btncontrols:[mod.bo.btnsubmit], msgcontrols:[mod.bo.txtmessage]};
            var dt = cs.forms.Common.getFormJSON(context.module.bo);
            context.module.bo.btnsubmit.setState("click", false);
            ScoutServer.CallServer(mod.servermodulename, "addnew", dt, context);
        },
        search : function(arg){
            var mod = arg.module;
            var context = {handler:mod.handler.default_handler, module:mod, btncontrols:[mod.bo_search.btnsubmit], msgcontrols:[mod.bo_search.txtmessage]};
            var dt = cs.forms.Common.getFormJSON(context.module.bo_search);
            context.module.bo_search.btnsubmit.setState("click", false);
            ScoutServer.CallServer(mod.servermodulename, "search", dt, context);
        }
    };
        
        
    /*
    ---------------------------------------
        All the predefined client action
    ---------------------------------------
    Predefined client action will receive a parameter, which consist of:
    1) module = the module object
    2) action = the action name
    */
    cs.forms.ModuleBase.prototype.clientaction.itemedit = function(arg){

        var mod = arg.module;
        var key = arg.adata[0];
        var customData = arg.customdata;

        // Show the DIV in the middle of the screen
        var divInputScreen = window.document.createElement("DIV");
        divInputScreen.style.position = "absolute";

        // Position this to the middle of the screen
        divInputScreen.style.left=(parseInt(document.body.offsetWidth)/2 - 200) + "px";
        divInputScreen.style.top=(parseInt(document.body.offsetHeight)/4) + "px";
        divInputScreen.style.display="inline";
        window.document.body.appendChild(divInputScreen);

        // Show the editing screen
        var module_EditString = new cs.forms.ModuleBase(mod.servermoduleid, mod.servermodulename);
        
        module_EditString.tpt = {};
        module_EditString.tpt.editor = new cs.forms.FormTemplate("RootForm",
                            {tag:"table", cellpadding:"0px", cellspacing:"0px", style:"width:300px;background-color:#9CB0B5;border-width:5px;border-color:#000000", html:[
                                {tag:"tr", html:[
    	                            {tag:"th", colspan:"2", html:new cs.forms.FormTemplateItem("RootForm", "btnClose")}
                                    ]},
                                customData.edititemconfig.editortemplate,
                                {tag:"tr", html:[
    	                            {tag:"td", html:""},
                                    {tag:"td", html:new cs.forms.FormTemplateItem("RootForm","btnSubmit")}
                                    ]},
                                {tag:"tr", html:[
                                    {tag:"td", html:""},
    	                            {tag:"td", html:new cs.forms.FormTemplateItem("RootForm","txtMessage")}
                                    ]}
                                ]
                            }
                        );

        module_EditString.bo = {
                    pKey : new cs.forms.JSHiddenField(),
                    btnSubmit : new cs.forms.Button({onclick: function(){module_EditString.clientaction.edit(module_EditString)},
                                                     defaultvalue: "Submit", statevalue: {click:"Submitting...", wait:"Processing..."}}),
                    btnClose : new cs.forms.Button({onclick: function(){window.document.body.removeChild(divInputScreen);},
                                                     defaultvalue: "close", statevalue: {click:"closing...", wait:"closing..."}}),
                    txtMessage : new cs.forms.Span()
                };
        cs.common.Object.jointo(customData.edititemconfig.bo, module_EditString.bo);
                
        module_EditString.clientaction = {};
        module_EditString.clientaction.edit = function(mod){
                var context = {handler:mod.handler.default_handler, module:mod, btncontrols:[mod.bo.btnSubmit], msgcontrols:[mod.bo.txtMessage]};
                var dt = cs.forms.Common.getFormJSON(context.module.bo);
                context.module.bo.btnSubmit.setState("click", false);
                ScoutServer.CallServer(mod.servermodulename, "Update", dt, context);
            };
        
        // Set the value for the business object
        module_EditString.bo.pKey.setValue(key);
        
        module_EditString.handlers[200]["getitemdetailsresult"] = function(context, res){

            var xmlDoc = XML.parse(res.ResponseBody.Message);
            
            var xmlSummaryNodes = XML.selectNodes(xmlDoc, "DataSet/diffgr:diffgram/ResultDataSet/Summary");
            var ajsonSummay = XML.XMLNodeArraytoJSONArray(xmlSummaryNodes);
            if (ajsonSummay[0].RecordCount > 0)
            {
                var xmlSingleItemNodes = XML.selectNodes(xmlDoc, "DataSet/diffgr:diffgram/ResultDataSet/ItemDetails");
                var ajsonSingleItem = XML.XMLNodeArraytoJSONArray(xmlSingleItemNodes);
                
                // the json array should have only 1 item, since we request by pKey
                for (strBOField in context.module.bo)
                {
                    // Set the module.bo fields to values returned from server
                    // note: all dynamic fields are to be in lowercase.
                    if (context.module.bo[strBOField].setValue!=undefined)
                    {
                        var strTemp = ajsonSingleItem[0][strBOField.toLowerCase()];
                        if (strTemp!=undefined)
                        {
                            context.module.bo[strBOField].setValue(strTemp);
                        }
                    }
                }
                
                var opt = {bindingParent:{RootForm: module_EditString.bo}, populatingData:true};
                var boForm = pc.appendJCSDOMtoJSDOM(module_EditString.tpt.editor, divInputScreen, opt);
            }
            else
            {
                cs.debugalert("The item is no longer found in the system.");
            }
        };

        // No choice, but to load the item data from the server again
        // This is because we definately won't have all the details of the item
        // But using the pKey it is enough for us to retrieve all the details.
        var contextItem = {module:module_EditString};
        
        // Get the datafield required from the edititemconfig.bo
        // which is then pass to the server module to retrieve the needed fields
        var astrDataField = new Array();
        for (strBOField in customData.edititemconfig.bo)
            astrDataField.push(strBOField.toLowerCase());
        
        var dtItem = {pKey: key, datafield: astrDataField};
        ScoutServer.CallServer(mod.servermodulename, "GetItemDetails", dtItem, contextItem);

    };
    	
    cs.forms.ModuleBase.prototype.clientaction.bulkremove = function(arg){

        // collect the bo from tmpModule
        var tmpModule = arg.module;
        var strAction = arg.action;
        
        // First loop check the selected record count
        var intFormCount = tmpModule.bo.ResultRow.getFormCount();
        var intDeleteCount = 0;
        for (var intFormIndex=0; intFormIndex<intFormCount; intFormIndex++)
        {
            var curRow = tmpModule.bo.ResultRow.getForm(intFormIndex);
            var jeleSelection = curRow.getElementByName("selection");
            if (jeleSelection!=undefined&&jeleSelection.getValue()==true)
            {
                intDeleteCount++;
            }
        }
        
        // If there is no record selected, ignore the request and show a message to user.
        if (intDeleteCount==0)
        {
            alert("Please select record(s) for deletion using the tickbox.");
            return false;
        }
        
        // Get confirmation from the user for action on the selected records
        if (confirm("Confirm to delete the " + intDeleteCount + " record(s)?")!=true)
        {
            return false;
        }
        
        for (var intFormIndex=0; intFormIndex<intFormCount; intFormIndex++)
        {
            
            var curRow = tmpModule.bo.ResultRow.getForm(intFormIndex);
            var jeleSelection = curRow.getElementByName("selection");
            if (jeleSelection!=undefined&&jeleSelection.getValue()==true)
            {
                var v = curRow.getElementByName("BulkAction_" + strAction).getValue();

                // Show some animation to the user that this row is being deleted.
                curRow.highlightDOM("#F1FFF1");
                
                // Make a call to the server to delete and callback to remove the DOM
                var context = {handler:tmpModule.handler.default_handler, module:tmpModule, localref:{row:curRow, rowindex:intFormIndex}};
                ScoutServer.CallServer(tmpModule.servermodulename, "Remove", v, context);
            }
        }
        
        return true;
    }
        
    cs.forms.ModuleBase.prototype.handler = {
        /*
        default_handler handles the following default responses:
        --------------------------------------------------------
        1) Invalid Response Code ( > 500 )
            - all : alert message
        2) Confirmation Response Code ( > 300 )
            - confirmation : display confirmation dialog
        3) Normal Response Code ( > 200 )
            - display : display status message
        */
        default_handler : function(context, res){
        
                    context.module.destroyProgressBar();
                    
                    // Create a handler code array and sort descendingly
                    var handlerCodeArray = new Array();
                    for (hCode in context.module.handlers)
                    {
                        handlerCodeArray.push(hCode);
                    }
                    handlerCodeArray.sort(function(a,b){if (a<b) return -1; else return 1;});
                    
                    //cs.debugalert(handlerCodeArray);
                    
                    if (res==undefined)
                    {
                        // Look for the highest error handler
                        var func = null;
                        while (func==undefined && handlerCodeArray.length>0)
                        {
                            func = context.module.handlers[handlerCodeArray.shift()]["any"];
                        }
                        
                        if (func == undefined)
                        {
                            cs.debugalert("A critical error had occured, there is no handler.");
                        }
                        else
                        {
                            func(context, res);
                        }
                    }
                    else
                    {
                        // Look for the largest matching code
                        var func = null;
                        while (func==undefined && handlerCodeArray.length>0)
                        {
                            var intCode = handlerCodeArray.pop();
                            //cs.debugalert("Checking:" + intCode + " vs " + res.ResponseCode);
                            if (intCode<=res.ResponseCode)
                            {
                                var funcs = context.module.handlers[intCode];
                                // cs.debugalert(intCode + "\n" + cs.Debug.inspect(funcs, {depth:1}));
                                if (funcs[res.ResponseAction]!=undefined)
                                {
                                    func = funcs[res.ResponseAction];
                                }
                            }
                        }
                        if (func == undefined)
                        {
                            cs.debugalert("A critical error had occured, there is no handler for " + res.ResponseCode + ":" + res.ResponseAction + ".");
                            
                        }
                        else
                        {
                            func(context, res);
                        }
                    }
                }    
    };
    
}
