/////////////////////////////////////////////////////////////////
//	Copyright © 2004-2008 by Symmetrix Software, Inc.
//				Brookfield, Wisconsin
//				ALL RIGHTS RESERVED
  

// Single model instance....
var g_myModel = new PLXModel();

// The global reference to the element that displays and allows editting of
// the PID....
var g_pidEntryElem;

// UI state data...
var g_UIState;

var g_lastClickedQtyBox;

// Finds (if necessary) and returns element that is the PID Entry element
// (i.e. usually a text input gizmo).
function GetPIDEntryElement()
{
	if ( g_pidEntryElem == undefined )
		g_pidEntryElem = g_myModel.getElementById( "_PIDEntry" );
		
	return g_pidEntryElem;
}

// Retrieve, purify, and return the text entered into the PID element.
function GetUserEnteredPID()
{
	var pidEntryElem = GetPIDEntryElement();
	if ( !pidEntryElem )
		return "";
	
	var pid = pidEntryElem.value.toUpperCase();
	pid = pid.replace( /^[\s]+/, "" );
	pid = pid.replace( /[\s]+$/, "" );
	return pid;
}

function IsPIDChanged()
{
	var pidEntryElem = GetPIDEntryElement();
	if ( !pidEntryElem )
		return false;
		
	var prevPID = pidEntryElem.defaultValue.toUpperCase();
	prevPID = prevPID.replace( /^[\s]+/, "" );
	prevPID = prevPID.replace( /[\s]+$/, "" );
	
	return prevPID != GetUserEnteredPID();
}

// Called to update the state of any "widgets" in the UI.....
function OnUpdateWidgets()
{
	// Update the enabled/disabled state of the accept and validate buttons...
	var pidEntryElem = GetPIDEntryElement();
	var cfgComplete = g_myModel.getPV( "model.state" ) == "complete";
	var pidChanged =  IsPIDChanged();
	var criticalMsg = g_myModel.getPV( "MS.crit" ) == "y"
	
	g_myModel.setPV( "aButt.enbl", cfgComplete && !pidChanged && !criticalMsg ? "y" : "n" );
	g_myModel.setPV( "vButt.enbl", pidChanged ? "y" : "n"  );
								 
};

// Call to update the model & document when there is activity in the PID edit element
// (i.e. user changes the PID).
function OnPIDInputChange( event )
{
	// determine whether the PID has actually changed and update the model
	// accordingly...
	var pidEntryElem = GetPIDEntryElement();
	var pidChanged =  IsPIDChanged();
	g_myModel.setPV( "ui.PIDInputChange", pidChanged ? "y" : "n" );
	
	// If we have access to the key that was pressed, check to see if it's the "enter"
	// key.  If so, we might want to take some additional action....
	if ( event )
		{
		var keyCode = uiGetKeyCode( event );

		// if the key pressed is the enter key....
		if ( keyCode == 13 )
			{
			// if the pid has been changed, then do a validate....
			if ( pidChanged )
				{
				DoValidate( GetUserEnteredPID(), event );
				OnPIDInputChange();
				}
				
			// otherwise try accepting the configuration.
			// Note: DoAccept() is assumed to check for a complete configuration....
			else 
				DoAccept();
			}
			
		// If they hit escape, go back to the last server provided PID...
		else if ( keyCode == 27 )
			{
			pidEntryElem.value = pidEntryElem.defaultValue;
			OnPIDInputChange();
			}
		}
}

// Call this to update a PID input box with new values.
function OnServerUpdatePIDInputBox( _e, _v )
{
	_e.defaultValue = _v;
	_e.value = _v;
	OnUpdateWidgets();
}

function DoCancel()
{
	// If cancelling a child, then save out UI state in case we come back....
	if ( g_myModel.getCfgPath() )
		SaveUIState();
	
	// if cancelling a root config, then blow away our UI state....
	else
		DeleteUIState();
		
	// Construct the cancel url and.....
	var url = g_myModel._serverAgentURL + "?cid=" + g_myModel._CID + "&cmd=cancel";
		
	// Away we go......
	window.location = url;
}

