
var EditableTableManager = new function()
{
	var rgTables = new Array();
	var sTableBeingDragged = "";
	
	this.hideAllPanes = function()
	{
		for (var sKey in rgTables)
		{
			if (rgTables[sKey] && rgTables[sKey].hidePane) rgTables[sKey].hidePane();
		}
	}
	
	this.hidePane = function(sTableName)
	{
		this.create(sTableName);
		rgTables[sTableName].hidePane();
	}
	
	this.isVisible = function()
	{
		for (var sKey in rgTables)
		{
			if (rgTables[sKey] && rgTables[sKey].isVisible && rgTables[sKey].isVisible())
				return true;
		}
		return false;
	}
	
	this.setShadow = function(sTableName)
	{
		this.create(sTableName);
		rgTables[sTableName].setShadow();
	}
	
	this.showDeletePane = function(sTableName, oElem, ixToDelete, sToDelete)
	{
		this.create(sTableName);
		rgTables[sTableName].showDeletePane(oElem, ixToDelete, sToDelete);
	}
	
	this.showDetailedDeletePane = function(sTableName, oElem, ixToDelete, sInfo1, sInfo2, sInfo3)
	{
		this.create(sTableName);
		rgTables[sTableName].showDetailedDeletePane(oElem, ixToDelete, sInfo1, sInfo2, sInfo3);
	}
	
	this.showEditPane = function(sTableName, oElem, mapValsToElems)
	{
		this.create(sTableName);
		rgTables[sTableName].showEditPane(oElem, mapValsToElems);
	}
	
	this.disablePaneForSubmit = function(sTableName)
	{
		this.create(sTableName);
		rgTables[sTableName].startSubmit();
		rgTables[sTableName].enablePane(false);
	}
	
	this.result = function(sTableName, oXML, sIdContainer)
	{
		this.create(sTableName);
		rgTables[sTableName].result(oXML, sIdContainer);
	}
	
	this.mousedownTopBar = function(sTableName)
	{
		this.create(sTableName);
		rgTables[sTableName].startDragging();
		sTableBeingDragged = sTableName;
	}
	
	this.stopDragging = function()
	{
		if (sTableBeingDragged && sTableBeingDragged.length)
		{
			this.create(sTableBeingDragged);
			rgTables[sTableBeingDragged].stopDragging();
			sTableBeingDragged = "";
		}
	}
	
	this.notifyMovement = function()
	{
		if (!sTableBeingDragged || !sTableBeingDragged.length) return;
		this.create(sTableBeingDragged);
		rgTables[sTableBeingDragged].notifyMovement();
	}
	
	this.setFocus = function(sTableName)
	{
		this.create(sTableName);
		rgTables[sTableName].setFocus();
	}
	
	this.enablePane = function(sTableName, bEnable)
	{
		this.create(sTableName);
		rgTables[sTableName].enablePane(bEnable);
	}
	
	this.create = function(sTableName)
	{
		if (!rgTables[sTableName])
			rgTables[sTableName] = new EditableTable(sTableName);
		rgTables[sTableName].init();	
	}
}

