//*********************************
// This script requires :
// > HTTP.js
// > XML.js
// > global.js

/**
 * The role of the Manager is to oversee & set the work its Agents
 */
Manager = {
		
	zIndexCurrent : 0, //px

        SHADOW_OFFSET : 3, // px

		fields : new Object(),
        agents : new Object(), // maps agentId to Agent
        pageIds : new Array(),
        pageTitles : new Array(),
        focussedAgentId : null, // {String} id of agent which has the obj which has the focus in the window
        dateLastModified : new Date(), // Date last request for modification was sent

        getNewAgent : function(id) {
                var atts = id.split('_');
                var agentType = atts[0];
                var fieldType = atts[1];
//alert("id : "+id+" and agentType : "+agentType+" fieldType : "+fieldType);


                switch (fieldType) {
                        case 'Bool' : return new CheckBoxAgent(id);
                        case 'Block' : return new BlockAgent(id);
                        case 'BlockSet' : return new BlockSetAgent(id);
                        case 'Country' : return new AlphaListAgent('Country',id);
                        case 'Currency' : return new DDAgent(id);
                        case 'Date' : switch (agentType) {
                                        case 'link' : return new DateAgent(id);
                                        case 'dOffLink' : return new DateOffsetAgent(id);
                                        default : return new TextInputAgent(id)}
                        case 'Double' : return new TextInputAgent(id);
                        case 'Email' : switch (agentType) {
                                        case 'pattern' : return new PatternAgent(id);
                                        default : return new TextInputAgent(id)}
                        case 'File' : switch (agentType) {
                                        case 'pattern' : return new PatternAgent(id);
                                        default : return new FileAgent(id)}
                        case 'FileSet' : switch (agentType) {
                                        case 'pattern' : return new PatternAgent(id);
                                        default : return new FileSetAgent(id)}
                        case 'FKey' : switch (agentType) {
                                        case 'radio' : return new CheckBoxAgent(id);
                                        case 'dd' : return new DDAgent(id);
                                        case 'aList' : return new AlphaListAgent('FKey',id);
                                        case 'popup' : return new PopupAgent(id);
                                        
                                        case 'pattern' : return new PatternAgent(id);
                                        case 'sug' : return new SuggestionAgent(id);
                                        case 'condIn' : return new CondInAgent(id);
                                        default : return new LKTableAgent(id)}
                        case 'FKeySet' : switch (agentType) {
                                        case 'radio' : return new CheckBoxAgent(id);
                                        case 'dd' : return new DDAgent(id);
                                        case 'aList' : return new AlphaListAgent('FKeySet',id);
                                        case 'popup' : return new PopupAgent(id);
                                        case 'pattern' : return new PatternAgent(id);
                                        case 'lkTable' : return new LKTableAgent(id);
                                        case 'sug' : return new SuggestionAgent(id);
                                        default : return new FKeySetAgent(id,agentType)}
                        case 'Gender' : return new CheckBoxAgent(id);
                        case 'HLink' : switch (agentType) {
                                        case 'pattern' : return new PatternAgent(id);
                                        default : return new TextInputAgent(id)}
                        case 'Int' : return new TextInputAgent(id);
                        case 'Language' : return new AlphaListAgent('Language',id);
                        case 'Parent' : switch (agentType) {
                                        case 'radio' : return new CheckBoxAgent(id);
                                        case 'dd' : return new DDAgent(id);
                                        case 'aList' : return new AlphaListAgent('Parent',id);
                                        case 'popup' : return new PopupAgent(id);
                                        case 'pattern' : return new PatternAgent(id);
                                        case 'sug' : return new SuggestionAgent(id);
                                        default : return new LKTableAgent(id)}
                        case 'RichDate' : switch (agentType) {
                                case 'link' : return new DateAgent(id);
                                case 'radio' : return new CheckBoxAgent(id);
                                case 'popup' : return new PopupAgent(id);
                                case 'dOffLink' : return new DateOffsetAgent(id);
                                case 'specifyRichDate' : return new RichDateAgent(id);
                                default : return new TextInputAgent(id)}
                        case 'ScaledQuantity' : return new ScaledQuantityAgent(id);
                        case 'Time' : switch (agentType) {
                                        case 'link' : return new TimeAgent(id);
                                        case 'dOffLink' : return new DateOffsetAgent(id);
                                        default : return new TextInputAgent(id)}
                        case 'TimeStamp' : switch (agentType) {
                                        case 'link' : return new TimeStampAgent(id);
                                        case 'dOffLink' : return new DateOffsetAgent(id);
                                        default : return new TextInputAgent(id)}
                        case 'TimeStampTZ' : switch (agentType) {
                                        case 'link' : return new TimeStampTZAgent(id);
                                        case 'dOffLink' : return new DateOffsetAgent(id);
                                        default : return new TextInputAgent(id)}
                        case 'Timezone' : return new DDAgent(id);
                        case 'Txt' : switch (agentType) {
                                        case 'pattern' : return new PatternAgent(id);
                                        default : return new TextAreaAgent(id)}
                        case 'TxtInter' : switch (agentType) {
                                        case 'link' : return new TxtInterAgent(id);
                                        case 'aList' : return new AlphaListAgent('Language',id);
                                        case 'pattern' : return new PatternAgent(id)}}},


		getFieldsManager : function(id) {
			if (id) {
				if (!this.fields[id]) this.fields[id] = this.getNewFields(id);
				return this.fields[id];
			}
		},
		
		getNewFields : function(id) {
			return new Fields(id);
		},
		
		
        /**
         * Uses the given id to return the corresponding Agent from the map. If it
         * doesn't already exist, a new Agent is added to the map & is returned.
         * @param {String} id (Required) Agent id
         * @return {Agent} The Agent in the map with the given id
         */
        getAgent : function(id) {
                if (id) {
                        if (!this.agents[id]) this.agents[id] = this.getNewAgent(id);
                        return this.agents[id]}},

        /**
         * Uses the name (if it exists) or the id of the HTML element to return
         * the corresponding Agent from the map. If it doesn't already exist,
         * a new Agent is added to the map & is returned.
         * @param {Object} obj HTML element
         * @return {Agent} An Agent for the given HTML element
         */
        getAgentForObj : function(obj) {
                if (obj) {
                        var id = obj.id;
                        if (obj.name && obj.name!='') id = obj.name;
                        if (!this.agents[id]) this.agents[id] = this.getNewAgent(id);
                        return this.agents[id]}},

        /**
         * @param {String} id Agent id
         * @return {Agent} The Agent in the map with the given id or null if it doesn't exist.
         */
        getAgentWithId : function(id) {
                return this.agents[id]},

        /**
         * @return {Agent} A PopupAgent corresponding to the given window name.
         * If it doesn't exist in the map, null is returned.
         */
        getAgentWithWinName : function(winName) {
                winName = decodeDashes(winName);
                var agentId = winName.substring(6,winName.lastIndexOf('_'));
                return this.getAgentWithId(agentId)},

        getWinName : function(agentId) {
                agentId = encodeDashes(agentId); // IE doesn't like dashes
                return 'popup_'+agentId+'_SEPARATORforKEY'+getKey()},



	/**
	 * Assigns a PopupAgent and opens a positioned popup window
	 * @param {HTMLElement} obj Used to get the agent & set popup position
	 * @param {String} href HREF to be opened in popup window
	 */
	openPopup : function(obj,href) {
		if (obj instanceof String) {
			this.getAgent(obj).displayPopup(href);
			this.setAgentFocus(this.getAgent(obj));
		} else {
			this.getAgentForObj(obj).openPopup(href);
//				this.setAgentFocus(obj);
		}
	},
		

	displayPopup : function(obj,href) {
		this.getAgent(obj).displayPopup(href);
		this.setAgentFocus(this.getAgent(obj));
	},
			
        getAgentFieldType : function(id) {
                var atts = id.split('_');
                var agentType = atts[0];
                var fieldType = atts[1];
                return fieldType;
        },

        /**
         * Adds the agent if it doesn't exist and triggers the blur & focus events for all existing agents
         */
//        setAgentFocus : function(obj, isHierarchicalTable) {
//                var faId = this.focussedAgentId;
//                var fa = (faId) ? this.getAgent(faId) : null;
//                var a = this.getAgentForObj(obj);
//                if ((!a || a.id!=faId) && fa && fa.onBlur) fa.onBlur(); // use onBlur action on focussed agent
//                this.focussedAgentId = (a) ? a.id : null;
//                if (a && a.onFocus) {
//                        if (isHierarchicalTable != undefined)
//                                a.onFocus(isHierarchicalTable);
//                        else
//                                a.onFocus();
//                }
//        }, // use onFocus action on new focussed agent
        
        
        setAgentFocus : function(obj, isHierarchicalTable) {
                var faId = this.focussedAgentId;
                var fa = (faId) ? this.getAgent(faId) : null;
                var a = this.getAgentForObj(obj);
//                if ((!a || a.id!=faId) && fa && fa.onBlur) fa.onBlur(); // use onBlur action on focussed agent
                this.focussedAgentId = (a) ? a.id : null;
                if (a && a.onFocus) {
                        if (isHierarchicalTable != undefined)
                                a.onFocus(isHierarchicalTable);
                        else
                                a.onFocus();
                }
        }, 


        //---
        //For RecordRules Management:
        /**
         * Set to "true" or "false", the boolean value of the Agent parameter "doCheckRules" (used for Record Rules management)
         * @param {String} agentId Required if not applied to a given record field
         * @param {Boolean} yesOrNo Required if not applied to a given record field
         */
        changeDoCheckRules : function(agentId, yesOrNo) {
                var a = this.getAgent(agentId);
                if (a)
                	a.doCheckRules = Boolean(yesOrNo);
        },

        /**
         * @return true or false, the boolean value of the Agent parameter "doCheckRules" (used for Record Rules management)
         * @type boolean
         */
        doWeCheckRules : function(agentId) {
                var a = this.getAgent(agentId);
                if (a)
                	return a.doCheckRules;
                else
                	return false;
        },

         
        /**
         * Set to "true" or "false", the boolean value of the Agent parameter "doCheckRules" (used for Record Rules management)
         * @param {String} agentId Required if not applied to a given record field
         * @param {Boolean} yesOrNo Required if not applied to a given record field
         */
        changeHasToBeHiddenByRules : function(agentId, yesOrNo) {
                var a = this.getAgent(agentId);
                if (a)
                	a.hasToBeHiddenByRules = Boolean(yesOrNo);
        },

        /**
         * @return true or false, the boolean value of the Agent parameter "doCheckRules" (used for Record Rules management)
         * @type boolean
         */
        doWeHideItByRules : function(agentId) {
                var a = this.getAgent(agentId);
                if (a)
                	return a.hasToBeHiddenByRules;
               	else 
               		return false;
        },
        
        //---
        
    /**
     * @return true if all of the Agents have a stable state
     * @type boolean
     */
	isStable : function() {
		for (var i in this.agents) {
			if (this.agents[i] && !this.agents[i].isStable()) {
				return false;
			}
		}
		return true;
	},

        



        /**
         * Opens a DIV panel to modify a value
         * @param {XMLElement} xeValue Required if not applied to a given record field
         */
        openPanel : function(obj, fieldLabel, xeValue, filter, isHierarchical, idFieldWithSuggestUI, specialPluginFieldId) {
                //Makes the LkTableAgent's panel loose the focus and disappear, on IE8.
                if (!$j.browser.msie || ($j.browser.msie && $j.browser.version < 8))
                        this.setAgentFocus(obj);

                this.getAgentForObj(obj).openPanel(fieldLabel, xeValue, filter, isHierarchical, idFieldWithSuggestUI, specialPluginFieldId);
        },

        setPanelShadow : function(agentId) {
                var a = this.getAgentWithId(agentId);
                if (a && a.listener_setShadow) a.listener_setShadow();},

        /**
         * Opens a DIV panel for the user to log in
         * @param {String} agentId Also corresponds to the id of a HTML element
         */
        openLoginPanel : function(agentId) {
                this.getAgent(agentId).openLoginPanel()},

        /**
         * Called on drop down onChange, checkBox onClick or radio button onClick
         */
        selectValue : function(obj) {
                this.setAgentFocus(obj);
                this.getAgentForObj(obj).submitValue(obj)
        },

        /**
         * Called on drop down onChange, checkBox onClick or radio button onClick.
         * Valid for FKey field type, calls PopupAgent
         */
        openNewRecord : function(obj) {
                this.getAgentForObj(obj).openNewRecord()},

        /**
         * Called by the modifier
         * @deprecated Popup modifier can not use opener vars in HTTPS
         */
        getOutTray : function(winName) {
                return this.getAgentWithWinName(winName).outTray},

        /**
         * Called by the modifier
         * @deprecated Popup modifier can not use opener vars in HTTPS
         */
        setTitleInPopup : function(winName) {
                var a  = this.getAgentWithWinName(winName);
                var pt = a.popupWindow.object('popupTitle');
                pt.innerHTML += a.outTray.fieldLabel;
                a.popupWindow.d.title = toTextOnly(pt.innerHTML)},

        /**
         * Called by popup window
         * @param {String} xml WidgetResult
         */
        processPopupResult : function(xml) {
                var xe = new ParsedXMLElement(xml);
                Manager.getAgentWithId(xe.getAttribute('agentID')).update(xe)},

        /**
         * @return true if there at least one open modifier
         * @type boolean
         */
        hasOpenModifier : function() {
                for (var i in this.agents) {
                        if (this.agents[i].popupWindow && !this.agents[i].isStable()) return true}
                return false},

        /**
         * @return true if at least one agent has an error
         * @type boolean
         */
        hasError : function() {
                for (var i in this.agents) {
                        var em = this.agents[i].errorMsg;
                        if (em!=null && em!='') return true}
                return false},

        /**
         * Submit all pending requests & close all panels/popups
         */
                sendAllRequests : function(pageId) {
                        var ta = this.agents;
                        for (var i in ta) {
                                try {
                                        if (ta[i].onBlur && ta[i].pageId == pageId) 
                                        	ta[i].onBlur();
                                } catch (e) {
//                                      alert(e.description);
                                }

                                try {
                                        if (ta[i].closePopup && ta[i].pageId == pageId) 
                                        	ta[i].closePopup();
                                } catch (e) {
//                                      alert(e.description);
                                }

                                try {
                                        if (ta[i].closePanel && ta[i].pageId == pageId) 
                                        	ta[i].closePanel();
                                } catch (e) {
//                                      alert(e.description);
                                }
                                
                                try {
                                	//if (ta[i].pageId == pageId) 
                                		//delete this.agents[i];
//                                	delete this.agents[i];
                                } catch (e) {
                                	
                                }

                        }},

        /**
         * @return String representing this manager for debugging purposes
         * @type String
         */
        toString : function() {
                var str = 'Manager {';
                for (var id in this.agents) {
                        str += '\n\t' + this.agents[id]}
                return str + '}'}
}