function DoAccept()
{
	if ( g_myModel.getPV( "model.state" ) != "complete" )
		return;

	// If accepting a child, then save out UI state in case we come back....
	if ( g_myModel.getCfgPath() )
		SaveUIState();
	
	// if accepting a root config, then blow away our UI state....
	else
		DeleteUIState();
		
	// Construct the accept url and.....
	var url = g_myModel._serverAgentURL + "?cid=" + g_myModel._CID + "&cmd=accept";
		
	// Away we go......
	window.location = url;
}

function DoEditEnum( objID )
{
	SaveUIState();

	// Construct the url to edit the child and.....
	var url = g_myModel._serverAgentURL + "?cid=" + g_myModel._CID + "&cmd=edit&tar=" + objID;
		
	// Away we go......
	window.location = url;
}

function DoShowSelector( objID )
{
	// Complete any previous select operation....
	SelectComplete();

	// Notify the document that there is a new selector being requested.
	g_myModel.setPV( objID + ".active", "y" );
	g_myModel.setPV( "model.activeOb", objID );
	
	// Reposition shared scrollbar to the top now that we have re-jiggered 
	// the selector pane.
	var summaryPane = g_myModel.getElementById( "plx_selector_pane" );
	if ( summaryPane && summaryPane.scrollTop != undefined )
		summaryPane.scrollTop = 0;

}

function DoEditOrToggleSel( objID, elem, ev, complSelect )
{
	if ( g_myModel.getPV( objID + ".select" ) == "y" )
		DoEditEnum( objID );
	else
		DoToggleSel( objID, elem, ev, complSelect );
}

function DoToggleSel( objID, elem, ev, complSelect )
{
	var cmd = "tar=" + objID + "&cmd=";
	
	// In order to toggle the selection, we need to know what the value
	// is now....
	// Also note... If this function was called as the result of a click,
	// then the checked state of the element may have been toggled visually
	// already.  We want to undo this and have the state of the check/radio
	// widget to be the current state NOT the state we are going to request.
	if ( g_myModel.getPV( objID + ".select" ) == "y" )
		{
		cmd += "unselect";
		if ( elem ) 
			elem.checked = true;
		}
	else
		{
		cmd += "select"; 
		if ( elem ) 
			elem.checked = false;
		}
	
	g_myModel.XTransaction( cmd );
	
	if ( complSelect )
		SelectComplete();

}

function OnClickQtyBox( objID, elem, ev )
{
	// If the user clicked this box from somewhere else, then...
	if ( g_lastClickedQtyBox != elem )
		{
		// Remember that we're here now...
		g_lastClickedQtyBox = elem;
		
		// If the quantity in the box is not defined, 0 or one, then 
		// toggle the selection.  Otherwise, let it be.
		// I.e. we don't want to unselect a quantity more than one.
		// This partially emulates the behavior of the Java UI except that
		// the Java UI would toggle the selection regardless of what the
		// quantity was.
		var currQty = g_myModel.getPV( objID + ".qty" );
		if ( !currQty || currQty == "0" || currQty == "1" ) 
			DoToggleSel( objID, elem, ev );
			
		elem.select();
		}
}

function OnBlurQtyBox( objID, elem, ev )
{
	if ( ValidateQty( objID, elem, ev ) )
		g_lastClickedQtyBox = null;
}

function OnClickQtySpinner( objID, qtyIncrement, elem, ev )
{
	if ( g_myModel.getPV( objID + ".allow" ) != "y" )
		return;
	
	var newQty = Number( g_myModel.getPV( objID + ".qty" ) ) + qtyIncrement;
	if ( newQty < 0 )
		return;
		
	DoSetQty( objID, newQty );
	
}

function DoSetValue( objID, newValue )
{
	g_myModel.XTransaction( "cmd=setVal&tar=" + objID + "&val=" + newValue );
}

