
// this used to be invoked from the Save Javascript / CF button, now it saves everything.
function userSaveCurrentCode()
{
	if (CodeEditorCommon.currentView == "javascript")
	{
		CodeEditorCommon.saveCode(CodeEditorCommon.currentView);
	}
	else if (CodeEditorCommon.currentView == "configTemplate")
	{
		userSaveConfigTemplate();
	}
}

function userSaveAll()
{
	CodeEditorCommon.saveCode("javascript");
	CodeEditorCommon.saveConfigTemplate();
	CodeEditorCommon.saveWidgetDetails();
}

function userTest()
{
}


function userTestWidget(method)
{
	var testMethod = (method == 'protopage') ? 'protopage' : 'protopage';
	
	CodeEditorCommon.saveCode("javascript");
	CodeEditorCommon.saveConfigTemplate();
	CodeEditorCommon.saveWidgetDetails();
	
	PPSCXHRLib.runWhenCallStackClear( function () { CodeEditorCommon.testWidget(testMethod); } );
}


// -- userSaveConfigTemplate
//
// saves all the elements of the config template.
function userSaveConfigTemplate()
{
	CodeEditorCommon.saveConfigTemplate();	
}


function userMakeSavePoint()
{
    if (confirm("This will create a 'save point' of your code at version " + widgetSource.Version + " and allow you to go one editing a new version.\r\n\r\nAre you sure you want to continue?"))
    {
		if (CodeEditorCommon.applicationState.isCodeDirty)
		{
			CodeEditorCommon.saveCode("javascript");
		}
		
		if (CodeEditorCommon.applicationState.isConfigTemplateDirty)
		{
			CodeEditorCommon.saveConfigTemplate();	
		}
		
		if (CodeEditorCommon.applicationState.isWidgetDetailsDirty)
		{
			CodeEditorCommon.saveWidgetDetails();
		}
		
				
        var oldVersionNumber = widgetSource.Version;
        var newVersionNumber = widgetSource.Version + 0.1;
        
        var apiCall  = { 'action' : 'makeSavePoint', 
                        'widgetSourceId' : widgetSourceId };

        var makeSavePointFunc = function () {
			var response = CodeEditorCommon.makeAPICall(apiCall, CodeEditorCommon.makeSavePointResponseHandler, true, "Creating saving point...");
		};
        
        PPSCXHRLib.runWhenCallStackClear(makeSavePointFunc);
    }
    
    PPSCUtilities.defocus();
}

function userRelease()
{
	/* we don't validate normal content.  should we validate URLs?  
	 * people can always submit a thing by hand to break it.??
	if (!CodeEditorCommon.validateUseSourceUrl())
	{
		if (!confirm("You have selected 'Use Source URL', but you have not typed a URL.  If you continue with the release, 'Use Source URL' will be disabled and the widget content will come from the HTML code."))
			return;
	}*/
	
    if (confirm("Releasing this version of your widget will save all source code and navigate to the Release page where you'll be able to edit the release details (such as the name, version and release state).\r\n\r\nAre you sure you want to continue?"))
    {
		//if (CodeEditorCommon.applicationState.isCodeDirty)
		//{
			CodeEditorCommon.saveCode("javascript");
		//}
		//if (CodeEditorCommon.applicationState.isConfigTemplateDirty)
		//{
			CodeEditorCommon.saveConfigTemplate();
		//}
        //if (CodeEditorCommon.applicationState.isWidgetDetailsDirty)
		//{
			CodeEditorCommon.saveWidgetDetails();
		//}
		
        var relocate = function () {
            document.location = "index.php5?p=submitRelease&widgetSourceId=" + widgetSourceId;
        };
        
        CodeEditorCommon.applicationState.IgnoreLeavingSiteConfirmation = true;
        
        PPSCXHRLib.runWhenCallStackClear(relocate);
    }
}

/*function saveMultipleCode()
{
    // nothing on save stack to do.
    if (CodeEditorCommon.code.saveStack.length == 0)
        return;
        
    if (CodeEditorCommon.xmlhttp.readyState == 4)
    {
        CodeEditorCommon.saveCode(CodeEditorCommon.code.saveStack.pop());
        setTimeout("saveMultipleCode()",100); // DONT USE THIS FORMAT
    }
    else
    {
        setTimeout("saveMultipleCode()",100);
    }
}*/

// -- userAnnotateCode
//
// sets up a code annotation box
function userAnnotateCode()
{
    document.getElementById("cgAnnotator").style.display = "block";
    
    // need to get cited text, store somplace.    
    CodeEditorCommon.applicationState.LastAnnotationText = CodeEditorCommon.getSelection();

    document.getElementById("cgAnnotatorCite").innerHTML = CodeEditorCommon.applicationState.LastAnnotationText;//.replace("\r", "<br>");
    
    document.getElementById("cgAnnotationComment").focus();

    return false;
}

// -- userCheckCode
//
// checks the javascript code for syntax problems
function userCheckCode()
{
    var js;
    if (CodeEditorCommon.currentView == "javascript")
        js = CodeEditorCommon.codeProcessor.getFromCodeArea();
    else
        js = CodeEditorCommon.code["javascript"];
    
    try
    {
        js = "Widget = function () {} \n" + js;
        eval(js);
        CodeEditorCommon.feedback("Code looks okay.");
    }
    catch (e)
    {
        document.getElementById("feedbackArea").innerHTML = "Error parsing code: " + e.message;
    }       
}


// -- userInsertNewMethod
//
// inserts a new method
function userInsertNewMethod()
{
    if (CodeEditorCommon.currentView != "javascript")
    {
        CodeEditorCommon.feedback("You can only insert a new method when editing the javascript code.");
        return;
    }
    
    var methodName = prompt("What is the name of the new method?", "newMethodName");
    
    if (methodName)
        CodeEditorCommon.codeProcessor.appendMethod(methodName);
}


// -- userInsertConfigTemplate
//
// inserts a new config template.
function userInsertConfigTemplate()
{
}

// -- userPreviewHTMLCode
//
// previews the HTML code.
function userPreviewHTMLCode()
{
    // fetch code into memory.  will this mean that it'd be detected as saved ?  check
    var htmlCode = CodeEditorCommon.codeProcessor.getFromCodeArea();
    
    var popupHeight = 240;
    var popupWidth = 384;


    if (window.screenY)
    {
        var popupTop = window.screenY + (window.outerHeight / 2) - (popupHeight/2);
        var popupLeft = window.screenX + (window.outerWidth / 2) - (popupWidth/2);
    }
    else if (window.screenTop)
    {
        var popupTop = window.screenTop + (document.body.clientHeight / 2) - (popupHeight/2);
        var popupLeft = window.screenLeft + (document.body.clientWidth / 2) - (popupWidth/2);
    }
    
    var htmlPreview = window.open('', 'htmlPreview', 'resizable=1,height=' + popupHeight + ',width=' + popupWidth + ',left=' + popupLeft + ',top=' + popupTop); 
    
    var htmlPreviewDoc = htmlPreview.document; 
    
    htmlPreviewDoc.write("<html><head><title>" + widget.Name + "</title>"); 
    htmlPreviewDoc.write("<link rel='stylesheet' href='style/main.css' />\n");
    htmlPreviewDoc.write("<link rel='stylesheet' href='style/codeEditor.css' />\n");
    htmlPreviewDoc.write("<link rel='stylesheet' href='style/roundedcorners/active/FFFFFF' />\n");
    //htmlPreviewDoc.write("<link rel='stylesheet' href='style/roundedcorners/non-active/FFFFD0' />\n");
    htmlPreviewDoc.write("<link rel='stylesheet' href='style/roundedcorners/active-header/FFFFC8' />\n");
    //htmlPreviewDoc.write("<link rel='stylesheet' href='style/roundedcorners/non-active-header/A8A8A8' />");
    htmlPreviewDoc.write("</head><body style=\"background: url('graphics/diag-background.gif'); background-repeat: xy;\">\n"); 

    htmlPreviewDoc.write('<div class="ppsc-panel">\n');
    htmlPreviewDoc.write('<div class="ppsc-panel-sqaure rounded-corner-active-header-ne"></div>\n');
    htmlPreviewDoc.write('<div class="ppsc-panel-sqaure rounded-corner-active-header-nw"></div>\n');
    htmlPreviewDoc.write('<div class="active-header-color ppsc-panel-mid"><b>&nbsp;</b></div>\n');

    htmlPreviewDoc.write('<div class="active-header-bg ppsc-panel-header"><span>WIDGET TITLE</span></div>\n');

    htmlPreviewDoc.write('<div class="ppsc-panel-content active">\n');
    
    htmlPreviewDoc.write(htmlCode);
    
    htmlPreviewDoc.write("</div>\n");
    
    htmlPreviewDoc.write('<div class="ppsc-panel-sqaure rounded-corner-active-se"></div>\n');
    htmlPreviewDoc.write('<div class="ppsc-panel-sqaure rounded-corner-active-sw"></div>\n');
    htmlPreviewDoc.write('<div class="active ppsc-panel-mid"><b>&nbsp;</b></div>\n');
    
    htmlPreviewDoc.write("</div>");
    
    htmlPreviewDoc.write("</body></html>");
    
    htmlPreviewDoc.close();
}








//
// CodeEditorCommon
//
// Here begins the main CodeEditorCommon objects
//



function CodeEditorCommon()
{
}

/*
*
*   Data
*
*/
CodeEditorCommon.ppscBaseUrl = ""; // include trailing slash
CodeEditorCommon.ppscEngine = "index.php5";
CodeEditorCommon.ppscApiEngine = "api.php5";
CodeEditorCommon.availableViews = ["javascript", "configTemplate"];
CodeEditorCommon.currentView = "";

CodeEditorCommon.code = {
                          "javascript" : "", "javascriptLoaded" : false,
                          "configTemplate" : "", "configTemplateLoaded" : false, // we don't need this now either.
                           saveStack : []
                        };
                        