/**
 * An Agent is assigned to a HTML element that is used to trigger modification of a value.
 * Its role is to manage modification of the value. More than one agent can be
 * assigned to a value.
 * It can call this.init(id) initialise the common agent attributes.
 *
 * @class abstract
 */
function Agent() {

        this.space = location.pathname.split('/')[2]; // "/ws/[space]"

        this.DEBUG = false;
        
        this.pageId = null;

        /**
         * Initialises the common agent attributes
         * @param {String} id Given in the following format:
         * [agentPrefix]_[fieldType]_['tFId'|'vFId']_[tableId|viewId]_[recId|'NA']_[fieldId]
         */
        this.init = function(id) {
        		this.pageId = Manager.pageIds[Manager.pageIds.length -1];
        		
                this.id = id;

                var ids = id.split('_');
                this.fieldRef = id.replace(/^[^_]+_/,'');
                this.agentPrefix = ids[0];
                this.fieldType = ids[1];

                if(ids.length <= 7) {
                        this.objectType = (ids[2]=='tFId') ? 'TABLE' : 'VIEW';
                        this.objectPSId = ids[3];
                        this.recId = (ids[4]=='NA') ? null : ids[4];
                        this.fieldId = ids[5];
                        this.mmrId = (ids[6]=='NA') ? null : ids[6];
                } else {
                        this.objectType = (ids[2]=='tFId') ? 'TABLE' : 'VIEW';
                        this.objectPSId = ids[3];
                        this.recId = (ids[4]=='NA') ? null : ids[4];
                        this.fieldId = ids[5];
                        this.mmrId = (ids[6]=='NA') ? null : ids[6];
                        this.mainTable = ids[8];
                        this.blockField = ids[9];
                }
                if (w.LANG_CODE)
                        this.lang = w.LANG_CODE;

                this.doCheckRules = false;//important: used in Record Rules management!
                this.hasToBeHiddenByRules = false;//important: used in Record Rules management!
        }


        this.isInstanceOf = function(typeName) {
                return (w[typeName] && this instanceof w[typeName])},

        /**
         * Can be overwritten if asyncronous requests are made by the agent.
         */
        this.isStable = function() {return true}

        this.hasFocus = function() {
                return (this.id==Manager.focussedAgentId)}

        /**
         * @return {Element} A WidgetResult Element
         */
        this.eWidgetResult = function(xeCommand) {
                return ProgramShop.getResultElement(this.xeWidgetQuery(xeCommand),this.space,this.DEBUG)}
                
		this.eWidgetResultAsync = function(xeCommand, funCallback, pointThis) {
                return ProgramShop.getResultElementAsync(this.xeWidgetQuery(xeCommand),this.space,this.DEBUG, funCallback, pointThis);
        }
                

        /**
         * @return {XMLElement} A WidgetResult XMLElement
         */
        this.xeWidgetResult = function(xeCommand) {
                var xeQuery = this.xeWidgetQuery(xeCommand);
                var space = this.space;
                var trace = this.DEBUG;
                return ProgramShop.getXEResult(xeQuery,space,trace)}

        this.xeWidgetQuery = function(xeCommand) {
                if(typeof(window['WidgetRootNodeQuery']) == 'undefined') {
                        WidgetRootNodeQuery='WidgetQuery';
                }
                var xe = new XMLElement(WidgetRootNodeQuery);
                xe.setAttribute('agentID',this.id);
                xe.setAttribute('lang',this.lang);
                xe.appendChild(xeCommand);
                return xe}

        /**
         * @private
         */

    this.xeSetCommonAttribs = function(xe,withRecId) {
            xe.setAttribute('objectType',this.objectType);
        xe.setAttribute('objectPSId',this.objectPSId);
        if (withRecId==true) {
                if (this.recId)
                        xe.setAttribute('recordId',this.recId);
                if (this.mmrId)
                        xe.setAttribute('mmrId',this.mmrId);
        }
        xe.setAttribute('fieldPSId',this.fieldId);
    }

    this.xeGetChildren = function(tablePSId, recordId, howMuch, offset) {
            var xe = new XMLElement('GetChildren');
            //this.xeSetCommonAttribs(xe);
            xe.setAttribute('tablePSId', tablePSId);
            if (recordId && recordId != '')
                    xe.setAttribute('id', recordId);
            if (howMuch != undefined  && isNumeric(offset) && howMuch > 0)
                    xe.setAttribute('howMuch', howMuch);
            if (offset != undefined && isNumeric(offset))
                    xe.setAttribute('offset', offset);

        return xe;
    }

    this.xeGetPresetDates = function (fieldPSId, objectPSId, objectType) {
            var xe = new XMLElement('GetPresetDates');
            //this.xeSetCommonAttribs(xe);
            xe.setAttribute('fieldPSId', fieldPSId);
            xe.setAttribute('objectPSId', objectPSId);
            xe.setAttribute('objectType', objectType);
            return xe;
    }

    this.xeGetFieldValue = function(args) {
            var xe = new XMLElement('GetFieldValue');
            this.xeSetCommonAttribs(xe,true);
        if (args && args.includeModGUIData==false)
                xe.setAttribute('includeModGUIData','false');
        return xe;
    }

    this.xeGetMMRFieldValue = function(args) {
            var xe = new XMLElement('GetMMRFieldValue');
            this.xeSetCommonAttribs(xe,true);
            if(args && args.includeModGUIData==false) xe.setAttribute('includeModGUIData','false');

            if(this.blockField) xe.setAttribute('blockFieldPSId',this.blockField);
            if(this.mainTable) xe.setAttribute('mainTablePSId',this.mainTable);
        return xe}
    
    this.xeGetExportData = function(args) {
    	var xe = new XMLElement('GetExportData');
        this.xeSetCommonAttribs(xe,true);
        if (args && args.guiType) xe.setAttribute('guiType',args.guiType);
        return xe;
    }


    this.clearValue = function(args) {
            this.xeSetFieldValue("<NullValue/>", args);
    }


    this.xeSetFieldValue = function(xeValue, args) {
            var xe = new XMLElement('SetFieldValue');
            this.xeSetCommonAttribs(xe,true);
        xe.appendChild(xeValue);

        if (args && args.returnHTMLLabel==true)
                xe.setAttribute('returnHTMLLabel','true');

        if (args && args.respectConstraints==false)
                xe.setAttribute('respectConstraints','false');

        return xe;
    }

    this.xeSetMMRFieldValue = function(xeValue,args) {
            var xe = new XMLElement('SetMMRFieldValue');
        this.xeSetCommonAttribs(xe,true);
        xe.appendChild(xeValue);
        if(args) {
                if (args.returnHTMLLabel==true) xe.setAttribute('returnHTMLLabel','true');
                if (args.respectConstraints==false) xe.setAttribute('respectConstraints','false');
                if (args.modificationKind) xe.setAttribute('modificationKind',args.modificationKind);
        }

            if(this.blockField) xe.setAttribute('blockFieldPSId',this.blockField);
            if(this.mainTable) xe.setAttribute('mainTablePSId',this.mainTable);

        return xe}

    this.xeParseFormattedValue = function(txt,args) {
            var xe = new XMLElement('ParseFormattedValue');
                xe.setAttribute('type',this.fieldType);
                new XMLText(txt,xe);
                if (args && args.dateFormat && args.dateFormat=='long') xe.setAttribute('dateFormat','long');
        return xe}

    this.xeGetModGUIData = function(args) {
            var xe = new XMLElement('GetModGUIData');
        this.xeSetCommonAttribs(xe,true);
        if (args && args.guiType) xe.setAttribute('guiType',args.guiType);
        return xe;
    }

    this.xeGetPSValueLabel = function(xeValue,args) {
            var xe = new XMLElement('GetPSValueLabel');
        this.xeSetCommonAttribs(xe);
        xe.appendChild(xeValue);
        if (args && args.dateFormat && args.dateFormat=='long') xe.setAttribute('dateFormat','long');
        return xe}

    /**
         * @param {Element} eWidgetResult Can also be a XMLElement
         * @return {Object} With attributes: label, value, errorMsg
         */
        this.parseWidgetResult = function(eWidgetResult) {
                var label = this.getResultLabel(eWidgetResult);
                var value = this.getResultValue(eWidgetResult);
                var errorMsg = this.getErrorMsg(eWidgetResult);
                return {label:label, value:value, errorMsg:errorMsg}}

        /**
         * Displays error message if not null. Otherwise it hides any existing error message.
         * @param {String} errorMsg
         */
        this.displayErrorMsg = function(errorMsg) {
                this.errorMsg = errorMsg;
                var oDiv = $("error_" + this.fieldRef);
                if (oDiv) {
                        oDiv.innerHTML = (errorMsg) ? errorMsg : '&nbsp;';
                        oDiv.style.display = (errorMsg) ? '' : 'none'}}

        /**
         * @param {Element} eWidgetResult Can also be a XMLElement
         * @return {String} Or null if no message
         */
        this.getErrorMsg = function(eWidgetResult) {
                if (eWidgetResult) {
                        var xesError = eWidgetResult.getElementsByTagName('Error');
                    if (xesError && xesError[0]) {
                            var errorMsg = XMLTools.getChildData(xesError[0]);
                            if (errorMsg!='') return errorMsg}}}

        /**
         * @param {Element} eWidgetResult Can also be a XMLElement
         * @return {String} Or empty string if no label
         */
        this.getResultLabel = function(eWidgetResult) {
                if (eWidgetResult) {
                        var esPSValueLabel = eWidgetResult.getElementsByTagName('PSValueLabel');
                        if (esPSValueLabel && esPSValueLabel[0]) {
                                var resLabel = XMLTools.getChildData(esPSValueLabel[0]);
                            if (resLabel!='') return resLabel;}}
                return ''}

        /**
         * @param {Element} eWidgetResult Can also be a XMLElement
         * @return {Element} A PSValue or null. Is an XMLElement if eWidgetResult is an XMLElement.
         */
        this.getResultValue = function(eWidgetResult) {
                if (eWidgetResult) {
                        var esPSValue = eWidgetResult.getElementsByTagName('PSValue');
                        if (esPSValue && esPSValue[0]) return esPSValue[0].childNodes[0];}}

        this.toString = function() {
                return 'Agent: {id: ' + this.id + '; fieldRef: ' + this.fieldRef + '}'}
}