function DoSetQty( objID, newQty )
{
	g_myModel.XTransaction( "cmd=setQty&tar=" + objID + "&val=" + newQty );
}

function DoValidate( PID )
{
	// Force model to update the PID visuals even if we get back what was sent
	// last time....
	g_myModel.setPV( "model.PID", "", true );

	g_myModel.XTransaction( "cmd=validate&PID=" + PID );
}

function DoReset()
{
	g_myModel.XTransaction( "cmd=reset" );
}

function DoUndo()
{
	g_myModel.XTransaction( "cmd=undo" );
}

function DoRedo()
{
	g_myModel.XTransaction( "cmd=redo" );
}

function SelectComplete()
{
	// If no active object selector, our work is done....
	var activeOb = g_myModel.getPV( "model.activeOb" );
	if ( !activeOb )
		return;

	// Notify the document that selector is no longer active...
	g_myModel.setPV( activeOb + ".active", "n" );
	g_myModel.setPV( "model.activeOb", "" );

}

function SaveUIState()
{
	// Create place to save UI state for all configurations that share
	// this CID....
	if ( !g_UIState )
		g_UIState = new Object;
		
	// Get/create this instances little piece of heaven...
	var edtPath = g_myModel.getCfgPath();
	if ( !g_UIState[ edtPath ] )
		g_UIState[ edtPath ] = new Object;
		
	var myState = g_UIState[ edtPath ];
	
	// Save the id of the object being editted (activeOb).
	var activeOb = g_myModel.getPV( "model.activeOb" );
	myState.activeOb = activeOb;
	
	// Save the scroll position of the standard UI's selection summary pane...
	// Only effective in IE.....
	var scrollingElement = g_myModel.getElementById( "plx_summary_pane" );
	if ( scrollingElement && scrollingElement.scrollTop != undefined )
		g_UIState[ edtPath ].sp1 = scrollingElement.scrollTop;
	
	// Ditto for the selector pane.....
	scrollingElement = g_myModel.getElementById( "plx_selector_pane" );
	if ( scrollingElement && scrollingElement.scrollTop != undefined )
		g_UIState[ edtPath ].sp2 = scrollingElement.scrollTop;

	// create/update our CID's cookie with the updates we made.
	var cookieText = ob2Initializer( g_UIState );
	document.cookie = g_myModel.getRootCID() + "=" + cookieText;

};

function DeleteUIState()
{
	document.cookie = g_myModel.getRootCID() + "=bye;expires=" + new Date(0).toUTCString();
	g_UIState = null;
}

function RestoreUIState()
{
	// Extract this CID's cookie from the cookie jar....
	var cookiesInTheCookieJar = document.cookie;
	var rootCIDKey = g_myModel.getRootCID() + "=";
	var startPos = cookiesInTheCookieJar.indexOf( rootCIDKey );
	if ( startPos < 0 )
		return false;	// Hey, who took our cookie from the cookie jar?

	// Get to the start of the cookie's value....
	startPos += rootCIDKey.length;	

	var endPos = cookiesInTheCookieJar.indexOf( ";", startPos );
	var ourCookie = cookiesInTheCookieJar.substring( startPos, endPos > 0 ? endPos : cookiesInTheCookieJar.length );
	
	// The cookie is a JavaScript initializer for g_UIState, so evaluate that....
	try 
		{ eval( "g_UIState=" + ourCookie + ";" );	}
	catch( e ) 
		{ g_UIState = null; }
		
	if ( !g_UIState )
		return false;	// Hey, who screwed the format of the cookie jar?
	
	// Do we have any settings in our cookie?
	var ourUISettings = g_UIState[ g_myModel.getCfgPath() ];
	if ( !ourUISettings )
		return false;
		
	// If we had an object being editted, then edit it again...
	if ( ourUISettings.activeOb )
		DoShowSelector( ourUISettings.activeOb );
	
	// If the scroll position for the standard UI's selection summary pane was
	// saved, then restore that.
	// Only effective for IE....  NOT TRUE!! Seems to work in FF (2.0.0.3) also...
	var scrollingElement = g_myModel.getElementById( "plx_summary_pane" );
	if ( scrollingElement && scrollingElement.scrollTop != undefined && ourUISettings.sp1 != undefined )
		scrollingElement.scrollTop = ourUISettings.sp1;

	// ditto for the attribute selector pane......
	scrollingElement = g_myModel.getElementById( "plx_selector_pane" );
	if ( scrollingElement && scrollingElement.scrollTop != undefined && ourUISettings.sp2 != undefined )
		scrollingElement.scrollTop = ourUISettings.sp2;
			
	return true;
		
};