CodeEditorCommon.tabContents = { diffViewHtml : "" };

//CodeEditorCommon.configElementDesigners = []; // array of ConfigElementDesigner objects.
CodeEditorCommon.designersCollection = new ConfigElementDesignerCollection("divConfigTemplateDesignerContainer", 0);
CodeEditorCommon.designersSaveIndex = -1;
CodeEditorCommon.designersNextIds = { };

CodeEditorCommon.codeProcessor = null;

CodeEditorCommon.ajaxFloaterStatus = null;

// This is an object use throughout the app when different parts need to 
// send messages to each other.
// 
// Used in:
// MOZ codeAreakeydown to send message to codeAreakeypress to tell it to cancel event.
// To determine whether the diff lists have been loaded
// Current properties used:
//   ConfigElementsLoaded
//   DiffSourceListGenerated
//   ConfigTemplateBeenOpened
//   
CodeEditorCommon.applicationState = { isCodeDirty : false, 
									  isConfigTemplateDirty : false,
									  isWidgetDetailsDirty : false,
									  isSourceUrlInUse : false,
									  CodeAreaKeyHandlersSetup : false };

// used to store node/element references which we access often.
CodeEditorCommon.nodeRefs = {};


CodeEditorCommon.cursorPositions = { javascript :  [1, 1], 
                                     //html : [1, 1],
                                     configTemplate : [1, 1] };

CodeEditorCommon.widgetMethods = [];

CodeEditorCommon.strings = { javascript : "Javascript",
                             //html : "HTML",
                             configTemplate : "Config Template",
                             details : "Widget Details" };

CodeEditorCommon.shortcutKeyBindings = 
    { keyCode83 : "userSaveAll" };


/*
*
*   Misc Methods
*
*/


// -- init
//
//
CodeEditorCommon.init = function ()
{
    CodeEditorCommon.codeProcessor = CodeEditorCommon.getProcessorFactory();
        
    PPSCHelpPopup.attachFormHelpHandlers();

    if (pageMode == "edit")
    {
		CodeEditorCommon.feedback("Initializing application...");
    }
        
    //
    // setup event for handling backspace. 
    // (these attach to the page itself, not the CodeEditor IFRAME and they are to intercept BACKSPACE so that
    // it doesn't move off the page)
    //
    if (window.event) { // IE
        document.attachEvent("onkeydown", CodeEditorCommon.onkeydownHandler);
    } else { // MOZ
		window.onkeydown = CodeEditorCommon.onkeydownHandler;
        window.onkeypress = CodeEditorCommon.onkeypressHandler;
    }
    
    
    //
    // setup event handler for on before unload
    //    
    window.onbeforeunload = CodeEditorCommon.onbeforeunloadHandler;

    //
    // setup this variable here, so we don't have to kepe calling 
    // .getElementById everytime we update the line number.
    //     
    CodeEditorCommon.editorStatusBar = document.getElementById("editor-status-bar");
    
    
    CodeEditorCommon.availableViews.push("details");

    // 
    // display the "Diff" menu option if appropriate
    //
    if (pageMode == "review" || pageMode == "edit")
    {
        document.getElementById("btnView_diff").style.display = "inline";
        CodeEditorCommon.availableViews.push("diff");
    }

    // 
    // put the IFRAME into edit mode (we always do this, because then we can copy/paste the code, else we can't)
    // 
    var codeDoc = document.getElementById("codeArea").contentWindow.document;

    try
    {
        if (codeDoc.designMode == "off" || codeDoc.designMode == "Inherit")
           codeDoc.designMode = "on";
    }
    catch (e)
    {
    }
    
    
	//
	// This is all app initialization now.  We need this to happen after the objects created (first) and events
	// attached (second) but before any timeouts or timing loops are setup (last)
	//     
	
    // setup all the node references that we use a lot so we don't have to keep calling getElementById()
    CodeEditorCommon.nodeRefs["addNewConfigElementLinkContainer"] = document.getElementById("addNewConfigElementLinkContainer");
    CodeEditorCommon.nodeRefs["addNewConfigElementFormContainer"] = document.getElementById("addNewConfigElementFormContainer");
    
    // currently this only relies on the document being loaded (as all it does is setup node refs within the class)
    CodeEditorCommon.designersCollection.init();

	// sets up the toggle function    
    CodeEditorCommon.designersCollection.setToggleFunction( CodeEditorCommon.writeToggleFunction("addNewConfigElementLinkContainer", "addNewConfigElementFormContainer"));
    
    // make the list of diff sources.
    CodeEditorCommon.initDiffPreviousSourceList();

    // init the Widget Details pane
    CodeEditorCommon.initWidgetDetails();
    
    //
    // setup the timing stuff.
    //
    if (widgetSource.UseSourceUrl)
    {
		CodeEditorCommon.deselectCodeView("javascript");
		CodeEditorCommon.selectDetailsView(true);
		CodeEditorCommon.toggleUseSourceUrl();
    }
    else
    {
		setTimeout( function () { CodeEditorCommon.selectCodeView('javascript'); }, 250); // used to be timed.
	}

	CodeEditorCommon.applicationState.CodeAreaKeyHandlersSetup = true;
	CodeEditorCommon.codeProcessor.setKeyHandlers();

	CodeEditorCommon.applicationState.Initialized = true;
		
    setInterval(function () { CodeEditorCommon.displayLineNumber(); }, 600);
    
    setInterval(function () { CodeEditorCommon.codeProcessor.refreshMethodList(); }, 5000); 
    
    if (pageMode == "edit")
    {
		CodeEditorCommon.feedback("<strong>Tip: </strong> You can use Alt-S to quickly save the widget.");
    }
    else
    {
		document.getElementById("tdAddNewConfigElementContainer").style.display = "none";
    }
      
    if (LKBrowser.is_ua_firefox10)
    {
		document.getElementById("divConfigTemplateDesignerContainerContainer").style.overflow = "scroll";
    }
}

// -- initWidgetDetails
//
// initializes the Widget Details
CodeEditorCommon.initWidgetDetails = function () 
{
	document.getElementById("widgetDefaultWidth").value = widgetSource.DefaultWidth;
	document.getElementById("widgetDefaultHeight").value = widgetSource.DefaultHeight;
	document.getElementById("widgetDefaultTitle").value = widgetSource.DefaultTitle;
	document.getElementById("widgetSourceUrl").value = widgetSource.SourceUrl;
	document.getElementById("widgetVerticalOffset").value = widgetSource.VerticalOffset;
	document.getElementById("widgetHorizontalOffset").value = widgetSource.HorizontalOffset;
	document.getElementById("widgetDisableScrollbars").checked = widgetSource.DisableScrollbars;
	document.getElementById("widgetSendUniqueUserIdentifier").checked = widgetSource.SendUniqueUserIdentifier;
	document.getElementById("widgetUseSourceUrl").checked = widgetSource.UseSourceUrl;
	
	if (widgetSource.SendWidgetAttributesAs == 1)
	{
		document.getElementById("widgetSendWidgetAttributesAs2").checked = true;
	}
	
	if (pageMode != "edit")
	{
		document.getElementById("widgetDefaultWidth").disabled = true;
		document.getElementById("widgetDefaultHeight").disabled = true;
		document.getElementById("widgetDefaultTitle").disabled = true;
		document.getElementById("widgetUseSourceUrl").disabled = true;	
		document.getElementById("widgetSourceUrl").disabled = true;
		document.getElementById("widgetVerticalOffset").disabled = true;
		document.getElementById("widgetHorizontalOffset").disabled = true;
		document.getElementById("widgetDisableScrollbars").disabled = true;		
		document.getElementById("widgetSendWidgetAttributesAs1").disabled = true;
		document.getElementById("widgetSendWidgetAttributesAs2").disabled = true;
		document.getElementById("widgetSendUniqueUserIdentifier").disabled = true;
	}
}

// -- codeAreaLoaded
//
//
CodeEditorCommon.codeAreaLoaded = function ()
{
	if (pageMode != "edit") {
		var caBody = document.getElementById("codeArea").contentWindow.document.body;
		if (caBody) 
			caBody.style.color = "#666666";
	}	
}

// -- initDiffPreviousSourceList
//
// creates the list of previous sources to fill in the diff dropdown
CodeEditorCommon.initDiffPreviousSourceList = function() 
{
	if (!CodeEditorCommon.applicationState.DiffSourceListGenerated)
	{
	    var sourceSELECT = document.getElementById("previousSourceListSELECT");

	    for (prevSourceId in previousSources)
	    {
	        var d = new Date(previousSources[prevSourceId].ReleaseDateMs);
	        option = document.createElement("option");
	        option.innerHTML = previousSources[prevSourceId].Version + " (" + d.toDateString() + " - " + 
	                PPSCUtilities.padNumber(d.getHours()) + ":" + PPSCUtilities.padNumber(d.getMinutes()) + ")";
	        option.label = previousSources[prevSourceId].Version;
	        option.value = prevSourceId;
	        
	        sourceSELECT.appendChild(option);
        }
        
        if (previousSources.length == 0)
        {
	        option = document.createElement("option");
	        option.innerHTML = "-";
	        option.label = "-";
	        option.value = "-";
	        
	        sourceSELECT.appendChild(option);
	                
            document.getElementById("diffResultsContainer").innerHTML = "This widget does not have any previous versions.";
        }
        
	    CodeEditorCommon.applicationState.DiffSourceListGenerated = true;
	}
}	

CodeEditorCommon.validateUseSourceUrl = function ()
{
	var useSourceUrl = document.getElementById("widgetUseSourceUrl").checked;
	var sourceUrl = document.getElementById("widgetSourceUrl").value;
	
	if (useSourceUrl && sourceUrl == "")
		return false;
		
	return true;		
}