/**
 * A panel agent is responsible for opening a positioned DIV and managing modification
 * of a value.
 * It must call this.init(id) to initialize the common agent attributes.
 * It must implement this attribute...
 * // this.width
 * It must implement these methods...
 * // this.isStable()
 * // this.openPanel
 * // this.update // implemented in modRec, filter & collection
 * @base Agent
 * @class abstract
 */
function PanelAgent() {

        this.panel = null;
        this.initialWinHeight = null; // set when div is created
        this.SHADOW_OFFSET = 3; // px


	this.getDiv = function() {
		
		// create level modal overlay if it don't exist
		var overlayId = "modal-overlay_" + this.getPanelId();
		var overlay = $(overlayId);
		if (!overlay) {
			overlay = $j("<div id='" + overlayId + "'></div>");
			var slideDivId = "#" + divId;
			var modalWindow = $j(slideDivId);
			
			$j("body").append(overlay);
			overlay.addClass("modal-overlay");
			
			overlay.css("opacity", 0.3);
			overlay.show();
			
			overlay.css("z-index", Manager.zIndexCurrent + 2);
		} 
		
		var divId = this.getPanelId();
		var div = $(divId);
		if (!div) {
			this.initialWinHeight = d.body.scrollHeight;
			div = d.createElement('DIV');
			div.id = divId;
			div.className = 'panel';
			var s = div.style;
			// set DIV style
			var obj = $(this.id);
			s.top = (getAbsPos(obj,'Top')+20) + 'px';
			var x = getAbsPos(obj,'Left') + 6;
			if (x+this.width > d.body.offsetWidth-16) 
				x = d.body.offsetWidth - 16 - this.width;
			
			if (x < 10) 
				x = 10;
			
			s.left = x + 'px';
			s.width = this.width + 'px';
			
			d.body.appendChild(div);
			
			// when you work in this div, add altitude of global variable zIndex in Manager
			$j("#"+divId).css("z-index", Manager.zIndexCurrent+5);
		}
		return div;
	}

	/**
	 * Sets a shadow on the panel DIV if it is displayed & updates position & dimensions.
	 */
	this.listener_setShadow = function() {
		var div = $(this.getPanelId());
		var sDivId = 'shadow_' + this.fieldRef;
		var sDiv = $(sDivId);
		if (!div && !sDiv) return; // failsafe
		// if no panel, remove shadow
		if (!div && sDiv) {
			d.body.removeChild(sDiv);
			return}
		// if panel but no shadow, append shadow
		if (div && !sDiv) {
			var div = this.getDiv();
			sDiv = d.createElement('DIV');
			sDiv.id = sDivId;
			sDiv.className = 'panelShadow';
			d.body.appendChild(sDiv);
			sDiv.innerHTML = '&nbsp;'}
		// mimic panel display
		var ds = div.style, ss = sDiv.style;
		ss.display = ds.display;
		// update position & dimensions
		if (ss.display!='none') {
			ss.left = ( (ds.left && ds.left != "" ? parseInt(ds.left.replace(/px/,''),10) : 0) + this.SHADOW_OFFSET) + 'px';
			ss.top = ( (ds.top && ds.top != "" ? parseInt(ds.top.replace(/px/,''),10) : 0) + this.SHADOW_OFFSET) + 'px';
			ss.width = div.offsetWidth + 'px';
			ss.zIndex = Manager.zIndexCurrent + Manager.SHADOW_OFFSET;
			ss.height = div.offsetHeight + 'px'}
		// continue listening
		setTimeout('Manager.setPanelShadow("'+this.id+'")',20);
	}

        this.setDivTop = function() {
                var div = this.getDiv();
                var divChildren = div.childNodes;
                var divHeight = 0;
                for (var i=0; i<divChildren.length; i++) {
                        divHeight += divChildren[i].offsetHeight}
                var maxTop = this.initialWinHeight - divHeight;
                if (maxTop<0)
                        maxTop = 0;

                if (parseInt(div.style.top.replace(/px/,''),10) > maxTop)
                        div.style.top = maxTop + 'px';
        }

        /**
         * Sets a shadow on the panel DIV if it is displayed & updates position & dimensions.
         */
        this.listener_setShadow = function() {
                var div = $(this.getPanelId());
                var sDivId = 'shadow_' + this.fieldRef;
                var sDiv = $(sDivId);
                if (!div && !sDiv) return; // failsafe
                // if no panel, remove shadow
                if (!div && sDiv) {
                        d.body.removeChild(sDiv);
                        return}
                // if panel but no shadow, append shadow
                if (div && !sDiv) {
                        var div = this.getDiv();
                        sDiv = d.createElement('DIV');
                        sDiv.id = sDivId;
                        sDiv.className = 'panelShadow';
                        d.body.appendChild(sDiv);
                        sDiv.innerHTML = '&nbsp;'}
                // mimic panel display
                var ds = div.style, ss = sDiv.style;
                ss.display = ds.display;
                // update position & dimensions
                if (ss.display!='none') {
                        ss.left = ( (ds.left && ds.left != "" ? parseInt(ds.left.replace(/px/,''),10) : 0) + this.SHADOW_OFFSET) + 'px';
                        ss.top = ( (ds.top && ds.top != "" ? parseInt(ds.top.replace(/px/,''),10) : 0) + this.SHADOW_OFFSET) + 'px';
                        ss.width = div.offsetWidth + 'px';
                        ss.height = div.offsetHeight + 'px'}
                // continue listening
                setTimeout('Manager.setPanelShadow("'+this.id+'")',20);
        }

        /**
         * if IE6 or earlier, hides the SELECT elements that are not children of the DIV element.
         * If no argument is given, shows all of the SELECT elements.
         * @argument {Object} div DIV element
         */
        this.toggleSelectObjs = function(div) {
                if (w.XMLHttpRequest) return; // return if IE7+ or not IE
                var oSelects = d.getElementsByTagName('SELECT');
                if (oSelects) {
                        for (i=0; i<oSelects.length; i++) {
                                var oSlt = oSelects[i];
                                var oLabel = $('ddLabel_'+oSlt.name);
                                var isInDiv = false;
                                var oParent = oSlt;
                                while (oParent) {
                                        if (oParent==div) {isInDiv = true; break}
                                        oParent = oParent.parentNode}
                                if (!isInDiv) {
                                        if (div) { // if the div arg was given
                                                oSlt.style.display = 'none';
                                                var selText = oSlt.options[oSlt.selectedIndex].text;
                                                if (oLabel) {
                                                        oLabel.innerHTML = selText;
                                                        oLabel.style.display = ''}
                                                else oSlt.parentNode.innerHTML = '<span id="ddLabel_'+oSlt.name
                                                        +'" class="selectReplace">'+selText+'</span>' + oSlt.parentNode.innerHTML;}
                                        else { // show SELECT
                                                oSlt.style.display = '';
                                                if (oLabel) oLabel.style.display = 'none';}}}}}

        /**
     * @param {Element | XMLElement} xe Contains child elems with 'code' attributes
     * @return {Object} Map of given 'code' attributes to corresponding child data
     */
    this.getMap = function(xe) { // xe contains child elems with 'code' attributes
            var map = {};
            if (xe) {
                    var cn = xe.childNodes;
                    if (cn) {
                            for (var i=0; i<cn.length; i++) {
                                    var value = (cn[i].firstChild) ? cn[i].firstChild.data : cn[i].getChildData();
                                    map[cn[i].getAttribute('code')] = value}}}
            return map}


    this.clearValue = function() {
            this.submitValue("<NullValue/>");
    }

    this.submitValue = function(xmlValue, returnHTMLLabel) {
            //CheckRule Management:
            var Agent = Manager.getAgent(this.id);
            var doCheckRules = Manager.doWeCheckRules(this.id);
            var hasToBeHiddenByRules = Manager.doWeHideItByRules(this.id);
            var doUpdate = true;
            var previousValue = null;
            //---

            if (this.recId) { //to avoid a "WidgetQuery/GetFieldValue" with a recId "null" (in filter.js for example)
                    var xeCommand = Agent.xeGetFieldValue();
                    var xeWidgetResult = Agent.xeWidgetResult(xeCommand);
                    var xePSValue = xeWidgetResult ? xeWidgetResult.getElementsByTagName('PSValue') : null;
                    previousValue = xePSValue && xePSValue != "" ? xeWidgetResult.getElementsByTagName('PSValue')[0].childNodes[0] : null;
            }

            //See XML.js and added String Prototype functions (for "equalsXML"):
            if ( (previousValue == null && xmlValue == null) ||
                            (previousValue != null && xmlValue != null && xmlValue.toString().equalsXML(previousValue.toString()) )) {

                    doUpdate = false;
            }

            if (doUpdate) {
                    var doIt = true;

                    if (doCheckRules && previousValue != null)
                            doIt = alertBeforeChange();//Is the user really sure ?

                    if (doIt) {
                            if(typeof(window['WidgetRootNodeQuery']) == 'undefined') {
                                    WidgetRootNodeQuery='WidgetQuery';
                            }

                            var xeWidgetQuery = new XMLElement(WidgetRootNodeQuery);
                            xeWidgetQuery.setAttribute('agentID',this.id);
                            xeWidgetQuery.setAttribute('lang',this.lang);

                            if (this.recId) {
                                    var xeSetFieldValue = new XMLElement('SetFieldValue',xeWidgetQuery);
                                    xeSetFieldValue.setAttribute('objectType',this.objectType);
                                    xeSetFieldValue.setAttribute('objectPSId',this.objectPSId);
                                    xeSetFieldValue.setAttribute('recordId',this.recId);
                                    xeSetFieldValue.setAttribute('fieldPSId',this.fieldId);
                                    if (returnHTMLLabel)
                                            xeSetFieldValue.setAttribute('returnHTMLLabel','true');
                                    new ParsedXMLElement(xmlValue,xeSetFieldValue);
                            } else if (this.mmrId) {
                                    var xeSetFieldValue = new XMLElement('SetMMRFieldValue',xeWidgetQuery);
                                    xeSetFieldValue.setAttribute('objectType',this.objectType);
                                    xeSetFieldValue.setAttribute('objectPSId',this.objectPSId);
                                    xeSetFieldValue.setAttribute('fieldPSId',this.fieldId);
                                    xeSetFieldValue.setAttribute('mmrId',this.mmrId);
                                    if(this.blockField) xeSetFieldValue.setAttribute('blockFieldPSId',this.blockField);
                                    if(this.mainTable) xeSetFieldValue.setAttribute('mainTablePSId',this.mainTable);
                                    if (returnHTMLLabel)
                                            xeSetFieldValue.setAttribute('returnHTMLLabel','true');

                                    new ParsedXMLElement(xmlValue,xeSetFieldValue);
                            } else {
                                    var xeGetPSValueLabel = new XMLElement('GetPSValueLabel',xeWidgetQuery);
                                    xeGetPSValueLabel.setAttribute('objectType',this.objectType);
                                    xeGetPSValueLabel.setAttribute('objectPSId',this.objectPSId);
                                    xeGetPSValueLabel.setAttribute('fieldPSId',this.fieldId);
                                    if (returnHTMLLabel) {
                                            xeGetPSValueLabel.setAttribute('returnHTMLLabel','true');
                                    }

                                    new ParsedXMLElement(xmlValue,xeGetPSValueLabel);
                            }

                            var xeWidgetResult = ProgramShop.getXEResult(xeWidgetQuery, this.space, this.DEBUG);

                            // show error or close panel
                            var xeError = xeWidgetResult.getChild('Error');
                            var errorMsg = (xeError) ? xeError.getChildData() : null;
                            if (errorMsg && /^ +$/.test(errorMsg))
                                errorMsg = null;

                            if (errorMsg != null && this.panel != undefined) {
                                this.panel.errorMsg = errorMsg;
                                this.displayPanel();
                            } else {
                            	//No error ? Great, so update the widget and its field...:
                                this.update(xeWidgetResult);
                                
                                //... then do check all the rules if needed...:
                                if (doCheckRules && !hasToBeHiddenByRules) {
                                    //Will check the rules and "nullify" all values which have to be hidden
                                    checkAllRulesAndFieldValues();
                                }

                                //... and finally, close the panel:
                                this.closePanel();
                            }
                    }
            }
    }

    this.getPanelId = function() {
		return 'panel_' + this.fieldRef;
	}

        this.displayPanel = function() {
                var div = this.getDiv();
                div.innerHTML = this.panel.toHTML();

                var whichId = this.getPanelId();
                var oPanel = $(this.getPanelId());

                if (oPanel) {
                        //To open or re-open the panel, smoothly:
                        $j(oPanel).fadeIn("fast",
                                        function () {
                                if (oPanel) {
                                        d.getElementById(whichId).style.display = 'block';
                                        
                                        // show level modal overlay
                                        var overlayId = "modal-overlay_" + whichId;
                                		var overlay = $j("#"+overlayId);
                                		overlay.show();
                                }
                    });
                }

                this.toggleSelectObjs(div);
                this.listener_setShadow();
                //if (isPopup())
                //        resizePopup({overrideMax: true, minWidth: 40 + this.width});
        }

	this.closePanel = function(id) {
		var whichId;

        if (id != undefined)
                 whichId = id;
        else
                whichId = this.getPanelId();


        var oPanel = $(this.getPanelId());

        if (oPanel) {
                //No more removed, just not displayed : OK for all widget type (lkTable and suggest included)
                $j(oPanel).fadeOut("fast",
                                function () {
                                        if (oPanel) {
                                                d.getElementById(whichId).style.display = 'none';
                                                //d.body.removeChild(oPanel);
                                                
                                                //hide level modal overlay
                                                var overlayId = "modal-overlay_" + whichId;
                                            	$j("#"+ overlayId).css("display", "none");
                                        }
                            });

                var o = $(this.id);
                if (o) o.focus();
        }

        this.toggleSelectObjs();
    	
        this.panel = null;
	}

    this.onBlur = function() {
    	this.closePanel();
    }

    this.toString = function() {
    	return 'PanelAgent: {id: ' + this.id + '; fieldRef: ' + this.fieldRef + '}';
    }
}

