/*
Copyright (c) 2010, Kinetic Data Inc. All rights reserved.
http://www.kineticdata.com
$Rev: 581 $
$Date: 2010-04-22 13:41:52 -0500 (Thu, 22 Apr 2010) $
*/
/**
 * This file is to be used for adding client-side functionality to Kinetic Survey and Kinetic Request.
 * @module kd_clientmanager
 *
 */

// setup shortcuts
if (typeof Dom == "undefined") { Dom = YAHOO.util.Dom; }
if (typeof Connect == "undefined") { Connect = YAHOO.util.Connect; }


/**
 * The KD global namespace object
 * @class KD
 * @static
 */
if (typeof KD == "undefined") {
    KD = {};
}
if (typeof KD.utils == "undefined") {
    KD.utils = {};
}

if (! KD.utils.ClientManager){

    /**
 ClientManager singleton
*/
    KD.utils.ClientManager= new function(){

        this._elements=new KD.utils.Hash();
        this._connections = new KD.utils.Hash();
        this._invalidSessionRequest = new Array();
        this.sessionId="";
        this.errorMessage="";
        this.successMessage="";
        this.authenticated; //boolean
        this.userName="";
        this.templateId="";
        this.customerSurveyId="";
        this.submitType="";//For approvals
        this.isNewPage; //boolean - used for 'Page is New' event ifExpr
        this.maxCharsOnSubmit = (64 * 1024) - 1; // 65535
        this.tooManyCharactersForSubmitStr = "A limit of "+this.maxCharsOnSubmit+" characters for a submit is being applied. Please reduce the number of characters you are attempting to submit.";
        this.requiredWarningStr = "Required fields missing:";
        this.validFormatWarningStr = "Invalid formatted fields:";
        this.submitButtons=new Array();
        this.isLoading=false;
        this.isSubmitting=false;
        this.sessionCheck = null;
        this.webAppContextPath = "/kinetic";
        //Custom Events
        this.onSetFieldsReturn;
        this.onAttachMenu;

        this.init = function(){
            KD.utils.ClientManager.isLoading=true;
            if(window.ks_initSessionVars){
                ks_initSessionVars();
            }
            KD.utils.ClientManager.initElements();

            KD.utils.ClientManager.onSetFieldsReturn = new YAHOO.util.CustomEvent("onSetFieldsReturn");
            KD.utils.ClientManager.onAttachMenu = new YAHOO.util.CustomEvent("onAttachMenu");

            var theForm=Dom.get('pageQuestionsForm');
            YAHOO.util.Event.addListener(theForm, 'submit', KD.utils.Action.validateForm, theForm, true);

            if(window.ks_actionsInit){
                ks_actionsInit();
            }
            KD.utils.ClientManager.checkMessages();
            KD.utils.ClientManager.initLogin();
            //KD.utils.Action.applyValueActions();
            KD.utils.ClientManager.initDateFields();
            KD.utils.ClientManager.isLoading=false;
        }

        this.registerItems = function(pageID, pageDocument) {
            KD.utils.ClientManager._elements.setItem(pageID, KD.utils.Util.getElementType(pageDocument.id));
            for (var i = 0; i < pageDocument.childNodes.length; i++) {
                var nextElement = pageDocument.childNodes[i];
                var instanceId=KD.utils.Util.getIDPart(nextElement.id);

                if (!nextElement || !instanceId) {
                    continue; //ignore items that we don't care about
                }

                if (nextElement.id && nextElement.id.indexOf("SECTION_")!=-1) {
                    for (var qidx=0; qidx<nextElement.childNodes.length; qidx++) {
                        var childElement = nextElement.childNodes[qidx];
                        var childInstId=KD.utils.Util.getIDPart(childElement.id);
                        if(!childElement|| !childInstId){
                            continue; //ignore items that we don't care about
                        }
                        KD.utils.ClientManager.initPatternWatch(childElement);
                        this._elements.setItem(childInstId, KD.utils.Util.getElementType(childElement.id));
                    }
                }
                if (nextElement.className && nextElement.className.indexOf("templateButtonLayer") != -1) {
                    this.submitButtons.push(instanceId);
                    var theForm=Dom.get('pageQuestionsForm');
                    var theButtons=Dom.getElementsByClassName('templateButton', 'input', nextElement);
                    YAHOO.util.Event.addListener(theButtons, 'click', KD.utils.Action._submitButtonClick, [theForm,instanceId], true);
                }
                if (nextElement.id) {
                    KD.utils.ClientManager.initPatternWatch(nextElement);
                    this._elements.setItem(instanceId, KD.utils.Util.getElementType(nextElement.id));
                }
            }
        }

        this.initElements = function() {
            var pageID = Dom.get("pageID").value;
            var pageDocument;

            if (pageID && pageID.length > 10) {
                pageDocument = Dom.get("PAGE_" + pageID);
                this.registerItems(pageID, pageDocument);
            } else {
                /*On confirmation pages, may not have a page set in the hidden PageID field*/
                var pages=Dom.getElementsByClassName("templateContent", "div");
                pageDocument=pages[0];
                if (!pageDocument) {
                    alert("Problem initializing page.");
                }
                for (var i = 0; i < pages.length; i++) {
                    pageDocument=pages[i];
                    this.registerItems(KD.utils.Util.getIDPart(pageDocument.id), pageDocument);
                }
            }
        }

        /**
	* Checks if there is a "message" layer for including messages from Remedy/web server such as "Successfully logged in".
	* Runs on load.
	* @return void
	*/
        this.checkMessages = function(){
            var messageLayer=Dom.get('message');
            if(messageLayer){
                if (KD.utils.ClientManager.successMessage && KD.utils.ClientManager.successMessage != ""){
                    messageLayer.innerHTML= KD.utils.ClientManager.successMessage;
                    messageLayer.style.visibility="visible";
                }
                if (KD.utils.ClientManager.errorMessage && KD.utils.ClientManager.errorMessage != ""){
                    messageLayer.innerHTML=KD.utils.ClientManager.errorMessage;
                    messageLayer.style.visibility="visible";
                }
            }else if(KD.utils.ClientManager.errorMessage && KD.utils.ClientManager.errorMessage != ""){
                alert(KD.utils.ClientManager.errorMessage);
            }
        }

        this.initDateFields = function(){
            var yearEls=Dom.getElementsByClassName("dateYear", "input");
            for (var i=0; i<yearEls.length; i++){
                var instId=yearEls[i].id.substring(5);
                if(instId){
                    KD.utils.Action.setDateFields(instId);
                }
            }
        }

        this.initLogin = function(){
            var loginForm=Dom.get("loginForm");
            var loginInfo=Dom.get('authenticatedName');
            if(KD.utils.ClientManager.authenticated){
                if(loginForm){
                    loginForm=loginForm.parentNode;
                    var parent=loginForm.parentNode;
                    parent.removeChild(loginForm);
                }
                if (loginInfo){
                    var login=loginInfo.innerHTML;
                    login=login.replace(/--loginName--/i, KD.utils.ClientManager.userName);
                    loginInfo.innerHTML=login;
                }
            }else{
                if(loginInfo){
                    var par=loginInfo.parentNode;
                    par.removeChild(loginInfo);
                }
                var originatingPage=Dom.get('originatingPage');
                if (originatingPage){
                    originatingPage.value=this.originatingPage;
                }
                var authenticationType=Dom.get('authenticationType');
                if (authenticationType){
                    authenticationType.value=this.authenticationType;
                }
                var sessionFld=Dom.get('loginSessionID');
                if(sessionFld){
                    sessionFld.value=Dom.get("sessionID").value;
                }
            }
        }
        /**
	* Returns the element type given an instance Id.
	* @param instanceId : instance ID of an element on the page
	* @return String of the element type.
	*/
        this.getElementType = function(instId){
            return this._elements.getItem(instId);
        }

        this.clearInvalidSessionRequest = function () {
            KD.utils.ClientManager._invalidSessionRequest = new Array();
        }
        this.getInvalidSessionRequest = function (){
            return KD.utils.ClientManager._invalidSessionRequest;
        }

        this.registerInvalidSessionRequest = function (dataReqInstId, post, path, callback){
            var paramsArray = new Array();
            paramsArray[0]=dataReqInstId;
            paramsArray[1]=post;
            paramsArray[2]=path;
            paramsArray[3]=callback;

            KD.utils.ClientManager._invalidSessionRequest=paramsArray;
        }



        /**
        * Monitors active Simple Data Request Connections to avoid getting results back out of order, particularly on keypress
        * @param dataReqInstId : The Simple Data Request instance Id
        * @param paramsArray : [YUI connection object, requestParamString]
        * @return : void
        * */
        this.setNewConnection = function(dataReqInstId, paramsArray){
            if (dataReqInstId != null && paramsArray != null && paramsArray.length >0){
                KD.utils.ClientManager._connections.setItem(dataReqInstId, paramsArray);
            }
        }

        /**
        * Determine whether the SDR is active (not yet returned a response)
        * @param dataReqInstId : The Simple Data Request instance Id
        * @return : boolean isActive
        * */
        this.isActiveConnection = function(dataReqInstId){
            var conn = KD.utils.ClientManager._connections.getItem(dataReqInstId);
            var isActive = false;
            if(conn != null && conn.length >0){
                isActive = Connect.isCallInProgress(conn[0]);
            }
            return isActive;
        }

        /**
        * Returns a connection object which includes the YUI connection, along with the params used for connection.
        * The params are useful if comparing whether a new request is the same as an old one.
        * @param dataReqInstId : The Simple Data Request instance Id
        * @return connectionInfo : [YUI connection object, requestParamString]
        * */
        this.getConnection = function(dataReqInstId){
            var conn;
            if (dataReqInstId != null){
                conn = KD.utils.ClientManager._connections.getItem(dataReqInstId);
            }
            return conn;
        }


        /*
	*/
        this.addAction = function(clientAction){
            //Special custom events
            if(clientAction.jsEvent=="*custom*" || clientAction.jsEvent=="submit" || clientAction.jsEvent=="beforeSubmit"){
                var id=clientAction.elementId;
                if(clientAction.jsEvent=="submit"|| clientAction.jsEvent=="beforeSubmit"){
                    id=id+"-"+clientAction.jsEvent
                };
                KD.utils.ClientManager.addCustomEvent(id, clientAction);
                return;
            }
            //Generic custom events
            if(clientAction.jsEvent=="setFieldsReturn" || clientAction.jsEvent=="attachMenu"){
                var customEvent=KD.utils.ClientManager.onSetFieldsReturn;
                if(clientAction.jsEvent=="attachMenu"){
                    customEvent=KD.utils.ClientManager.onAttachMenu;
                }
                customEvent.subscribe(function(type, origItems, clientAction){
                    KD.utils.Action._customEventHandler(type, origItems,clientAction)
                }, clientAction);
                return;
            }
            //Standard Events
            YAHOO.util.Event.addListener(clientAction.elObj, clientAction.jsEvent, function(e){
                clientAction.action.apply(KD.utils.Action,[e,this])
            }, clientAction, true);
            //If the objects have a value, fire the action now for page re-loads, approvals, back button
            var objs=new Array();
            if(KD.utils.Util.isArray(clientAction.elObj)){
                var objs=clientAction.elObj;
            }else{
                objs.push(clientAction.elObj);
            }
            for(var i = 0; i < objs.length; i++){
                KD.utils.Action.applyValueActions(objs[i],clientAction);
            }
        }

        /* Key: Instance ID of the dynamic text element it is tied to (only one custom event per text element).
	*  Value: a clientAction object.
	*/
        this.customEvents=new KD.utils.Hash();

        /* Custom Events are tied to Dynamic Text Elements.
	* They are useful for triggering something when a dynamic text element is interacted with,
	* such as on an innerHTML update in a service catalog.  Only one customEvent per dynamic text element is stored.
	* @param clientAction : A KD.utils.ClientAction object
	*/
        this.addCustomEvent = function(id, clientAction){
            var actions=KD.utils.ClientManager.customEvents.getItem(id);
            if(actions && actions.length > 0){
                actions.push(clientAction);
            }else{
                actions=[clientAction];
            }
            KD.utils.ClientManager.customEvents.setItem(id, actions);
        }

        this.initPatternWatch = function(el){
            var inputEl=KD.utils.Util.getQuestionInput(KD.utils.Util.getIDPart(el.id));
            if (inputEl && !inputEl.length){ //If this is an array of radio buttons exit, as we don't do patterns for them
                var pattern=inputEl.getAttribute('validationFormat');
                if(pattern && pattern != ""){
                    YAHOO.util.Event.addListener(inputEl, 'focus', KD.utils.Action._disableButtonEvents);
                    YAHOO.util.Event.addListener(inputEl, 'blur', KD.utils.Action.checkPattern);
                }
                //Watch typing for textarea fields w/max characters set
                else if(inputEl.tagName && inputEl.tagName.toUpperCase()=="TEXTAREA" && inputEl.getAttribute("maxlength")){
                   YAHOO.util.Event.addListener(inputEl, 'keyup', function(e,parms){
                        KD.utils.Action.watchFieldLength(parms)
                    }, inputEl);
                    YAHOO.util.Event.addListener(inputEl, 'change', function(e,parms){
                        KD.utils.Action.watchFieldLength(parms)
                    }, inputEl);
                }
            //Watch for attachments
            }else if(inputEl && inputEl.length){
                if(inputEl[0].getAttribute('fileTypesAllowed') != null){
                    YAHOO.util.Event.addListener(inputEl[0], 'change', function(e,parms){
                        KD.utils.Action._setFileLink(parms)
                    }, inputEl);
                    KD.utils.Action._setFileLink(inputEl[0]);
                }
            }
        }


        /**
         * Creates a simple, modal login dialog
         * @param {object} options - object of options to build the simple login dialog.
         *     showAuthStr: true|false (default false)
         *     showUserName: true|false (default false)
         */
        this.renderSimpleLogin = function(options) {
            // build up the html for the dialog form
            KD.utils.ClientManager.buildSimpleLogin(options);

            // dialog button handlers
            var handleCancel = function() {
                // re-enable the main form submit buttons
                KD.utils.ClientManager.isSubmitting=false;
                for (var i = 0; i < KD.utils.ClientManager.submitButtons.length; i += 1) {
                    KD.utils.Action.enableButton(KD.utils.ClientManager.submitButtons[i]);
                }
                // cancel and destroy the dialog
                this.cancel();
                this.destroy();
            }
            var handleSubmit = function() {
                Connect.initHeader("X-Requested-With", "XMLHttpRequest");
                this.submit();
                this.show();  // keep the dialog open, and let the callback handle it
            }

            // render the form in a YUI dialog container
            var simpleLogin = new YAHOO.widget.Dialog("simpleLogin",
            {
                width: "300px",
                fixedcenter: true,
                visible: false,
                constraintoviewport: true,
                close: false,
                modal: true,
                postmethod: 'async',
                buttons: [
                {
                    text: "Login",
                    handler: handleSubmit,
                    isDefault: true
                },

                {
                    text: "Cancel",
                    handler: handleCancel
                }
                ]
            } );

            // callbacks for the XhrRequest object
            var handleSuccess = function(o) {
                // re-enable the main form submit buttons
                KD.utils.ClientManager.isSubmitting=false;
                for (var i = 0; i < KD.utils.ClientManager.submitButtons.length; i += 1) {
                    KD.utils.Action.enableButton(KD.utils.ClientManager.submitButtons[i]);
                }
                var params = KD.utils.ClientManager.getInvalidSessionRequest();
                // If recovered, run the last Datarequests again
                if (params[0]==="PREV_PAGE_REQUEST") {
                    KD.utils.Action.disableSubmitButtons();
                    KD.utils.Action.loadPreviousPage();
                } else if (params[0]==="NEXT_PAGE_REQUEST"){
                    KD.utils.Action.disableSubmitButtons();
                    document.pageQuestionsForm.submit();
                } else if (params[1] !== null && params[2] !== null && params[3] !== null) {
                    Connect.asyncRequest(params[1],params[2],params[3]);
                } else {
                // did not recognize the type of action, do nothing special
                }
                // hide and destroy the dialog
                simpleLogin.hide();
                simpleLogin.destroy();
            };
            var handleFailure = function(o) {
                // display error messages
                var statusCode = null;
                if (o && o.status) {
                    statusCode = o.status;
                }
                var errorMessage = null;
                if (o && o.getResponseHeader && o.getResponseHeader['X-Error-Message']) {
                    errorMessage = o.getResponseHeader['X-Error-Message'];
                } else {
                    errorMessage = "Error: " + statusCode;
                }

                var msgEl = Dom.get('simpleLoginMsg');
                if (msgEl) {
                    msgEl.innerHTML = errorMessage;
                    Dom.setStyle(msgEl, 'display', 'block');
                } else {
                    alert(errorMessage);
                }

                var pwdInput = Dom.get('simpleLoginPass');
                if (pwdInput) {
                    pwdInput.value = "";
                    pwdInput.select();
                    pwdInput.focus();
                }
            };

            // define the callback object
            simpleLogin.callback = {
                success: handleSuccess,
                failure: handleFailure,
                timeout: 30000
            };

            // validate the user at least entered a login id
            simpleLogin.validate = function() {
                var data = this.getData();
                if (data.UserName == "") {
                    alert("Please enter your Login ID");
                    return false;
                } else {
                    return true;
                }
            };

            // render and display the dialog, then focus on first input field
            simpleLogin.render();
            simpleLogin.show();
            simpleLogin.focusFirst();
            var userInput = Dom.get("simpleLoginUser");
            var passInput = Dom.get("simpleLoginPass");
            if (userInput && userInput.getAttribute("readOnly") != "true") {
                userInput.select();
                userInput.focus();
            } else {
                passInput.select();
                passInput.focus();
            }
        }


        /**
         * Simple login dialog used for expired sessions
         * @param {object} options - object of options to build the simple login dialog.
         *     showAuthStr: true|false (default false)
         *     showUserName: true|false (default false)
         **/

        this.buildSimpleLogin = function(options){
            var showAuthStr = false;
            var showUserName = false;
            if (options) {
                if (options.showAuthStr && options.showAuthStr != "") {
                    showAuthStr = options.showAuthStr;
                }
                if (options.showUserName && options.showUserName != "") {
                    showUserName = options.showUserName;
                }
            }


            if (Dom.get('simpleLogin') === null) {
                // outer div to contain the form elements
                var outerdiv = document.createElement('div');
                outerdiv.id = "simpleLogin";
                outerdiv.className = " yui-skin-sam simpleLoginLayer";

                // heading
                var hd = document.createElement('div');
                hd.className = "hd";
                hd.innerHTML = "Expired session, please login";
                outerdiv.appendChild(hd);

                var bd = document.createElement('div');
                bd.className = "bd";
                outerdiv.appendChild(bd);

                // error message
                var msg = document.createElement('div');
                msg.id = "simpleLoginMsg";
                Dom.setStyle(msg, 'display', 'none');
                bd.appendChild(msg);

                // form
                var form = document.createElement('form');
                form.name = "Login";
                form.action = "KSAuthenticationServlet";
                bd.appendChild(form);

                // username label and input field
                var userdiv = document.createElement('div');
                var userlabel = document.createElement('label');
                userlabel.className = "simpleLoginLabel";
                userlabel.innerHTML = "Login ID";
                var userinput = document.createElement('input');
                userinput.id = "simpleLoginUser"
                userinput.name = "UserName";
                userinput.type = "text";
                userinput.className = "simpleLoginInput";
                userdiv.appendChild(userlabel);
                userdiv.appendChild(userinput);
                form.appendChild(userdiv);

                if (!showUserName && KD.utils.ClientManager.userName != null && KD.utils.ClientManager.userName.length > 0) {
                    // Preset and disable the user login name.
                    // We don't want to allow the user to enter another login name
                    userinput.value = KD.utils.ClientManager.userName;
                    userinput.setAttribute("readOnly", "readOnly");
                    userinput.style.backgroundColor=KD.utils.Action.readOnlyColor;
                }

                // password label and input field
                var passdiv = document.createElement('div');
                var passlabel = document.createElement('label');
                passlabel.className = "simpleLoginLabel";
                passlabel.innerHTML = "Password";
                var passinput = document.createElement('input');
                passinput.id = "simpleLoginPass"
                passinput.name = "Password";
                passinput.type = "password";
                passinput.className = "simpleLoginInput";
                passdiv.appendChild(passlabel);
                passdiv.appendChild(passinput);
                form.appendChild(passdiv);

                // authentication string label and input field
                if (showAuthStr) {
                    var authdiv = document.createElement('div');
                    var authlabel = document.createElement('label');
                    authlabel.className = "simpleLoginLabel";
                    authlabel.innerHTML = "Authentication";
                    var authinput = document.createElement('input');
                    authinput.id = "simpleLoginAuth"
                    authinput.name = "Authentication";
                    authinput.type = "text";
                    authinput.className = "simpleLoginInput";
                    authdiv.appendChild(authlabel);
                    authdiv.appendChild(authinput);
                    form.appendChild(authdiv);
                }
                // insert the form into the document body
                document.body.insertBefore(outerdiv, document.body.childNodes[0]);
            }
        };

        // Checks if the current session is still active.  Returns 200 for valid
        // session, and 401 for non-valid session
        this.checkSession = function(authenticate) {
            KD.utils.ClientManager.sessionCheck = null;
            var auth = authenticate === true ? '&auth=forced' : '';
            var sUrl = "resources/partials/sessionCheck.jsp?srv="+encodeURIComponent(KD.utils.ClientManager.templateId)+auth;
            var callback = {
                success: function (o) {
                    KD.utils.ClientManager.sessionCheck = o;
                },
                failure: function (o) {
                    KD.utils.ClientManager.sessionCheck = o;
                },
                argument: [{
                    timeout: 5000
                }]
            };
            KD.utils.Action._makeSyncRequest(sUrl, callback);
        };

    }; // KD.utils.ClientManager
}

/**
* @class KD.utils.ClientAction
*
*/
KD.utils.ClientAction = function(config){
    this.elementId;
    this.jsEvent;
    this.action;
    this.ifExpr;
    this.actionId;
    this.params;
    this.elObj;
    this.currEvt;//The most recent event to act on this
    this.synchronous;//true if this request should be made synchronously (blocking)
    this.useGetEntry;//true if this request set the usegetlist to false
    this.timeout;
    if(config){
        this.elementId=config.elementId;
        this.jsEvent=config.jsEvent;
        this.action=config.action;
        this.ifExpr=config.ifExpr;
        this.actionId=config.actionId;
        this.params=config.params;
        this.elObj=KD.utils.Util.getQuestionInput(this.elementId);
        this.synchronous=config.synchronous;
        this.useGetEntry=config.useGetEntry;
        this.timeout=config.timeout;
        if(!this.elObj){
            var elId=KD.utils.Util.getPrefixFromType(KD.utils.ClientManager.getElementType(this.elementId))+this.elementId;
            this.elObj=Dom.get(elId);
        }
    }

};