// -- toggleUseSourceUrl
//
// toggles the use of the SourceUrl field on a widget source.  
// we'll have to change: event handlers, cssClass for tabs, display of text boxes.
CodeEditorCommon.toggleUseSourceUrl = function ()
{
	var useSourceUrlCheckbox = document.getElementById("widgetUseSourceUrl");
	var sourceUrlText = document.getElementById("widgetSourceUrl");
	var verticalOffsetText = document.getElementById("widgetVerticalOffset");
	var horizontalOffsetText = document.getElementById("widgetHorizontalOffset");
	var disableScrollbars = document.getElementById("widgetDisableScrollbars");
	var sendWidgetAttributesAs1 = document.getElementById("widgetSendWidgetAttributesAs1");
	var sendWidgetAttributesAs2 = document.getElementById("widgetSendWidgetAttributesAs2");
	var sendUniqueUserIdentifier = document.getElementById("widgetSendUniqueUserIdentifier");
	
	if (useSourceUrlCheckbox.checked) // this has been updated by the time we get here
	{		
		CodeEditorCommon.applicationState.isSourceUrlInUse = true;
		
		if (pageMode == "edit")
		{
			sourceUrlText.disabled = false;
			verticalOffsetText.disabled = false;
			horizontalOffsetText.disabled = false;
			disableScrollbars.disabled = false;
			sendWidgetAttributesAs1.disabled = false;
			sendWidgetAttributesAs2.disabled = false;
			sendUniqueUserIdentifier.disabled = false;
		}
		
		// disable the tabs.
		document.getElementById("btnView_javascript").className = "codeview-link-disabled";
		document.getElementById("sourceUrlInUseWarning").style.display = "block";
	}
	else
	{
		CodeEditorCommon.applicationState.isSourceUrlInUse = false;
		
		sourceUrlText.disabled = true;
		verticalOffsetText.disabled = true;
		horizontalOffsetText.disabled = true;
		disableScrollbars.disabled = true;
		sendWidgetAttributesAs1.disabled = true;
		sendWidgetAttributesAs2.disabled = true;
		sendUniqueUserIdentifier.disabled = true;

		// enable the tabs.
		document.getElementById("btnView_javascript").className = "codeview-link-unselected";
		document.getElementById("sourceUrlInUseWarning").style.display = "none";
	}
}


// -- test
//
// tester function mainly used on event testing.
CodeEditorCommon.test = function ()
{
    alert("test");
}

// -- feedback
//
// feedsback the 'text' to the user via the feedbackArea in the code editor
CodeEditorCommon.feedback = function(text)
{
    document.getElementById("feedbackArea").innerHTML = text;
}


// -- moveToMethod
//
// actually just takes a line number returned from the SELECT statement, but it's
// wrapper here as the internals will likely change.
CodeEditorCommon.moveToMethod = function(selectObject)
{
    if (CodeEditorCommon.currentView == "javascript")
    {
        window.codeArea.focus();
        CodeEditorCommon.codeProcessor.moveToMethod(selectObject.options.selectedIndex);
    }
}


// -- writeToggleFunction
//
// write's a generic toggle function for the two given node names.
CodeEditorCommon.writeToggleFunction = function (nodeOneName, nodeTwoName, displayMode)
{
	var dispMode = displayMode ? displayMode : "block";
	
	var f = function () 
	{
		if (document.getElementById(nodeOneName).style.display == "none")
		{
			document.getElementById(nodeOneName).style.display = dispMode;
			document.getElementById(nodeTwoName).style.display = "none";
		}
		else
		{
			document.getElementById(nodeOneName).style.display = "none";
			document.getElementById(nodeTwoName).style.display = dispMode;
		}	
	
	};
	
	return f;
}


// -- findConfigDesignerById 
//
// returns the config element designer with the given id
CodeEditorCommon.findConfigDesignerById = function (configElementDesignerId)
{
	return CodeEditorCommon._findConfigDesignerById(configElementDesignerId, CodeEditorCommon.designersCollection);
}

CodeEditorCommon._findConfigDesignerById = function (configElementDesignerId, configElementDesignersCollection)
{
	for (var i = 0; i < configElementDesignersCollection.elementDesigners.length; i++)
	{	
		if (configElementDesignersCollection.elementDesigners[i].id == configElementDesignerId)
		{
			return configElementDesignersCollection.elementDesigners[i];
		}
		if (configElementDesignersCollection.elementDesigners[i].children)
		{
			var r = CodeEditorCommon._findConfigDesignerById(configElementDesignerId, configElementDesignersCollection.elementDesigners[i].children);
			if (r != null)
			{
				return r;
			}
		}
	}
	
	return null;
}


// -- addNewConfigElement
//
// makes an API call to add a new config element
CodeEditorCommon.addNewConfigElement = function(configElementTypeID, destinationDesignerCollection)
{
	var newConfigElementDesigner = CodeEditorCommon.ConfigElementDesignerFactory(configElementTypeID);
	
	if (newConfigElementDesigner == null)
	{
		alert("Sorry, a new config element could not be created of that type. (Error code: 8001)");
		return;
	}
	
	newConfigElementDesigner.setContainerId(destinationDesignerCollection.containerConfigElementId);

	// note: we used to add it to the array here, now we only add it if it's saved to the DB okay.
	
	destinationDesignerCollection.toggleFunction(); // toggles the "Add new ..." form on and off.
	
	var runWhenSaved = function () {
			// add it to the array
			if (this.data.param1.id > 0)
			{
				var newDesignerIndex = destinationDesignerCollection.elementDesigners.push(newConfigElementDesigner) - 1;
				newConfigElementDesigner.order = destinationDesignerCollection.findMaxOrder() + 1;
				if (newConfigElementDesigner.order <= 0) // if it's NEGATIVE_INFINITY (from findMaxOrder() or 0 - because it's the first element)
					newConfigElementDesigner.order = 1;

				// render it on the screen
				if (destinationDesignerCollection.containerConfigElementId != 0)
				{
					var parent = CodeEditorCommon.findConfigDesignerById(destinationDesignerCollection.containerConfigElementId);
					if (parent != null)
					{
						parent.childrenChanged();				
					}
				}
				
				destinationDesignerCollection.renderConfigElementDesigner( newDesignerIndex );
			}
			else
			{
				alert("There was a problem saving your new widget attribute. (W1194).  Please try again in a couple of minutes.");
			}
	    };
	    
	CodeEditorCommon.saveConfigElement(newConfigElementDesigner, false, runWhenSaved);
}


CodeEditorCommon.testWidget = function (method)
{
	var testMethod = (method == 'standalone') ? 'standalone' : 'protopage';
	
	var requestObj = { action : 'testWidget',
					   widgetSourceId : widgetSourceId,
					   testType : testMethod
					  };
	
	CodeEditorCommon.makeAPICall(requestObj, CodeEditorCommon.testWidgetHandler, true, "Testing widget...", { "testType" : testMethod } );
}

CodeEditorCommon.testWidgetHandler = function ()
{
    if (this.xmlhttp.readyState == 4)
    {
        // save the source code into local variable
        try
        {
            var response = JSON.parse(this.xmlhttp.responseText);
            if (response.status != "ok")
            {
                alert("Problem deploying widget code to test server.  Please try again in a few minutes.");
            }
        }
        catch(ex) 
        {
			alert("ERROR: Unknown response: " + this.xmlhttp.responseText + " (" + ex.message + ")");
        }
        
        if (response.status == "ok")
        {
			var windowWidth, windowHeight, sx = 0, sy = 0;
			var strWinWidth = "", strWinHeight = "", strFullScreen = "";
			
			// open new browser window, sized to fit widget size.
			if (this.data.testType == 'standalone')
			{
				windowWidth = document.getElementById("widgetDefaultWidth").value;
				windowHeight = document.getElementById("widgetDefaultHeight").value;
				
				sx = PPSCUtilities.getScreenCenterX();
				sy = PPSCUtilities.getScreenCenterY();
				sx = sx - (windowWidth/2);
				sy = sy - (windowHeight/2);
				
				strWinWidth = ",width=" + windowWidth;
				strWinHeight = ",height=" + windowHeight;
			}
			else
			{
				strFullScreen = ",fullscreen=yes";
			} 

			window.open(response.url, "test" + this.data.testType, "location=yes,resizable=yes,menubar=yes,toolbar=yes,titlebar=yes" + strWinWidth + strWinHeight + strFullScreen + ",top=" + sy + ",left=" + sx);
			//alert(response.url);
        }         
    }	
}



// -- saveConfigTemplate
//
// saves the whole configuration template by using multiple AJAX calls
CodeEditorCommon.saveConfigTemplate = function ()
{
	CodeEditorCommon.designersCollection.collectInfo();
	
	var requestObj = { action : 'saveWidgetConfigTemplate', 
					   widgetId : widget.Id,
					   widgetSourceId : widgetSourceId,
					   widgetConfigElements : CodeEditorCommon.designersCollection.getElementDesigners()
					    };

	CodeEditorCommon.makeAPICall(requestObj, CodeEditorCommon.saveConfigTemplateHandler, true, "Saving config template...");
}



// -- saveConfigTemplateHandler
//
// callback for the AJAX call to save a config template
CodeEditorCommon.saveConfigTemplateHandler = function ()
{
    if (this.xmlhttp.readyState == 4)
    {
        // save the source code into local variable
        try
        {
            var response = JSON.parse(this.xmlhttp.responseText);
            if (response.isError)
            {
                alert("Error " + response.errorCode + ": " + response.message);
            }
        }
        catch(ex) 
        {
			alert("ERROR: Unknown response: " + this.xmlhttp.responseText + " (" + ex.message + ")");
        }
        
        // this is out here (and not just on the else{} of the if() after the eval()) because if it's up there then any javascript
        // code errors wouldn't be handled in the proper way but would be caught by that catch above and sent to the feedback window.
        if (!response.isError)
        {
			// TODO - find alternative to this -- CodeEditorCommon.feedback("Loaded config elements successfully.");
			
			// CodeEditorCommon.xmlhttpData is a user paramter we set when using AJAX to communicate between the callee 
			// and the callback methods.
			//CodeEditorCommon.xmlhttpData.setDirtyStatus(false);
			
			CodeEditorCommon.designersCollection.updateTitles();
			
			CodeEditorCommon.designersCollection.runChildrenChanged();
			
			CodeEditorCommon.setConfigTemplateDirty(false);
			
			/*if (CodeEditorCommon.xmlhttpData && CodeEditorCommon.xmlhttpData.hasFunction)
			{
				CodeEditorCommon.xmlhttpData.func();
				CodeEditorCommon.xmlhttpData.hasFunction = false;
				CodeEditorCommon.xmlhttpData.func = null;
			}*/
        }         
    }		
}