PanelAgent.prototype = new Agent();


/**
 * A login panel agent can display a panel for the user to log in, if required.
 * It must call this.init(id) to initialize the common agent attributes.
 * It must implement these methods...
 * // this.update // implemented in modRec, filter & collection
 * // this.onLogin // implemented in modRec, filter & collection
 * @base PanelAgent
 * @class abstract
 */
function LoginPanelAgent() {

        this.width = 320;

        this.initLoginPanel = function(eGUI) {
                if (!eGUI) {
                        var eWidgetResult = this.eWidgetResult(this.xeGetModGUIData());
                        eGUI = eWidgetResult.getElementsByTagName('ModGUIData')[0].childNodes[0]}
                var hrefNewUser = eGUI.getAttribute('hrefNewUser');
            var hrefForgotPass = eGUI.getAttribute('hrefForgotPass');
            var guiLabels = this.getMap(eGUI.getElementsByTagName('GUILabels')[0]);
                var colorIconDir = eGUI.getAttribute('colorIconDir');
                this.panel = new LoginPanel(this.id,hrefNewUser,hrefForgotPass,guiLabels,colorIconDir)}

        this.openLoginPanel = function() {
                if (!this.panel) this.initLoginPanel();
                this.displayPanel();
                this.panel.setFocus()}

        this.login = function() {

                var xeSessionQuery = new XMLElement('SessionQuery');
                var xeIdentifySession = new XMLElement('IdentifySession',xeSessionQuery);
                xeIdentifySession.setAttribute('pwd',this.panel.getPassword());
                xeIdentifySession.setAttribute('username',this.panel.getUserName());

                var xeSessionResult = ProgramShop.getResult(xeSessionQuery,this.space,this.DEBUG);
                var xeResult = xeSessionResult.childNodes[0];

                var errorMsg = this.panel.guiLabels.errorSystem; // until proven otherwise

                if (xeResult.tagName=='PlatformSession') {
                        errorMsg = this.panel.guiLabels.errorNotMember; // until proven otherwise
                        var xeMemberInfo = xeResult.getChild('MemberInfo');
                        if (xeMemberInfo) errorMsg = null;}
                else if (xeResult.tagName=='Report') {
                        var xeReportEntry = xeResult.getChild('ReportEntry');
                        if (xeReportEntry) {
                                var msg = xeReportEntry.getAttribute('msg');
                                if (msg) errorMsg = msg;}}

                if (errorMsg) this.panel.showError(errorMsg); // show error message
                else {
                        this.closePanel();
                        this.panel = null; // then continue the process...
                        this.onLogin()}}
}

