//*********************************
// This script requires :
// > HTTP.js
// > XML.js
// > global.js

/**
 * The role of the Manager is to oversee & set the work its Agents
 */
Manager = {

	SHADOW_OFFSET : 3, // px

	agents : new Object(), // maps agentId to Agent
	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];

		switch (fieldType) {
			case 'Bool' : return new CheckBoxAgent(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);
					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);
					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 '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)}}},

	/**
	 * 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+'_'+getKey()},

	/**
	 * Adds the agent if it doesn't exist and triggers the blur & focus events for all existing agents
	 */
	setAgentFocus : function(obj) {
		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) a.onFocus();}, // use onFocus action on new focussed agent

	/**
	 * @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].isStable()) return false;}
		return true},

	/**
	 * 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) {
		this.getAgentForObj(obj).openPopup(href);
		this.setAgentFocus(obj)},

	/**
	 * 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) {
		this.setAgentFocus(obj);
		this.getAgentForObj(obj).openPanel(fieldLabel,xeValue)},

	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() {
		var ta = this.agents;
		for (var i in ta) {
			if (ta[i].onBlur) ta[i].onBlur();
			if (ta[i].closePopup) ta[i].closePopup();
			if (ta[i].closePanel) ta[i].closePanel();}},

	/**
	 * @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;

	/**
	 * 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.id = id;
		var ids = id.split('_');
		this.fieldRef = id.replace(/^[^_]+_/,'');
		this.agentPrefix = ids[0];
		this.fieldType = ids[1];
		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];
		if (w.LANG_CODE) this.lang = w.LANG_CODE;}



	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)}

	/**
	 * @return {XMLElement} A WidgetResult XMLElement
	 */
	this.xeWidgetResult = function(xeCommand) {
		return ProgramShop.getXEResult(this.xeWidgetQuery(xeCommand),this.space,this.DEBUG)}

	this.xeWidgetQuery = function(xeCommand) {
		var xe = new XMLElement('WidgetQuery');
        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.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');
        return xe}

    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 && args.returnHTMLLabel==true) xe.setAttribute('returnHTMLLabel','true');
        if (args && args.respectConstraints==false) xe.setAttribute('respectConstraints','false');
        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 initialise 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() {
		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)}
		return div}

	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 = (parseInt(ds.left.replace(/px/,''),10) + this.SHADOW_OFFSET) + 'px';
			ss.top = (parseInt(ds.top.replace(/px/,''),10) + 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.submitValue = function(xmlValue,returnHTMLLabel) {

    	var xeWidgetQuery = new XMLElement('WidgetQuery');
        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 (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);
        this.update(xeWidgetResult);

        // show error or close panel
        var xeError = xeWidgetResult.getChild('Error');
		var errorMsg = (xeError) ? xeError.getChildData() : null;
		if (errorMsg && /^ +$/.test(errorMsg)) errorMsg = null;
        if (errorMsg) {
        	this.panel.errorMsg = errorMsg;
			this.displayPanel()}
        else this.closePanel();}

    this.getPanelId = function() {
		return 'panel_' + this.fieldRef}

	this.displayPanel = function() {
		var div = this.getDiv();
		div.innerHTML = this.panel.toHTML();
		this.toggleSelectObjs(div);
		this.listener_setShadow();
		if (isPopup()) resizePopup({overrideMax: true, minWidth: 40 + this.width});}

	this.closePanel = function() {
		var oPanel = $(this.getPanelId());
		if (oPanel) {
			d.body.removeChild(oPanel);
			$(this.id).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 initialise 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)}}
}