// -- saveWidgetDetails
//
//
CodeEditorCommon.saveWidgetDetails = function ()
{
	CodeEditorCommon.designersCollection.collectInfo();

	var defWidth = document.getElementById("widgetDefaultWidth").value*1;
	var defHeight = document.getElementById("widgetDefaultHeight").value*1;
	var vertOffset = document.getElementById("widgetVerticalOffset").value*1;
	var horizOffset = document.getElementById("widgetHorizontalOffset").value*1;
	
	var disableScrollbarsValue = document.getElementById("widgetDisableScrollbars").checked ? 1 : 0;	
	var sendWidgetAttributesAsValue = document.getElementById("widgetSendWidgetAttributesAs1").checked ? 0 : 1;
	var sendUniqueUserIdentifierValue = document.getElementById("widgetSendUniqueUserIdentifier").checked ? 1 : 0;	
	var useSourceUrlValue = document.getElementById("widgetUseSourceUrl").checked ? 1 : 0;
	
	defWidth = !defWidth ? 0 : defWidth; /* this takes case of it being some letters */
	defHeight = !defHeight ? 0 : defHeight;	
	horizOffset = !horizOffset ? 0 : horizOffset;
	vertOffset = !vertOffset? 0 : vertOffset;

	
	if (defWidth != defWidth)
	{
		alert("Warning: Couldn't save widget details because the 'Default Width' value must be a whole number.");
		return;
	}
	
	if (defHeight != defHeight)
	{
		alert("Warning: Couldn't save widget details because the 'Default Height' value must be a whole number.");
		return;
	}
	
	var requestObj = { action : 'saveWidgetDetails', 
					   widgetId : widget.Id,
					   widgetSourceId : widgetSourceId,
					   defaultHeight : defHeight,
					   defaultWidth : defWidth,
					   defaultTitle : document.getElementById("widgetDefaultTitle").value,
					   sourceUrl : document.getElementById("widgetSourceUrl").value,
					   verticalOffset : vertOffset,
					   horizontalOffset : horizOffset,
					   disableScrollbars : disableScrollbarsValue,
					   sendWidgetAttributesAs : sendWidgetAttributesAsValue,
					   sendUniqueUserIdentifier : sendUniqueUserIdentifierValue,
					   useSourceUrl : useSourceUrlValue
 				     };
 				     
	CodeEditorCommon.makeAPICall(requestObj, CodeEditorCommon.saveWidgetDetailsHandler, true, "Saving widget details...");
}


// -- saveWidgetDetailsHandler
//
// callback for the AJAX call to save a config element
CodeEditorCommon.saveWidgetDetailsHandler = function ()
{
    if (this.xmlhttp.readyState == 4)
    {
        // save the source code into local variable
        try
        {
            var response = JSON.parse(this.xmlhttp.responseText);
            if (response.isError)
            {
                alert("Error " + response.errorCode + ": " + response.message);
            }
            else
	        {
				CodeEditorCommon.setWidgetDetailsDirty(false);
            }
        }
        catch(ex) 
        {
			alert("ERROR: Unknown response: " + this.xmlhttp.responseText + " (" + ex.message + ")");
        }
    }		
}


// -- saveConfigElement
//
// saves a single WidgetConfigElement designer.
// NOTE: We now only use saveConfigTemplate for the main saving of items - this was added when each one was being saved individually
// which has now changed - however, what we do do with this one is use it to save newly created items (thus getting the id back from
// the server in as a JSON object) which we can use to populate our in memory representation.
CodeEditorCommon.saveConfigElement = function(configElementDesigner, suppressStatusFloat, funcRunWhenDone)
{
	if (!configElementDesigner)
		return;
	
	var configElementDataOnly_aux = configElementDesigner.getData();
	
	if (configElementDataOnly_aux instanceof Array) // Tables and Option Groups return an array
	{
		var configElementDataOnly = configElementDataOnly_aux[0];
	}
	else
	{
		var configElementDataOnly = configElementDataOnly_aux;
	}
	
	//var configElementDataOnly = JSON.stringify(CodeEditorCommon.designersCollection);
	
	var requestObj = { action : 'saveWidgetConfigElement', 
					   widgetId : widget.Id,
					   widgetSourceId : widgetSourceId,
					   widgetConfigElementId : configElementDesigner.id,
					   widgetConfigElement : configElementDataOnly 
					    };

	var message = suppressStatusFloat ? "" : "Saving configuration element...";

	var xhrCallObj = new PPSCXHRLibCallArg("", requestObj, CodeEditorCommon.saveConfigElementHandler, true, message);
						    
	xhrCallObj.data.param1 = configElementDesigner;
	if (funcRunWhenDone && typeof funcRunWhenDone == "function")
	{
		xhrCallObj.oncomplete = funcRunWhenDone;
	}
	
	CodeEditorCommon.makeAPICallXHRArg(xhrCallObj);
}


// -- saveConfigElementsHandler
//
// callback for the AJAX call to save a config element
CodeEditorCommon.saveConfigElementHandler = function ()
{
    if (this.xmlhttp.readyState == 4)
    {	
        // save the source code into local variable
        try
        {
            var response = JSON.parse(this.xmlhttp.responseText);
            if (response.isError)
            {
                alert("Error " + response.errorCode + ": " + response.message);
            }
        }
        catch(ex) 
        {
			alert("ERROR: Unknown response: " + this.xmlhttp.responseText + " (" + ex.message + ")");
        }
        
        // this is out here (and not just on the else{} of the if() after the eval()) because if it's up there then any javascript
        // code errors wouldn't be handled in the proper way but would be caught by that catch above and sent to the feedback window.
        if (!response.isError)
        {
			if (this.data.param1.setDirtyStatus)
			{
				this.data.param1.setDirtyStatus(false);
			}

			this.data.param1.setId(response.widgetConfigElementId);
        }         
    }		
}




// -- deleteConfigElement
//
// delete's a widgetConfigElement from the database via AJAX call.
CodeEditorCommon.deleteConfigElement = function(configElementDesignerContainer, configElementDesigner, suppressStatusFloat)
{
	if (!configElementDesigner)
		return;
	
	var message = suppressStatusFloat ? "" : "Deleting config element...";

	var requestObj = { action : 'deleteWidgetConfigElement', 
					   widgetSourceId : widgetSourceId,
					   widgetConfigElementId : configElementDesigner.id
					  };

	CodeEditorCommon.makeAPICall(requestObj, CodeEditorCommon.deleteConfigElementHandler, true, message, [ configElementDesignerContainer, configElementDesigner ]); 
}


// -- deleteConfigElementsHandler
//
// callback for the AJAX call to delete a config element
CodeEditorCommon.deleteConfigElementHandler = function ()
{
    if (this.xmlhttp.readyState == 4)
    {
        // save the source code into local variable
        try
        {
            var response = JSON.parse(this.xmlhttp.responseText);
            if (response.isError)
            {
                alert("Error " + response.errorCode + ": " + response.message);
            }
        }
        catch(ex) 
        {
			alert("ERROR: Unknown response: " + this.xmlhttp.responseText + " (" + ex.message + ")");
        }
        
        // this is out here (and not just on the else{} of the if() after the eval()) because if it's up there then any javascript
        // code errors wouldn't be handled in the proper way but would be caught by that catch above and sent to the feedback window.
        if (!response.isError)
        {
			// if there's no error then we want to remove it from the UI.
			
			if (this.data[0].deleteElement)
			{
				this.data[0].deleteElement( this.data[1] );
			}
			
			var parentDesigner = CodeEditorCommon.findConfigDesignerById(this.data[0].containerConfigElementId);
			if ((parentDesigner instanceof Object) && parentDesigner.children)
			{
				parentDesigner.childrenChanged();
			}
        }         
    }		
}

// -- renderConfigElementDesigners
//
//
CodeEditorCommon.renderAndShowRootConfigElementDesigners = function()
{
	// would it be better to remove the child nodes programatically through the DOM ?
	//		- would we need to iterate through each of them ?
	CodeEditorCommon.designersCollection.renderConfigElementDesigners();
}


// -- ConfigElementDesignerFactory
//
// creates a new config element designer object for the given config element type.
CodeEditorCommon.ConfigElementDesignerFactory = function(configElementTypeID)
{
	var newConfigElementDesigner = null;
	
	if (configElementTypeID == ConfigElementType.HiddenAttribute) // HIDDEN ATTRIBUTE
	{
		var nextFreeName = CodeEditorCommon.findNextFreeAttributeName(CodeEditorCommon.designersCollection, "attribute");

		newConfigElementDesigner = new ConfigHiddenAttributeDesigner(-1, -1, nextFreeName, "Value");		
		
	} else if (configElementTypeID == ConfigElementType.TextField) { // TEXTFIELD
	
		var nextFreeName = CodeEditorCommon.findNextFreeAttributeName(CodeEditorCommon.designersCollection, "textbox");
		
		newConfigElementDesigner = new ConfigTextFieldDesigner(-1, -1, nextFreeName, "Label", "Your description here", "Default value", "100", "100");
		
	} else if (configElementTypeID == ConfigElementType.Divider) { // DIVIDER

		newConfigElementDesigner = new ConfigDividerDesigner(-1, -1, "divider", "Label", "Your description here");

	} else if (configElementTypeID == ConfigElementType.Checkbox) { // CHECKBOX

		var nextFreeName = CodeEditorCommon.findNextFreeAttributeName(CodeEditorCommon.designersCollection, "checkbox");

		newConfigElementDesigner = new ConfigCheckboxDesigner(-1, -1, nextFreeName, "Label here", "Your description goes here.", false);

	} else if (configElementTypeID == ConfigElementType.Table) { // TABLE

		var nextFreeName = CodeEditorCommon.findNextFreeAttributeName(CodeEditorCommon.designersCollection, "table");
		
		newConfigElementDesigner = new ConfigTableDesigner(-1, -1, nextFreeName);

	} else if (configElementTypeID == ConfigElementType.OptionGroup) {  // OPTION GROUP

		var nextFreeName = CodeEditorCommon.findNextFreeAttributeName(CodeEditorCommon.designersCollection, "optionGroup");
		
		newConfigElementDesigner = new ConfigOptionGroupDesigner(-1, -1, nextFreeName, "Label", "Your description here", null);
		
	} else if (configElementTypeID == ConfigElementType.OptionGroupElement) {  // OPTION ELEMENT

																		// id,order,attrName,label,value,isDefault
		newConfigElementDesigner = new ConfigOptionGroupElementDesigner(-1, -1, "optionElement", "Label", 1, 0);

	}			
	
	return newConfigElementDesigner;
}