LoginPanelAgent.prototype = new PanelAgent();


/**
 * Panel GUI object if user is required to login
 */
function LoginPanel(agentId,hrefNewUser,hrefForgotPass,guiLabels,colorIconDir) {

        this.agentId = agentId;
        this.hrefNewUser = hrefNewUser;
        this.hrefForgotPass = hrefForgotPass;
        this.guiLabels = guiLabels;
        this.colorIconDir = colorIconDir;

        this.getUserName = function() {
                return $('username').value}

        this.getPassword = function() {
                return $('password').value}

        this.showError = function(msg) {
                var oMsg = $('loginErrorMsg');
                oMsg.innerHTML = '<div class="perror">'+msg+'</div>';
                oMsg.parentNode.style.display = ''}

        /**
         * @param {String} mgr Alternative path to Manager, ie, "parent.Manager"
         */
        this.toHTML = function(mgr) {

                if (!mgr) mgr = 'Manager';
                var agent = mgr + ".getAgentWithId(\'"+this.agentId+"\')";

                var html = '<table class="wide ptable">'
                + '<tr>'
                + '<td class="ptitbar" onMouseDown="DragAndDrop.start(this,event); return false">'
                        + '<table class="wide" summary="'
                        + this.guiLabels.titleBar+'">'
                        + '<tr>'
                        + '<td>'+this.guiLabels.login+'</td>'
                        + '<td align="right" valign="top"><input type="image" onClick="'+agent+'.closePanel()" '
                        + 'src="'+this.colorIconDir+'bt_close_11.gif" class="bt11" tabIndex="1" '
                        + 'alt="'+this.guiLabels.close+'"></td>'
                        + '</tr>'
                        + '</table>'
                + '</td>'
                + '</tr>'
                + '<tr>'
                + '<td align="center" class="login">'
                        + '<table>'
                        + '<tr>'
                        + '<td align="right">'+this.guiLabels.username+'</td>'
                        + '<td><input id="username" type="text" tabIndex="2" '
                        + 'onKeyPress="if (event.keyCode==13) {'+agent+'.login(); return false}"></td>'
                        + '<td>&nbsp;</td>'
                        + '</tr>'
                        + '<tr>'
                        + '<td align="right">'+this.guiLabels.password+'</td>'
                        + '<td><input id="password" type="password" tabIndex="3" '
                        + 'onKeyPress="if (event.keyCode==13) {'+agent+'.login(); return false}"></td>'
                        + '<td><input type="image" onClick="'+agent+'.login()" src="/rsrc/img/bt_right.gif" '
                        + 'class="bt11" alt="'+this.guiLabels.submit+'" tabIndex="4"></td>'
                        + '</tr>'
                        + '<tr style="display: none">'
                        + '<td>&nbsp;</td>'
                        + '<td colspan="2" id="loginErrorMsg">&nbsp;</td>'
                        + '</tr>'
                        + '<tr>'
                        + '<td>&nbsp;</td>'
                        + '<td align="right"><a href="'+this.hrefNewUser+'" tabIndex="-1">'+this.guiLabels.newUser+'</a></td>'
                        + '<td><a href="'+this.hrefNewUser+'" tabIndex="5">'
                        + '<img src="/rsrc/img/bt_right.gif" class="bt11" alt="'+this.guiLabels.subscribe+'">'
                        + '</a></td>'
                        + '</tr>'
                        + '<tr>'
                        + '<td>&nbsp;</td>'
                        + '<td align="right"><a href="'+this.hrefForgotPass+'" target="_blank" tabIndex="-1">'
                        + this.guiLabels.forgotPass+'</a></td>'
                        + '<td><a href="'+this.hrefForgotPass+'" target="_blank" tabIndex="6">'
                        + '<img src="/rsrc/img/bt_right.gif" class="bt11" alt="'+this.guiLabels.getPass+'"></a></td>'
                        + '</tr>'
                        + '</table>'
                + '</td>'
                + '</tr>'
                + '</table>';
                return html}

        this.setFocus = function() {
                $('username').focus()}
}