function SetMsgLevelIcon( elem, val )
{
	elem.src = val == "critical" ?
							g_myModel.getParam( "IconMsgCritical" )   :
							val ==  "warning" ?
											g_myModel.getParam( "IconMsgWarning" ) :
											g_myModel.getParam( "IconMsgInfo" );

} 


//////////////////////////////////////////////////////////////////////////////////////
// Validation logic for quantities and scalr attribute values....
//
// global flag to prevent validation recursion.., Assumes single threading!
var g_validateInProgress = false;		

function ValidateQty( objID, elem, event )
{
	if ( g_validateInProgress )
		return true;
		
	g_validateInProgress = true;
	var dataOK = true;
	var valueChanged = false;
		
	var newQty = Number( elem.value );
	var currQty = Number( elem.defaultValue );
	if ( newQty != currQty )
		{
		valueChanged = true;
  	if ( isNaN( newQty ) || newQty < 0 )
  		{
  		alert( formatArgs( "The specified quantity (%0) is not a valid quantity.", [elem.value] ) );
  		dataOK = false;
  		}
		}
		
	if ( valueChanged && dataOK )
		DoSetQty( objID, newQty );
		
	if ( !dataOK )
		elem.focus();
	
	g_validateInProgress = false;
		
	return dataOK;
}

function ValidateValue( objID, elem, event )
{
	if ( g_validateInProgress )
		return true;
		
	g_validateInProgress = true;

	var newVal = elem.value;
	var currVal = elem.defaultValue;
		
	var uiStyle = g_myModel.getPV( objID + ".UIStyle" );
	var minVal = g_myModel.getPV( objID + ".minVal" );
	var maxVal = g_myModel.getPV( objID + ".maxVal" );
	
	var valueChanged = false;
	var convertError = false;
	var rangeError = false;
	
	if ( uiStyle == "editString" )
		{
		valueChanged = newVal != currVal;
		if ( valueChanged )
			rangeError = ( minVal != null && newVal < minVal ) || ( maxVal != null && newVal > maxVal );
		}
		
	else if ( uiStyle == "editInteger" || uiStyle == "editReal" )
		{
		minVal = minVal != null ? Number( minVal ) : -Infinity;
		maxVal = maxVal != null ? Number( maxVal ) : Infinity;
		currVal = Number( currVal );
		newVal = Number( newVal );
		valueChanged = newVal != currVal;
		if ( valueChanged )
			{
			convertError = isNaN( newVal );
			rangeError = newVal < minVal || newVal > maxVal;
			}
		}
		
	else
		throw new Error( "Unexpected UI style of '" + uiStyle + "'" );

	if ( valueChanged )
		{
  	if ( convertError )
  		alert( formatArgs( "The specified value (%0) is not valid.", [elem.value] ) );
  
		else if ( rangeError )
			alert( formatArgs( "The specified value (%0) is not in the valid range.", [elem.value] ) );
		}
		
	if ( valueChanged && !convertError && !rangeError )
		DoSetValue( objID, newVal );
		
	if ( convertError || rangeError )
		elem.focus();
	
	g_validateInProgress = false;

	return !convertError && !rangeError;
}