// -- findNextFreeAttributeName
//
// find's the next free attribute name
CodeEditorCommon.findNextFreeAttributeName = function (designerCollection, baseName)
{
	return baseName + CodeEditorCommon._findNextFreeAttributeName(designerCollection, baseName, 1);
}

// -- _findNextFreeAttributeName
//
// auxillary method used by findNextFreeAttributeName for it's recursion.
CodeEditorCommon._findNextFreeAttributeName = function (designerCollection, baseName, count)
{
	for (var i = 0; i < designerCollection.elementDesigners.length; i++)
	{
		if (designerCollection.elementDesigners[i].attributeName == (baseName + count))
		{
			i = -1; // restart search
			count++;
			continue;
		}
		
		if (designerCollection.elementDesigners[i].children)
		{
			new_count = CodeEditorCommon._findNextFreeAttributeName(designerCollection.elementDesigners[i].children, baseName, count);
			
			if (count != new_count) // it's been incremented because a child matched count, so we need to restart the loop.
			{
				i = -1;
				count = new_count;
				continue;
			}
		}
	}
	
	return count;
}


// -- renderConfigElementDesigner
//
// renders one config element, returning the document node which is the container DIV created
// with the rendered contents inside.  This is used by CodeEditorCommon.renderConfigElements
// as well as other methods.
CodeEditorCommon.renderSingleConfigElementDesigner = function(parentDesignerCollection, configElem)
{
	var configElemContainer = document.createElement("div");
	configElemContainer.id = "configElementContainer" + configElem.id;
	configElemContainer.className = "configElementContainer";
	
	var configElemDesignerHeader = document.createElement("span");
	configElemDesignerHeader.className = "configElementHeader text";
	configElemDesignerHeader.style.fontSize = "13px";
	
	configElem.setTitleNodeRef(configElemDesignerHeader);
	configElem.drawTitle();
	
	if (pageMode == "edit")
	{
		var configElemDesignerIcons = document.createElement("span");
		configElemDesignerIcons.className = "configElementHeader icons";
		
		var moveElementUpImg = document.createElement("img");
		moveElementUpImg.border = "0";
		moveElementUpImg.src = "graphics/arrow up 12.gif";
		moveElementUpImg.title = "Move element up";
		moveElementUpImg.onclick = function () { parentDesignerCollection.moveElementUp(configElem); };
		
		var moveElementDownImg= document.createElement("img");
		moveElementDownImg.border = "0";
		moveElementDownImg.src = "graphics/arrow down 12.gif";
		moveElementDownImg.title = "Move element down";
		moveElementDownImg.onclick = function () { parentDesignerCollection.moveElementDown(configElem); };
		
		var delElementImg = document.createElement("img");
		delElementImg.border = "0";
		delElementImg.src = "graphics/cross.gif";
		delElementImg.title = "Delete element...";		
		delElementImg.onclick = function () { CodeEditorCommon.deleteConfigElement(parentDesignerCollection, configElem, false); };
		
		/*var saveChangesLink = document.createElement("a");
		saveChangesLink.href = "javascript: void(0);";
		saveChangesLink.onclick = function () { CodeEditorCommon.saveConfigElement(configElem); };
		saveChangesLink.innerHTML = "Save Changes";
		saveChangesLink.style.marginRight = "6px";*/

		// Add stuff to the icons SPAN element 
		//configElemDesignerIcons.appendChild(saveChangesLink);
		configElemDesignerIcons.appendChild(moveElementUpImg);
		configElemDesignerIcons.appendChild(document.createTextNode(" "));
		configElemDesignerIcons.appendChild(moveElementDownImg);
		configElemDesignerIcons.appendChild(document.createTextNode(" "));
		configElemDesignerIcons.appendChild(delElementImg);
	}
	
	// now do the main content bit.
	configElemContainer.innerHTML = "<br /><br />";
	
	var designerNode = configElem.getDesignerNode( (pageMode != "edit") );
	if (designerNode)
		configElemContainer.appendChild(designerNode);
	
	// lastly we add the two header SPAN's we created above.  this has to be done last cos we're using innerHTML above.
	configElemContainer.insertBefore(configElemDesignerHeader, configElemContainer.childNodes[0]);
	
	if (pageMode == "edit")
	{
		configElemContainer.insertBefore(configElemDesignerIcons, configElemContainer.childNodes[0]);
	}
	
	return configElemContainer;
}

// -- createAnnotation
//
//
CodeEditorCommon.createAnnotation = function()
{
    // flow:
    // get text from TEXTAREA
    // escape it.
    // get citation
    // build API call
    // call API
    // close down box? could put this on he onclick also.
    
    CodeEditorCommon.ajaxFloaterStatus = new Floater("bodyElement", "floaterApiCall", "Creating annotation...");
    
    var annotation = document.getElementById("cgAnnotationComment").value;
    var codeCitation = (CodeEditorCommon.applicationState.LastAnnotationText) ? "" + CodeEditorCommon.applicationState.LastAnnotationText : "";

    annotation = annotation.replace(/"/g, "\\\"");
    var annotationLines = annotation.split("\r\n");
    if (annotationLines.length <= 1)
        annotationLines = annotation.split("\n");
    annotation = annotationLines.join("\\r\\n");

    codeCitation = codeCitation.replace(/"/g, "\\\"");
    codeCitation = codeCitation.split("\r\n").join("\\r\\n");
    
    var codeLine = CodeEditorCommon.codeProcessor.line == "-" ? -1 : CodeEditorCommon.codeProcessor.line;
    
    var codeType = (CodeEditorCommon.currentView == "diff") ? "general" : CodeEditorCommon.currentView;
    
    var req = "{ action : 'makeCodeAnnotation',\r\n codeType : \"" + codeType + "\", \r\n widgetSourceId : " + widgetSourceId + ",\r\n annotation : \"" + annotation + "\",\r\n codeCitation : \"" + codeCitation  + "\", \r\n codeLine : \"" + codeLine + "\"}";

    CodeEditorCommon.makeAPICall(req, CodeEditorCommon.standardPrintResultHandler, true);
}


// -- getSelection
//
//
CodeEditorCommon.getSelection = function (win)
{
    var selectedText = "";
    if (win == null)
        win = document.getElementById("codeArea").contentWindow;
    
    if (win.getSelection)
        selectedText = win.getSelection();

    if (win.document.selection && win.document.selection.type != 'none')
    {
        var ieRange = win.document.selection.createRange();
        selectedText = ieRange.text;
    }
    
    return selectedText;        
}


// -- runWhenSavesDone
//
//
/*CodeEditorCommon.runWhenSavesDone = function (func)
{
    if (CodeEditorCommon.code.saveStack.length == 0 && CodeEditorCommon.xmlhttp.readyState == 4)
        func();
    else
        setTimeout("CodeEditorCommon.runWhenSavesDone(" + func + ")", 100);
}*/


// -- saveCode
//
//
CodeEditorCommon.saveCode = function (codeTypeToSave)
{
    // if we haven't yet loaded the code, we don't need to save it.
    CodeEditorCommon.code[codeTypeToSave] = CodeEditorCommon.codeProcessor.getFromCodeArea();
   
    var codeToSave = CodeEditorCommon.code[codeTypeToSave].replace(/"/g, "\\\"");
    codeToSave = codeToSave.split("\r\n").join("\\r\\n");
    
    var req = "{ action : 'saveCode', widgetSourceId : " + widgetSourceId + ", codeType : \"" + codeTypeToSave + "\", code : \"" + codeToSave  + "\"}";

	var oncomplete = function () { CodeEditorCommon.setCodeDirty(false); };

    CodeEditorCommon.makeAPICall(req, CodeEditorCommon.standardPrintResultHandler, true, "Saving...", null, oncomplete);
}


// -- fetchWidgetSourceCode
//
//
CodeEditorCommon.fetchWidgetSourceCode = function (codeToFetch)
{
    var req = "{ action : 'getCode', widgetSourceId : " + widgetSourceId + ", codeType : '" + codeToFetch + "'}";

    CodeEditorCommon.codeProcessor.loadIntoCodeArea("Loading code...");

    CodeEditorCommon.makeAPICall(req, CodeEditorCommon.loadingcodehandlerDisplayCode, true);
}


// -- Make API call
//
// makes the API call to the showcase.
CodeEditorCommon.makeAPICall = function (apiRequest, responseCallback, async, message, data, oncompleteHandler)
{
	var xhrCallArg = new PPSCXHRLibCallArg(CodeEditorCommon.ppscBaseUrl + CodeEditorCommon.ppscApiEngine, 
										   apiRequest,  // this is JSON string or JS object
										   responseCallback, 
										   async, 
										   message);
	
	if (data)
	{
		if (data instanceof Array)
		{
			for (var i = 0; i < data.length; i++)
			{
				xhrCallArg.data[i] = data[i];
			}
		}
		else if (data instanceof Object)
		{
			for (var name in data)
			{
				xhrCallArg.data[name] = data[name];
			}
		}
	}
	
	if (oncompleteHandler)
	{
		xhrCallArg.oncomplete = oncompleteHandler;	
	}

	PPSCXHRLib.makeXHRCall(xhrCallArg);
}