DragAndDrop = {

        div : null, // obj
        shadowDiv : null, // optional shadow (obj)
        shadowOffset : 3, // px
        offset : null, // {x,y}
        mousePos : null, // {x,y}

        start : function(obj,e) { // e = event
                if (!e) e = w.event;
                // climb tree to panel div
                var rePanel = /^panel_/;
                while (obj && !rePanel.test(obj.id)) obj = obj.parentNode;
                if (!obj) return; // failsafe
                this.div = obj;
                // also set shadow div
                this.shadowDiv = $(this.div.id.replace(rePanel,'shadow_'));
                // calculate offset of mouse from div
                this.setMousePos(e);
                var x = getAbsPos(this.div,'Left') - this.mousePos.x;
                var y = getAbsPos(this.div,'Top') - this.mousePos.y;
                this.offset = {x:x, y:y}
                // set doc actions
                d.onmousemove = this.setMousePos;
                d.onmouseup = this.end;
                // prevent text selection in IE
                d.onselectstart = function () { return false; };
                // change mouse pointer
                d.body.style.cursor = 'move';
                // start listener
                this.listener_updateDivPos()},

        end : function() {
                d.onmousemove = null;
                d.body.style.cursor = 'auto';
                DragAndDrop.div = null;
                DragAndDrop.shadowDiv = null},

        setMousePos : function(e) { // e = event
                if (!e) var e = w.event;
                var x, y;
                if (e.pageX) {
                        x = e.pageX;
                        y = e.pageY}
                else if (e.clientX) {
                        x = e.clientX + d.body.scrollLeft + d.documentElement.scrollLeft;
                        y = e.clientY + d.body.scrollTop + d.documentElement.scrollTop}
                DragAndDrop.mousePos = {x:x, y:y}},

        listener_updateDivPos : function() {
                if (d.onmousemove) {
                        var x = this.mousePos.x + this.offset.x;
                        var y = this.mousePos.y + this.offset.y;
                        if (x<0) x = 0;
                        if (y<0) y = 0;
                        var ds = this.div.style;
                        var ss = (this.shadowDiv) ? this.shadowDiv.style : null;
                        if (isFinite(x)) {
                                ds.left = x + 'px';
                                if (ss) ss.left = (x+this.shadowOffset) + 'px'}
                        if (isFinite(y)) {
                                ds.top = y + 'px';
                                if (ss) ss.top = (y+this.shadowOffset) + 'px'}
                        setTimeout('DragAndDrop.listener_updateDivPos()',50)}}
}