function EditableTable(sName)
{
	var oTable = elById('static'+sName);
	var oPane = elById('edit'+sName);
	var oMask = elById("panemask" + sName + maskType());
	
	var oDelete = XMLParser.getNodeUsingIdFrom(oPane, "div", "delete");
	var oEditable = XMLParser.getNodeUsingIdFrom(oPane, "div", "editable");
	var oError = XMLParser.getNodeUsingIdFrom(oPane, "div", "error");
	
	var rgErrorsShown = new Array();
	
	var pxLeftCurrent;
	var pxTopCurrent;
	var bPositioned = false;
	var bShadowAdded = false;
	var bShrunk = false;
	var bDragging = false;
	var pxLeftDragOffset;
	var pxTopDragOffset;
	var bVisible = false;

	this.init = function()
	{
		oPane = elById('edit'+sName);

		// We need to make sure that this is the same object that we initialized
		// in the first place, b/c our ajax view/edit page swaps may have replaced
		// some of the nodes (case 288101)
		//
		if (!oPane.bInitialized)
		{
			oTable = elById('static'+sName);
			oMask = elById("panemask" + sName + maskType());
		
			oDelete = XMLParser.getNodeUsingIdFrom(oPane, "div", "delete");
			oEditable = XMLParser.getNodeUsingIdFrom(oPane, "div", "editable");
			oError = XMLParser.getNodeUsingIdFrom(oPane, "div", "error");
	
			rgErrorsShown = new Array();
		
			// EditableTable initialization
			if (oPane)
			{	
				var oTextArea = XMLParser.getNodeFrom(oPane, "textarea");
				var pxMin = oTextArea ? 450 : 350;
				
				var pxWidth;
				var oWidthSpan = XMLParser.getNodeUsingIdFrom(oPane, "span", "pxWidthTable");
				if (oWidthSpan) pxWidth = oWidthSpan.innerHTML;
				if (pxWidth != null)
				{
					if (pxWidth != 0)
						oPane.style.width = pxWidth + "px";
					else
						oPane.style.width = pxMin + "px";
				}
				else
				{
					oPane.style.width = (oTable ? Math.max(oTable.offsetWidth,pxMin) : pxMin) + "px";
				}
				
				if (window.opera)
				{
					// Opera won't support our transparent dropshadows, so give it a border
					oPane.style.border = "1px solid #333333";
				}
			}

			oPane.bInitialized = true;
		}
	}	

	this.result = function(oXML, sIdContainer)
	{
		Info.hide();
		this.enablePane(true);
		if (!this.parseAndShowErrors(oXML))
		{
			// Success
			var oContainer = elById(sIdContainer ? sIdContainer : "container"+sName);
			var sHTML = XMLParser.getCDataFrom(oXML, "sHTML");
			if (oContainer && sHTML) oContainer.innerHTML = sHTML;
			oTable = elById('static'+sName);
			if (!this.parseAndShowWarning(oXML))
			{
				// no warnings or errors: Success.
				this.hidePane();
			}
			else
			{
				// warnings returned from server
				this.doSetShadow();
			}
			this.yellowFade(XMLParser.getTextFrom(oXML, "idEditableRow"));
			oElemLastSrc = null;

			//We changed the table, so we'd better clean up the old KB Nav
			KeyManager.cleanupOnClick(); 
			KeyManager.setupGridBrowser();
		}
		else
		{
			// errors returned from server
			this.doSetShadow();
		}
	}
	
	this.isVisible = function()
	{
		return bVisible;
	}
	
	this.yellowFade = function( idRow )
	{
		YFTManager.hideYellow(sName);
		var sId = sName + "_" + idRow;
		var oRow = elById(sId);
		if (oRow) YFTManager.showYellow(sName, oRow);
	}
	
	this.parseAndShowWarning = function(oXML)
	{
		var sWarning = XMLParser.getTextFrom(oXML, "sWarning");
		if (sWarning && sWarning.length)
		{
			this.showErrorPane(sWarning);
			this.setFocus();
			return true;
		}
		return false;
	}
	
	this.parseAndShowErrors = function(oXML)
	{
		this.hideAllErrors();
		var rgErrors = XMLParser.getNodeArrayFrom(oXML, "Error");
		var sError, sId, bShowingError, bFocusSet;
		bShowingError = false;
		bFocusSet = false;
		
		for (var ix = 0; ix < rgErrors.length; ix++)
		{
			sError = XMLParser.getTextFrom(rgErrors[ix], "sError");
			sId = XMLParser.getTextFrom(rgErrors[ix], "sId");
			if (sError && sId)
			{
				this.showErrorElement(sError, sId);
				bShowingError = true;
				if (!bFocusSet)
				{
					// Try to focus the first input element w/ an error
					var oElem = XMLParser.getNodeUsingIdFrom(oPane, "input", sId);
					if (oElem)
						try{safeFocus(oElem); bFocusSet = true;} catch(err){};
				}
			}
		}
		
		if (!bFocusSet) this.setFocus();
		return bShowingError;
	}
	
	this.showErrorElement = function(sError, sId)
	{
		var oElem = XMLParser.getNodeUsingIdFrom(oPane, "input", sId);
		var oDesc = XMLParser.getNodeUsingIdFrom(oPane, "div", "error_"+sId);
		
		if (oElem && oElem.className == "dlg") oElem.className = "dlgError";
		if (oDesc)
		{
			oDesc.innerHTML = sError;
			oDesc.style.display = "";
		}
		rgErrorsShown[rgErrorsShown.length] = sId;
	}
	
	this.hideErrorElement = function(sId)
	{
		var oElem = XMLParser.getNodeUsingIdFrom(oPane, "input", sId);
		var oDesc = XMLParser.getNodeUsingIdFrom(oPane, "div", "error_"+sId);
		if (oElem && oElem.className == "dlgError") oElem.className = "dlg";
		if (oDesc) oDesc.style.display = "none";
	}
	
	this.hideAllErrors = function(sId)
	{
		if (!rgErrorsShown) return;
		for (var ix = 0; ix < rgErrorsShown.length; ix++)
		{
			this.hideErrorElement(rgErrorsShown[ix]);
		}
		rgErrorsShown = new Array();
	}
	
	this.enablePane = function(bEnabled)
	{
		if (!oPane) return;
		
		var rgToDisable = XMLParser.getNodeArrayFrom(oPane, "input");
		for (var ix = 0; ix < rgToDisable.length; ix++)
		{
			rgToDisable[ix].disabled = !bEnabled;
		}
		
		rgToDisable = XMLParser.getNodeArrayFrom(oPane, "textarea");
		for (var ix = 0; ix < rgToDisable.length; ix++)
		{
			rgToDisable[ix].disabled = !bEnabled;
		}
	}
	
	this.startSubmit = function()
	{
		Process.start(this, "result", null, Lang.getString("FB_SUBMITTING"), oPane.id, null);
	}
	
	this.hidePane = function()
	{
		bVisible = false;
		if (!oPane) return;
		
		this.hideAllErrors();
		this.stopDragging();
		theMgr.hideAllPopups();
		if (oMask) oMask.style.display = "none";
		
		this.repairPageFocus();
		KeyManager.removePopupKeys();
		FadeManager.startFadeOut(sName, oPane, this.hideShadow);
	}
	
	this.repairPageFocus = function()
	{
		var rgInput = XMLParser.getNodeArrayFrom(oPane, "input");
		var oToFocus = null;
		for (var ix = 0; ix < rgInput.length; ix++)
		{
			if (rgInput[ix].type.toLowerCase() != "hidden")
			{
				oToFocus = rgInput[ix];
				break;
			}
		}
		if (oToFocus && oToFocus.focus)
		{
			try {safeFocus(oToFocus); oToFocus.blur();}
			catch (err) {}
		}
	}
	
	this.setPaneState = function(sState)
	{
		if (oDelete)	oDelete.style.display = (sState == "delete") ? "" : "none";
		if (oEditable)	oEditable.style.display = (sState == "editable") ? "" : "none";
		if (oError)		oError.style.display = (sState == "error") ? "" : "none";
		
		if (!oMask) return;
		
		if (sState == "delete" || sState == "editable" || sState == "error")
		{
			oMask.style.top = "0px";
			oMask.style.left = "0px";
			oMask.style.width = documentWidth() + 'px';
			oMask.style.height = documentHeight() + 'px';
			oMask.style.display = "";
		}
		else
		{
			oMask.style.display = "none";
		}
	}
	
	this.showErrorPane = function(sError)
	{
		if (!oPane) return;
		
		var oSpan = XMLParser.getNodeUsingIdFrom(oPane, "span", "mainErrorContainer");
		if (oSpan) oSpan.innerHTML = sError;
		
		this.setPaneState("error");
		this.setFocus();
	}
	
	this.showDeletePane = function(oElem, ixToDelete, sToDelete)
	{
		if (!oPane) return;
		theMgr.hideSelects();
		this.fadeIn(false);
		this.setPaneState("delete");
		this.setPaneLoc(oElem);
		var oDiv = XMLParser.getNodeUsingIdFrom(oPane, "div", "delete");
		var oSpan = XMLParser.getNodeUsingIdFrom(oPane, "span", "sToDelete");
		if (oSpan) oSpan.innerHTML = encodeLTGT(sToDelete);
		var oToDelete = XMLParser.getNodeUsingIdFrom(oPane, "input", "ixToDelete");
		oToDelete.value = ixToDelete;
		this.setFocus();
	}
	
	this.fadeIn = function(bFocusDuringFade)
	{
		bShadowAdded = false;
		bPositioned = false;
		bVisible = true;

		// case 281806 - remove click mask and stop keyboard browsing
		KeyManager.cleanupOnClick(); 
		this.registerHotKeys();

		if (bFocusDuringFade)
		{
			FadeManager.startFadeIn(sName, oPane, null, true, 
				new Function("", 
					"EditableTableManager.enablePane('" + sName + "', true); EditableTableManager.setFocus('" + sName + "'); EditableTableManager.setShadow('" + sName + "');"));
		}
		else
		{
			FadeManager.startFadeIn(sName, oPane, null, true, this.setShadow);
		}
	}

	this.registerHotKeys = function()
	{
		var rgInput = XMLParser.getNodeArrayFrom(oPane, "input");
		for (var ix = 0; ix < rgInput.length; ix++)
		{
			var cKey = rgInput[ix].getAttribute("cHotKey");
			if (cKey)
			{
				KeyManager.registerPopupKey(cKey, rgInput[ix].id);
			}
		}
	}
	
	this.setShadow = function()
	{
		if (!bPositioned || bShadowAdded || oPane.style.display == "none") return;
		ShadowManager.applyShadow(sName, pxLeftCurrent, pxTopCurrent, oPane);
		bShadowAdded = true;
	}
	
	this.doSetShadow = function()
	{
		ShadowManager.applyShadow(sName, pxLeftCurrent, pxTopCurrent, oPane);
	}
	
	this.hideShadow = function()
	{
		ShadowManager.hideShadow(sName);
	}
	
	this.showDetailedDeletePane = function(oElem, ixToDelete, sInfo1, sInfo2, sInfo3)
	{
		if (!oPane) return;
		theMgr.hideSelects();
		this.fadeIn(false);
		this.setPaneState("delete");
		this.setPaneLoc(oElem);
		var oDiv = XMLParser.getNodeUsingIdFrom(oPane, "div", "delete");
		
		var oSpan = XMLParser.getNodeUsingIdFrom(oDiv, "span", "sToDelete");
		if (oSpan) oSpan.innerHTML = encodeLTGT(sInfo1);
		oSpan = XMLParser.getNodeUsingIdFrom(oDiv, "span", "sToDelete2");
		if (oSpan) oSpan.innerHTML = encodeLTGT(sInfo2);
		oSpan = XMLParser.getNodeUsingIdFrom(oDiv, "span", "sToDelete3");
		if (oSpan) oSpan.innerHTML = encodeLTGT(sInfo3);
		
		var oToDelete = XMLParser.getNodeUsingIdFrom(oPane, "input", "ixToDelete");
		oToDelete.value = ixToDelete;
		this.setFocus();
	}
	
	var oElemLastSrc;
	this.showEditPane = function(oElem, mapValsToElems)
	{
		if (!oPane) return;
	
		theMgr.hideSelects();
		this.fadeIn(true);
		oPane.style.visibility = "hidden";
		this.setPaneState("editable");
		
		var oDiv = XMLParser.getNodeUsingIdFrom(oPane, "div", "editable");
		
		for (var ix = 0; oElemLastSrc != oElem && ix < mapValsToElems.length; ix++)
		{
			if (mapValsToElems[ix].sTag.indexOf("fb:") == 0)
			{
				// setting custom tag value
				XMLParser.setCustomTagValue(oDiv, encodeLTGT(mapValsToElems[ix].sTag), mapValsToElems[ix].value);
			}
			else if (mapValsToElems[ix].sTag == 'a' || mapValsToElems[ix].sTag == 'span')
			{
				var o = XMLParser.getNodeUsingIdFrom(oPane, mapValsToElems[ix].sTag, mapValsToElems[ix].sId);
				if (o)
				{
					if (mapValsToElems[ix].value.length)
					{
						if (mapValsToElems[ix].sTag == 'a')
							o.href = mapValsToElems[ix].value;
						else if (mapValsToElems[ix].fIsHtml)
							o.innerHTML = mapValsToElems[ix].value;
						else
							o.innerHTML = encodeLTGT(mapValsToElems[ix].value);
						o.style.display = "";
					}
					else
					{
						o.style.display = "none";
					}
				}
			}
			else
			{
				// setting form element value
				var o = XMLParser.getNodeUsingIdFrom(oPane, mapValsToElems[ix].sTag, mapValsToElems[ix].sId);
				if (o)
				{
					if (o.type.toLowerCase() == "radio" || o.type.toLowerCase() == "checkbox")
						o.checked = mapValsToElems[ix].value;
					else
						o.value = mapValsToElems[ix].value;
					
					if (o.tagName.toLowerCase() == "textarea")
					{
						o.fxnResize = this.doSetShadow;
						// Always begin w/ original number of rows
						if (!o.nRowsOriginal)	o.nRowsOriginal = o.rows;
						else					o.rows = o.nRowsOriginal;
						// Resize text area as necessary to accommodate text
						adjustRows(o);
					}
				}
			}
		}
		this.setPaneLoc(oElem);
		oPane.style.visibility = "visible";
		oElemLastSrc = oElem;
		this.enablePane(false);
	}
	
	this.setPaneLoc = function(oElem)
	{
		if (!oPane) return;
		
		if (oPane.offsetHeight > windowHeight())
			this.shrinkPane();
		else if (bShrunk)
			this.unShrinkPane();
		
		var pxTop = (calculateOffset(oElem, "offsetTop")-25);

		if ((pxTop + oPane.offsetHeight) > (scrollTop() + windowHeight()))
		{
			pxTop = Math.max(2, (scrollTop() + windowHeight() - oPane.offsetHeight - 25));
		}
		
		pxTopCurrent = pxTop;
		pxLeftCurrent = (calculateOffset(oTable, "offsetLeft")+15);
		oPane.style.top = pxTopCurrent + "px";
		oPane.style.left = pxLeftCurrent + "px";
		bPositioned = true;
		if (oPane.scrollWidth && oPane.scrollWidth > oPane.offsetWidth)
		{
			// Case 285078: Make sure large font size doesn't cause
			// form control to be obscured
			oPane.style.width = (oPane.scrollWidth + 10) + 'px';
		}
	}
	
	this.shrinkPane = function()
	{
		var rgTextAreas = XMLParser.getNodeArrayFrom(oPane, "textarea");
		
		for (var ix = 0; ix < rgTextAreas.length; ix++)
		{
			if (rgTextAreas[ix] && rgTextAreas[ix].rows)
			{
				// Gradually shrink each textarea, but never shrink to less than 4 rows
				while(oPane.offsetHeight > windowHeight() && rgTextAreas[ix].rows > 4)
				{
					rgTextAreas[ix].rows--;
				}
				// Stop rows from re-expanding on textbox focus
				rgTextAreas[ix].bRowLock = true;
			}
		}
		bShrunk = true;
	}
	
	this.unShrinkPane = function()
	{
		var rgTextAreas = XMLParser.getNodeArrayFrom(oPane, "textarea");
		
		for (var ix = 0; ix < rgTextAreas.length; ix++)
		{
			if (rgTextAreas[ix])
			{
				rgTextAreas[ix].bRowLock = false;
				adjustRows(rgTextAreas[ix]);
			}
		}
		bShrunk = false;
	}
	
	this.setFocus = function()
	{
		var oToFocus;
		var oDiv = isVisible(oDelete) ? oDelete : isVisible(oEditable) ? oEditable : oError;
		if (oDiv)
		{
			oToFocus = XMLParser.getNodeFrom(oDiv, "button");
			var rg = XMLParser.getNodeArrayFrom(oDiv, "input");
			for (var ix = 0; ix < rg.length; ix++)
			{
				if (rg[ix].type != "hidden")
				{
					oToFocus = rg[ix];
					break;
				}
			}
			if (!(oToFocus.tagName.toLowerCase() == "input" && oToFocus.value.length == 0) && XMLParser.getNodeFrom(oDiv, "textarea"))
			{
				// Textarea gets focus precedence over buttons and non-empty inputs
				// Empty inputs get focus precedence over all else
				oToFocus = XMLParser.getNodeFrom(oDiv, "textarea");
			}
		}
		if ((oToFocus.tagName.toLowerCase() == "textarea" || oToFocus.type.toLowerCase() == "text") && oToFocus.id)
		{
			giveTextBoxFocus(oToFocus.id);
			adjustRows(oToFocus);
		}
		else
			safeFocus(oToFocus);
	}
	
	this.startDragging = function()
	{
		pxLeftDragOffset = xMouse - calculateOffset(oPane, "offsetLeft");
		pxTopDragOffset = yMouse - calculateOffset(oPane, "offsetTop");
		bDragging = true;
		bCancelEvents = true;
	}
	
	this.stopDragging = function()
	{
		bDragging = false;
		pxLeftDragOffset = 0;
		pxTopDragOffset = 0;
		bCancelEvents = false;
		this.setFocus();
	}
	
	this.notifyMovement = function()
	{
		if (bDragging)
		{
			pxLeftCurrent = xMouse - pxLeftDragOffset;
			pxTopCurrent = yMouse - pxTopDragOffset;			
			ShadowManager.positionShadow(sName, pxLeftCurrent, pxTopCurrent, oPane);
			oPane.style.left = pxLeftCurrent + 'px';
			oPane.style.top = pxTopCurrent + 'px';
			removeTextSelections();
		}
	}	
}