// -- Make API call
//
// makes the API call to the showcase.
CodeEditorCommon.makeAPICallXHRArg = function (xhrCallArg)
{
	xhrCallArg.url = CodeEditorCommon.ppscBaseUrl + CodeEditorCommon.ppscApiEngine;
	PPSCXHRLib.makeXHRCall(xhrCallArg);
}

/*
OLD CodeEditorCommon.makeAPICall:
	
    var req; // string to hold the request object
    CodeEditorCommon.xmlhttp.open("POST", CodeEditorCommon.ppscBaseUrl + CodeEditorCommon.ppscApiEngine, async);
    CodeEditorCommon.xmlhttp.setRequestHeader("Content-Type", "text/plain");
    if (async)
        CodeEditorCommon.xmlhttp.onreadystatechange = responseCallback;
    
    if (typeof(apiRequest) == "object")
        req = JSON.stringify(apiRequest);
    else
        req = apiRequest;
    
    CodeEditorCommon.xmlhttp.send(req);
    
    if (!async)
    {
        try
        {
			var decodedResponse = JSON.parse(CodeEditorCommon.xmlhttp.responseText);
        }
        catch (ex)
        {
            var decodedResponse = { isError : true, errorCode : 50, message : "Unknown API response." };
        }
        return decodedResponse;
    }
}*/


// -- setViewStyle
//
//
CodeEditorCommon.setViewStyle = function (obj, action)
{
	if (action == "selectedLink") {
	    obj.className = "codeview-link-selected";
	} else if (action == "unselectedLink") {
	    obj.className = "codeview-link-unselected";		
	} else if (action == "highlightedLink") {
	    obj.className = "codeview-link-highlighted";			
	} else if (action == "disabledLink") {
		obj.className = "codeview-link-disabled";
	}	
}


// -- codeAreaOnLoad event
//
// currently unused.
CodeEditorCommon.codeAreaOnLoad = function ()
{
}


// -- displayLineNumber
//
// displays the current line + column number.  currently called from a 
// setInterval() on 600 ms
CodeEditorCommon.displayLineNumber = function()
{
    CodeEditorCommon.codeProcessor.calculateLineColumn();
    
    if (CodeEditorCommon.codeProcessor.lineColumnDirty)
    {
        CodeEditorCommon.editorStatusBar.innerHTML = 
            "Line: " + CodeEditorCommon.codeProcessor.line  + 
            "&nbsp;&nbsp;&nbsp;Column: " + CodeEditorCommon.codeProcessor.column;
    }    
}


/*
*
*   Callback functions - AJAX callbacks
*
*/

// -- makeSavePointResponseHandler
//
//
CodeEditorCommon.makeSavePointResponseHandler = function () 
{
    if (this.xmlhttp.readyState == 4)
    {
        // save the source code into local variable
        try
        {
            var decodedResponse = JSON.parse(this.xmlhttp.responseText);
            
            if (decodedResponse.isError)
            {
                document.getElementById("feedbackArea").innerHTML = decodedResponse.errorCode + ": " + decodedResponse.message;
            }
            else
            {
                // blank error.
                // TODO
                //StatusMessage.MakeNew("statusApiResult", decodedResponse.message);
                document.getElementById("feedbackArea").innerHTML = decodedResponse.message;
                try
                {
                    if (decodedResponse.newVersion)
                    {
                        widgetSource["Version"] = decodedResponse.newVersion;
                        document.getElementById("titleWidgetSourceVersion").innerHTML = decodedResponse.newVersion;

						/*
						The API function needs to return the source Id of the old/previous version which has just been made.
						var sourceSELECT = document.getElementById("previousSourceListSELECT");

						var d = new Date(previousSources[prevSourceId].ReleaseDateMs);
						option = document.createElement("option");
						option.innerHTML = previousSources[prevSourceId].Version + " (" + d.toDateString() + " - " + 
								PPSCUtilities.padNumber(d.getHours()) + ":" + PPSCUtilities.padNumber(d.getMinutes()) + ")";
						option.label = previousSources[prevSourceId].Version;
						option.value = prevSourceId;
				        
						sourceSELECT.appendChild(option);*/
                    }
                } catch (ex) {}
            } 
        }
        catch(ex) 
        {
            document.getElementById("feedbackArea").innerHTML = "ERROR: Unknown response:<br>" + this.xmlhttp.responseText;
        }
        
        //CodeEditorCommon.ajaxFloaterStatus.KillMe();
    }
}


// -- loadingcodehandlerDisplayCode
//
//
CodeEditorCommon.loadingcodehandlerDisplayCode = function ()
{
    if (this.xmlhttp.readyState == 4)
    {
        try
        {
            var decodedResponse = JSON.parse(this.xmlhttp.responseText);
        }
        catch(e)
        {
            // we do nothing because if the code didn't eval then it obviously isn't a 
            // JSON error response.
            var decodedResponse = { isError : false };        
        } 

        if (decodedResponse && decodedResponse.isError)
        {
            document.getElementById("feedbackArea").innerHTML = decodedResponse.message;
            CodeEditorCommon.code[CodeEditorCommon.currentView] = decodedResponse.message;
            CodeEditorCommon.codeProcessor.loadIntoCodeArea(decodedResponse.message)
        } 
        else 
        {
            // save the source code into local variable
            CodeEditorCommon.code[CodeEditorCommon.currentView] = this.xmlhttp.responseText;
            CodeEditorCommon.code[CodeEditorCommon.currentView + "Loaded"] = true;        
            CodeEditorCommon.codeProcessor.loadIntoCodeArea(this.xmlhttp.responseText);
        }
        
        //window.frames["codeArea"].focus();
        //setTimeout( 'window.frames["codeArea"].focus()', 200);
        
        if (! CodeEditorCommon.applicationState.Initialized)
        {
			CodeEditorCommon.applicationState.Initialized = true;
			CodeEditorCommon.codeProcessor.refreshMethodList();
        }
        
		if (pageMode == "edit")
		{
			if (! CodeEditorCommon.applicationState.CodeAreaKeyHandlersSetup)
			{
				CodeEditorCommon.applicationState.CodeAreaKeyHandlersSetup = true;
				CodeEditorCommon.codeProcessor.setKeyHandlers();
			}
        
			CodeEditorCommon.feedback("<strong>Tip: </strong> You can use Alt-S to quickly save the widget.");
		}
    }    
}

// -- standardPrintResultHandler
//
//
CodeEditorCommon.standardPrintResultHandler = function ()
{
    if (this.xmlhttp.readyState == 4)
    {
        try
        {
            var decodedResponse = JSON.parse(this.xmlhttp.responseText);
            if (decodedResponse.isError)
            {
                document.getElementById("feedbackArea").innerHTML = decodedResponse.errorCode + ": " + decodedResponse.message;
            }
            else
            {
                document.getElementById("feedbackArea").innerHTML = decodedResponse.message;
            } 
        }
        catch(ex) 
        {
            document.getElementById("feedbackArea").innerHTML = "ERROR: Unknown response:<br>" + this.xmlhttp.responseText;
        }
        
        //CodeEditorCommon.ajaxFloaterStatus.KillMe();
    }
}


// -- diffhandler
//
//
CodeEditorCommon.diffhandler = function ()
{
    if (this.xmlhttp.readyState == 4)
    {
        try
        {
            var decodedResponse = JSON.parse(this.xmlhttp.responseText);
        }
        catch(e)
        {
            // we do nothing because if the code didn't eval then it obviously isn't a 
            // JSON error response.
            var decodedResponse = { isError : false };        
        } 

        if (decodedResponse && decodedResponse.isError)
        {
            document.getElementById("feedbackArea").innerHTML = decodedResponse.message;
        } 
        else 
        {
            document.getElementById("diffResultsContainer").innerHTML = this.xmlhttp.responseText;
        }
        
        //CodeEditorCommon.ajaxFloaterStatus.KillMe();
        CodeEditorCommon.applicationState.DiffViewGenerated = true;      
    }    
}

/*
*
*   Event handlers - button handlers, stuf flike that
*
*/

// -- displaySelectedDiff 
//
// displays a diff of the current version verses that selected from the SELET box
CodeEditorCommon.displaySelectedDiff = function ()
{
	// clear whatever is there.  This is not needed in functional terms, the contents
	// is overwritten - but in FF, if content exists when we set the content, and the
	// previous/existing contents is more than one page long, then the DIV is sized
	// incorrectly and the code editor goes over one page :(
	document.getElementById("diffResultsContainer").innerHTML = "";

    // we may not have any previous sources, in that case we can't show anything.
    if (previousSources.length == 0)
        return;

    var wsId = document.getElementById("previousSourceListSELECT").value; //selectObject.value;  // the id of the source to diff against.
    
    var req = "{ action : 'getCodeDiff', newWidgetSourceId : " + widgetSourceId + ", " +
                 "oldWidgetSourceId : " + wsId + ", codeType : \"javascript\" }";

    CodeEditorCommon.makeAPICall(req, CodeEditorCommon.diffhandler, true, "Generating diff...");
}


// -- selectActiveButton
//
// selects the active button
CodeEditorCommon.selectActiveButton = function (viewToSelect)
{
	for (i = 0; i < CodeEditorCommon.availableViews.length; i++)
	{
		if (CodeEditorCommon.availableViews[i] == viewToSelect)
		{
			CodeEditorCommon.setViewStyle(document.getElementById("btnView_" + viewToSelect), "selectedLink");
		}
		else
		{
			if ((CodeEditorCommon.availableViews[i] == "javascript") &&
				CodeEditorCommon.applicationState.isSourceUrlInUse)
			{
				CodeEditorCommon.setViewStyle(document.getElementById("btnView_" + CodeEditorCommon.availableViews[i]), "disabledLink");
			}
			else
			{
				CodeEditorCommon.setViewStyle(document.getElementById("btnView_" + CodeEditorCommon.availableViews[i]), "unselectedLink");			
			}
		}
	}
}

// -- doSelectProcessingForView
//
// runs the appropriate deselection code for the 
CodeEditorCommon.doDeselectProcessingForView = function (viewToDeselect)
{
	if (viewToDeselect == "javascript") // don't want to save Config Template stuff.
		CodeEditorCommon.deselectCodeView(CodeEditorCommon.currentView);
	else if (viewToDeselect == "configTemplate")
		CodeEditorCommon.deselectConfigTemplateView();
	else if (viewToDeselect == "diff")
		CodeEditorCommon.deselectDiffView();
	else if (viewToDeselect == "details")
		CodeEditorCommon.deselectDetailsView();
}


// -- deselectCodeView
//
// does the tidying up when moving away from a code window.
CodeEditorCommon.deselectCodeView = function (viewToDeselect, skipData)
{
	//if (! skipData)
	//	CodeEditorCommon.code[viewToDeselect] = CodeEditorCommon.codeProcessor.getFromCodeArea();
    document.getElementById("codeArea").style.display = "none";
	document.getElementById("feedbackAreaContainer").style.display = "none";    
}


// -- selectCodeView
//
//
CodeEditorCommon.selectCodeView = function (viewToSelect)
{
	if (CodeEditorCommon.applicationState.isSourceUrlInUse || CodeEditorCommon.currentView == viewToSelect)
		return;
	
	CodeEditorCommon.doDeselectProcessingForView(CodeEditorCommon.currentView);

	document.getElementById("feedbackAreaContainer").style.display = "block";
    document.getElementById("codeArea").style.display = "inline";

	// set the button styles.
	CodeEditorCommon.selectActiveButton(viewToSelect);
	
    // save for later.
	CodeEditorCommon.currentView = viewToSelect;
}

// -- deselectDiffView
//
// this does all the tidying up when leaving a diff view.
CodeEditorCommon.deselectDiffView = function ()
{
	// what are we doing here?  If we just display=none and display=block it, then what happens in FF is that when returing
	// to the Diff screen it expands the container DIV to be the height of the DIFF document meaning that the code editor
	// suddenly expands way beyond the windows size (assuming document is that big, of course).  So we have to save the contents
	// of the DIFF results and then restore it later.
	CodeEditorCommon.tabContents.diffViewHtml = document.getElementById("diffResultsContainer").innerHTML;
	document.getElementById("diffResultsContainer").innerHTML = "";

	// now hide it.
	document.getElementById("diffContainer").style.display = "none";
}

// -- selectDiffView
//
// This is not what's called when the user changes the source type drop down, or version
// to diff again (that is displaySelectedDiff().  This is called as a diff only version of 
// selectCodeView().
CodeEditorCommon.selectDiffView = function ()
{
	if (CodeEditorCommon.currentView == "diff") // return if we're already in diff.
		return;
	
	if (! CodeEditorCommon.applicationState.Initialized)
	{
		CodeEditorCommon.feedback("Application is still initializing (please wait before switching views)....");
		setTimeout(function() { CodeEditorCommon.feedback(''); }, 2000);
		return;
	}

	CodeEditorCommon.doDeselectProcessingForView(CodeEditorCommon.currentView);
	
    //document.getElementById("saveCurrentLinkContainer").style.display = "none";
    //document.getElementById("diffViewDummyLink").style.display = "block";
    

	// flow:
	// set display of DIFF_CONTAINER
	// set display styles for NAV TABs
	// set what view we're in.
	
	// make diff area visible
    document.getElementById("diffContainer").style.display = "block";
	
	// what's this all about?  IF we simply set the .innerHTML here, then firefox (why?!!!) will set the whole DIV size to match
	// that of the containing contents - so the code editor window becomes misshaped.  If we delay it by 100ms then it's fine.
	setTimeout( function () {
			document.getElementById('diffResultsContainer').innerHTML = CodeEditorCommon.tabContents.diffViewHtml;
		}
		, 100);

	//
    // reset our tab styles. (the select buttons)
    //
	// set the button styles.
	CodeEditorCommon.selectActiveButton("diff");
    
    // save for later.
	CodeEditorCommon.currentView = "diff";
	
	CodeEditorCommon.displaySelectedDiff();
}


// -- deselectDetailsView
//
// this does all the tidying up when leaving the details view.
CodeEditorCommon.deselectDetailsView = function ()
{
	// now hide it.
	document.getElementById("detailsContainer").style.display = "none";
}

// -- selectDetailsView
//
// This is not what's called when the user changes the source type drop down, or version
// to diff again (that is displaySelectedDiff().  This is called as a diff only version of 
// selectCodeView().
CodeEditorCommon.selectDetailsView = function (forceView)
{
	if (CodeEditorCommon.currentView == "details") // return if we're already in diff.
		return;
	
	if (!forceView)
	{
		if (! CodeEditorCommon.applicationState.Initialized)
		{
			CodeEditorCommon.feedback("Application is still initializing (please wait before switching views)....");
			setTimeout(function () { CodeEditorCommon.feedback(''); }, 2000);
			return;
		}
	}

	CodeEditorCommon.doDeselectProcessingForView(CodeEditorCommon.currentView);
	
    //document.getElementById("saveCurrentLinkContainer").style.display = "none";
    //document.getElementById("diffViewDummyLink").style.display = "block";
    

	// flow:
	// set display of DIFF_CONTAINER
	// set display styles for NAV TABs
	// set what view we're in.
	
	// make diff area visible
    document.getElementById("detailsContainer").style.display = "block";
	
	//
    // reset our tab styles. (the select buttons)
    //
	// set the button styles.
	CodeEditorCommon.selectActiveButton("details");
    
    // save for later.
	CodeEditorCommon.currentView = "details";
	
	if (pageMode == "edit")
		document.getElementById("widgetDefaultWidth").focus();
}




// -- deSelectConfigTemplateView
//
// does all the deselection processing for the Config TEmplate designer.
CodeEditorCommon.deselectConfigTemplateView = function ()
{
	// save configTemplate contents.
	// we need to collect all the infomration stored in the textboxes / controls on the Config Element view.
	CodeEditorCommon.designersCollection.collectInfo();
	
	
	// blank the HTML. (to avoid FF spilling it over one page view when returning)
	document.getElementById("divConfigTemplateDesignerContainer0").innerHTML = "";
	
	// now hide it
	document.getElementById("configTemplateContainer").style.display = "none";
	// force it to be small.
	//document.getElementById("configTemplateContainer").style.height = "100px";
	//document.getElementById("bodyElement").style.overflow = "hidden";	
}


// -- selectConfigTemplateView
//
// Called on the "Config Template" tab.
CodeEditorCommon.selectConfigTemplateView = function ()
{
	if (CodeEditorCommon.currentView == "configTemplate") // return if we're already in diff.
		return;
		
	if (! CodeEditorCommon.applicationState.Initialized)
	{
		CodeEditorCommon.feedback("Application is still initializing (please wait before switching views)....");
		setTimeout(function () { CodeEditorCommon.feedback(''); }, 2000);
		return;
	}
		
	
	// Save whatever code we were looking at.
	CodeEditorCommon.doDeselectProcessingForView(CodeEditorCommon.currentView);
	
	if (pageMode == "edit")
	{
		/*document.getElementById("saveCurrentLink").innerHTML = "Save Config Template";
		document.getElementById("saveCurrentLink").title = "Saves the Configuration Template";*/
		//document.getElementById("saveCurrentLinkContainer").style.display = "block";
	    //document.getElementById("diffViewDummyLink").style.display = "none";
	}
	
	document.getElementById("divConfigTemplateDesignerContainer0").innerHTML = "Loading...";
	
	if (!CodeEditorCommon.applicationState.ConfigElementsLoaded)
	{
		setTimeout(function () { CodeEditorCommon.getConfigElements(); }, 150); // this loads the config elements into the CodeEditorCommon object
	}
	else
	{
		// what's this all about?  IF we simply set the .innerHTML here, then firefox (why?!!!) will set the whole DIV size to match
		// that of the containing contents - so the code editor window becomes misshaped.  If we delay it by 100ms then it's fine.
		//setTimeout("CodeEditorCommon.getConfigElements()", 1000); // this loads the config elements into the CodeEditorCommon object
		
		// was the callback: function(){document.getElementById('configTemplateContainer').style.height='100%';}
		setTimeout(function() { CodeEditorCommon.designersCollection.renderConfigElementDesigners(); }, 150);
	}
	
	// make visible our thing.
    document.getElementById("configTemplateContainer").style.display = "block";	

    // reset our tab styles.
	CodeEditorCommon.selectActiveButton("configTemplate");

    // save for later.
	CodeEditorCommon.currentView = "configTemplate";
	
	//document.getElementById("bodyElement").style.overflow = "scroll";
    //document.getElementById("configTemplateContainer").style.overflow = "auto";
    
    if (!CodeEditorCommon.applicationState.ConfigTemplateBeenOpened)
    {
		CodeEditorCommon.onresize();
		CodeEditorCommon.applicationState.ConfigTemplateBeenOpened = 1;
	}
}



// -- getConfigElements
//
// 
CodeEditorCommon.getConfigElements = function () 
{
	// { action : 'getConfigElements', widgetSourceId : 79}
	var requestObj = { action : 'getWidgetConfigElements', 
					   widgetSourceId : widgetSourceId };

	CodeEditorCommon.makeAPICall(requestObj, CodeEditorCommon.getConfigElementsHandler, true, "Fetching widget attributes...");
}


CodeEditorCommon.codeEvaler = function (code)
{
	return eval(code);
}

// -- getConfigElementsHandler
//
// callback for the AJAX call to get the config elements
CodeEditorCommon.getConfigElementsHandler = function ()
{
	var configElementsTemp = null;
	
    if (this.xmlhttp.readyState == 4)
    {
        // save the source code into local variable
        try
        {
			configElementsTemp = CodeEditorCommon.codeEvaler(this.xmlhttp.responseText);
            //eval("var configElementsTemp = " + this.xmlhttp.responseText);
            //var configElementsTemp = JSON.parse(CodeEditorCommon.xmlhttp.responseText);
            if (configElementsTemp.isError)
            {
                //alert("Error " + configElementsTemp.errorCode + ": " + configElementsTemp.message);
				document.getElementById("divConfigTemplateDesignerContainer0").innerHTML = "There was a problem loading the configuration template: " + configElementsTemp.message + " (" + configElementsTemp.errorCode + ")";
            }
        }
        catch(ex) 
        {
			alert("ERROR: Unknown response:<br>" + this.xmlhttp.responseText + " (" + ex + ")");
        }
        
        // this is out here (and not just on the else{} of the if() after the eval()) because if it's up there then any javascript
        // code errors wouldn't be handled in the proper way but would be caught by that catch above and sent to the feedback window.
        if (!configElementsTemp.isError)
        {
			CodeEditorCommon.applicationState.ConfigElementsLoaded = true;	
        
			CodeEditorCommon.feedback("Loaded widget attributes successfully.");
			
			CodeEditorCommon.designersCollection.elementDesigners = configElementsTemp;
			
			CodeEditorCommon.designersCollection.updateContainerIds();
						
			CodeEditorCommon.designersCollection.renderConfigElementDesigners();			

			CodeEditorCommon.designersCollection.runChildrenChanged();			
        }
    }
}

// -- formElementFocus
// 
//
CodeEditorCommon.formElementFocus = function ()
{
	CodeEditorCommon.applicationState.isEditing = true;
}

// -- formElementUnfocus
// 
//
CodeEditorCommon.formElementUnfocus = function ()
{
	CodeEditorCommon.applicationState.isEditing = false;
}



// -- setCodeDirty
//
//
CodeEditorCommon.setCodeDirty = function(state)
{
	CodeEditorCommon.applicationState.isCodeDirty = state;
}
// -- setConfigTemplateDirty
//
//
CodeEditorCommon.setConfigTemplateDirty = function(state)
{
	CodeEditorCommon.applicationState.isConfigTemplateDirty = state;
}

// -- setWidgetDetailsDirty
//
//
CodeEditorCommon.setWidgetDetailsDirty = function(state)
{
	CodeEditorCommon.applicationState.isWidgetDetailsDirty = state;
}


// -- touchWidgetDetails
//
// called on the keypress event for each of the input fields making up the Widget
// Details
CodeEditorCommon.touchWidgetDetails = function(obj)
{
	CodeEditorCommon.setWidgetDetailsDirty(true);
}


// -- onresize
//
// resizes the main code editing window
CodeEditorCommon.onresize = function ()
{
    if (window.innerHeight != null)
    {
        document.getElementById("sizer-table").height = window.innerHeight - 87 - 24; // 24 == the top title area with dashed-line below it
    }
    else if (!window.innerHeight && document.body.clientHeight != null)
    {
        document.getElementById("sizer-table").height = document.body.clientHeight - 87 - 24;
    }
    
    
    if (window.innerHeight != null)
    {
        document.getElementById("divConfigTemplateDesignerContainerContainer").style.height = (window.innerHeight - 87 - 70 - 111) + "px";
    }
    else if (!window.innerHeight && document.body.clientHeight != null)
    {
        document.getElementById("divConfigTemplateDesignerContainerContainer").style.height = (document.body.clientHeight - 87 - 70 - 112) + "px";
    }
      /* 
    //alert(document.getElementById("tdConfigTemplateContainer").clientHeight);
    var configTemplateContainerHeight = document.getElementById("tdConfigTemplateContainer").clientHeight;
    var divConfigTemplateContainer = document.getElementById("configTemplateContainer").clientHeight;
	alert(configTemplateContainerHeight + " " + divConfigTemplateContainer);
    if (configTemplateContainerHeight != 0)
    {
		document.getElementById("divConfigTemplateDesignerContainerContainer").style.height = (document.getElementById("tdConfigTemplateContainer").clientHeight - 5) + "px";
	}*/
}


// -- onBeforeUnload handler
//
// enables a message to be shown to user warning them they may lose data if
// they haven't saved their code.
CodeEditorCommon.onbeforeunloadHandler = function (e)
{
    if (pageMode == "edit" && !CodeEditorCommon.applicationState.IgnoreLeavingSiteConfirmation)
    {
		var message = "";
		
		if (CodeEditorCommon.applicationState.isCodeDirty && CodeEditorCommon.applicationState.isConfigTemplateDirty)
		{
			message = "javascript code and configuration template";
		} 
		else if (CodeEditorCommon.applicationState.isCodeDirty)
		{
			message = "javascript code";
		}
		else if (CodeEditorCommon.applicationState.isConfigTemplateDirty)
		{
			message = "configuration template";
		}
		
		if (message != "")
		{
			return "You have changed the " + message + " since saving.  If you exit you will lose these changes.";
		}
    }
}


// -- Key press handler
// 
// currently only setup in FF, but could be attached in IE if needed. just
// traps backspace at the mo.  have to do that in FF in here.
CodeEditorCommon.onkeypressHandler = function (e)
{
    var evt = (window.event) ? window.event : e;
    var selAnchor = window.getSelection().anchorNode;
    var isAnnotating = (selAnchor != null) && (selAnchor.id == "cgAnnotationDivContainer");
    // var isEditing = selAnchor.nodeName == "INPUT" || selAnchor.nodeName == "TEXTAREA";    
    
    if (!window.event && evt.keyCode == 8 && !isAnnotating && 
        !CodeEditorCommon.applicationState.isEditing           ) {// trap and disable backspace in moz.
        if (!CodeEditorCommon.applicationState.shownBackspaceMessage)
        {
            document.getElementById("feedbackArea").innerHTML = 
                "The backspace key has been disabled on this page so that you do not lose work by accidentially hitting it.  If you'd like to go back please use the back button in your browser.  Sorry for the inconvinience.";
            CodeEditorCommon.applicationState.shownBackspaceMessage = true;
        }
        return false;
    }
}


// -- Key down handler
//
// just traps backspace at the mo, have to do that here for IE.  is setup on FF but does nothing - might
// be needed for cancelling default Ctrl-S etc, events.
CodeEditorCommon.onkeydownHandler = function (e)
{
    evt = (window.event) ? window.event : e;
    
    var parentElem = null;
    
    if (document.selection)
    {    
		parentElem = document.selection.createRange().parentElement();
	}
	else
	{
		parentElem = window.getSelection().getRangeAt(0).startContainer;
	}
    
    if (window.event && evt.keyCode == 8 && 
        (parentElem.id != "cgAnnotationComment" && parentElem.nodeName != "INPUT" && parentElem.nodeName != "TEXTAREA") ) { // trap and disable backspace in IE
        if (!CodeEditorCommon.applicationState.shownBackspaceMessage)
        {
            document.getElementById("feedbackArea").innerHTML = 
                "The backspace key has been disabled on this page so that you do not lose work by accidentially hitting it.  If you'd like to go back please use the back button in your browser.  Sorry for the inconvinience.";
            CodeEditorCommon.applicationState.shownBackspaceMessage = true;
        }
        return false;
    }
    
    /*if (!window.event && evt.ctrlKey && evt.keyCode == 83)
    {
		alert('a');
		evt.preventDefault();
		evt.stopPropagation();
		return false;
    }*/
}




// -- codeviewLinkMouseOver
//
//
CodeEditorCommon.codeviewLinkMouseOver = function (obj)
{
	if ((obj.id == "btnView_javascript" || obj.id == "btnView_configTemplate") &&
		CodeEditorCommon.applicationState.isSourceUrlInUse)
	{
		return;
	}
	
	if (obj.id == "btnView_" + CodeEditorCommon.currentView)
	{
	}
	else
	{
		CodeEditorCommon.setViewStyle(obj, "highlightedLink");
	}
}

// -- codeviewLinkMouseOut 
//
//
CodeEditorCommon.codeviewLinkMouseOut = function (obj)
{
	if ((obj.id == "btnView_javascript" || obj.id == "btnView_configTemplate") &&
		CodeEditorCommon.applicationState.isSourceUrlInUse)
	{
		return;
	}

	if (obj.id == "btnView_" + CodeEditorCommon.currentView)
	{
		CodeEditorCommon.setViewStyle(obj, "selectedLink");
	}
	else
	{
		CodeEditorCommon.setViewStyle(obj, "unselectedLink");
	}
}

// -- expandFeedbackArea
//
// 
CodeEditorCommon.expandFeedbackArea = function()
{
    if (codeArea.document.body.clientHeight > 200)
    {
        newSize = (document.getElementById("feedbackStatusAreaContainer").height)*1 + 15;
        CodeEditorCommon.setCodeAreaSize(newSize);
    }
}

// -- shrinkFeedbackArea
//
//
CodeEditorCommon.shrinkFeedbackArea = function()
{
    newSize = document.getElementById("feedbackAreaContainer").height - 15;
    if (newSize > 59)
    {
        CodeEditorCommon.setCodeAreaSize(newSize);
    }
}

CodeEditorCommon.setCodeAreaSize = function (size)
{
    document.getElementById("feedbackStatusAreaContainer").height = size;
}


/*
*
* Factory methods
*
*/
 
// Code Editor Processor Factory
//
// -- factory method whihc gets an object to handler all the browser specific processing
CodeEditorCommon.getProcessorFactory = function ()
{
    var processor = null;
    if (LKBrowser.is_ua_ie)
    {
        processor = new CEPIE();
    }
    
    if (LKBrowser.is_ua_moz)
    {
        processor = new CEPMOZ();
    }
    
    return processor;
} 
