//****************************************************************************************
//
//	display.js
//
//	Objects to support the combination of data and display for Web page display and updating
//
//	Depends On:
//					Style Sheet Class definitions (optional)
//					global.js
//
//	Copyright: 	David Horne, Tuross Technologies Australia P/L
//				dkhorne@bigpond.net.au
//
//****************************************************************************************

//****************************************************************************************
//	Tabset Object
//****************************************************************************************
	function TabSet(Name, Target, controlOptions) {

	//	Tabset Details
		this.Name = Name;								//	Name of Tabset
		this.Target = Target;							//	Target for Tabset to be displayed
		this.Options = new Options(controlOptions);		//	Controls the display of the tabs
		this.Default = "";								//	The Default tab
		
		this.SelectedTab = "";							//	Name of selected Tab
		this.ActiveTab = null;							//	Points to Tab that is active

	//	Tabs object		
		this.Tabs = new Object();						//	Tab objects

	//	Tab methods
		//	Initilise the tabset
		this.Init =					function(Default) {
										this.SelectedTab = (((Default != null) && (this.Tabs[Default] != null)) ? Default : this.Default);

										for (var item in this.Tabs) {
											if (this.Tabs.hasOwnProperty(item)) {
												this.Tabs[item].Object = DOM.getElementById(this.Tabs[item].Target);
												if (this.Tabs[item].Object == null) {
													alert("The tab target for " + this.Tabs[item].Name + " could not be found. Tab is being disabled.");
													this.Tabs[item].Enabled = false;
												} else {
													this.Tabs[item].Object.style.display = "none";
//													this.Tabs[item].Enabled = true;

													if (this.SelectedTab == "")
														this.SelectedTab = item;
												}
											}
										}
										this.Select();
									}
	
		// Adds a new Tab		
		this.AddTab = 				function(Name, Label, Target, Init, Default) {
										if (this.Tabs[Name] == null) {
											this.Tabs[Name] = {'Name': Name, 'Label': Label, 'Target': Target, 'Init': Init, 'Enabled': true};
											if ((Default) || (this.Default == ""))
												this.Default = Name;
										} else {
											alert("Tab - " + Name + " already exists.");
										}
									}

		//	Select a tab
		this.Select = 				function(Tab) {
										Tab = (Tab != null ? Tab : this.SelectedTab);
										
										if (this.Tabs[Tab] != null) {
											this.SelectedTab = Tab;
											this.Render();
											this.Activate();
										} else {
											alert("Tab - " + Tab + " does not exist.");
										}
									}


	//	Tab display settings
		var Tab_Text = "<a href=\"javascript:[TABSET].Select('[TAB]')\">[TABLABEL]</a>"	

		var Mid_On = "<div class='tab-on-mid'>[TABLABEL]</div>"
		var Left_On = "<div class='tab-on-left'></div>"
		var Right_On = "<div class='tab-on-right'></div>"
		var Right_End_On = "<div class='tab-on-end'></div>"

		var Mid_Off = "<div class='tab-off-mid'>[TABLABEL]</div>"
		var Left_Off = "<div class='tab-off-left'></div>"
		var Right_Off = "<div class='tab-off-right'></div>"
		var Right_End_Off = "<div class='tab-off-end'></div>"

		//	Displays the Tabset
		this.Render =				function() {
										var strTabs = [], strTabText;
										var first = true;
										var selectedID = -1;
										
										for (var item in this.Tabs) {
											if (this.Tabs.hasOwnProperty(item)) {
												if (this.Tabs[item].Enabled) {
													strTabText = Tab_Text.replace(/\[TABSET\]/g, this.Name);
													strTabText = strTabText.replace(/\[TAB\]/g, item);
													strTabText = strTabText.replace(/\[TABLABEL\]/g, this.Tabs[item].Label);
												} else {
													strTabText = this.Tabs[item].Label;
												}

												strTabs.push((item == this.SelectedTab ? Left_On : Left_Off));
												strTabs.push((item == this.SelectedTab ? Mid_On : Mid_Off).replace(/\[TABLABEL\]/g, strTabText));
												strTabs.push((item == this.SelectedTab ? Right_On : Right_Off));
												if (item == this.SelectedTab)
													selectedID = strTabs.length - 2;
											}
										}
										strTabs.pop();
										strTabs.push(((item == this.SelectedTab) ? Right_End_On : Right_End_Off));
										
										//	hide the first end if specified
										if (this.Options.Get("HideFirstEnd", "false", "boolean"))
											strTabs[0] = "";

										//	if selected end images over write the off end images
										if (this.Options.Get("OverwriteOffEnds", "false", "boolean")) {
											strTabs[selectedID + 2] = "";
											strTabs[selectedID - 2] = "";
										}
										
										DOM.setInnerHTML(this.Target, strTabs.join(" "));
									}

		//	Activate selected Tab
		this.Activate = 			function() {
										for (var item in this.Tabs) {
											if (this.Tabs.hasOwnProperty(item)) {
												if (this.Tabs[item].Enabled) {
													if (item == this.SelectedTab) {
														this.Tabs[item].Object.style.display = "block";
														try {
															if (this.Tabs[item].Init != null) eval(this.Tabs[item].Init);
														}
														catch (err) {
															alert("Cannot activate selected tab." + err.description);
														}
													} else {
														this.Tabs[item].Object.style.display = "none";
													}
												}
											}
										}
									}

		
		self[Name] = this;
	}

//****************************************************************************************
//	Button Object
//****************************************************************************************

	function Button(Name, Text, controlOptions) {
		this.Name = Name;
		this.ID = "but" + Name + "." + UIManager.ButtonCount++;
		this.Text = Text;
		this.URL = null;
		this.Target = null;
		this.Lock = false;

		this.Options = new Options(controlOptions);
		this.Options.SetIfNull("OnClass", "button-on");
		this.Options.SetIfNull("OverClass", "button-on");
		this.Options.SetIfNull("OffClass", "button-off");
		this.Options.SetIfNull("TextClass", "button-text");
		this.Options.Set("onclick", "UI_Buttons." + this.Name + ".Click(); " + this.Options.Get("onclick", ""));

		this.Active = true;
		this.Clicked = false;
		this.Locked = false;
			
		this.Link =	UIManager.Button_Link;
		this.Render = UIManager.Button_Render;
		this.Click = UIManager.Button_Click;
		this.SetState = UIManager.Button_SetState;
	}
		
//****************************************************************************************
//	FileUpload Manager
//****************************************************************************************

	var FileManager = new function() {
		return {
			Fields: {},
			Frames: {},
			
			Init:						function(displayName, processingFile) {
											var id = displayName + "_fileframe";
											this.Frames[id] = {frame: null, ready: false, callingID: ""};
											DialogManager.New(id, processingFile, FileManager.Callback);
										},
										
			FrameID:					function(elementid) {
											var element = UIManager.ParseID(elementid);
											return element.Display + "_fileframe";
										},

			Callback:					function(frame) {
											var id = frame.name;
											if (FileManager.Frames[id] == null) {
												alert("Unable to process FileManager callback. Frame not found.");
												return;
											}
											
											switch (frame.Action.toLowerCase()) {
												case "init":
													FileManager.Frames[id].frame = frame;
													FileManager.Frames[id].ready = frame.Ready;
													break;
													
												case "cancel":
													DialogManager.Close(id);
													break;
													
												case "submit":
													DialogManager.Close(id);
													var frameDetails = FileManager.Frames[id];
													switch (frame.Status.toLowerCase()) {
														case "error":
															alert("Error uploading file. " + frame.ErrorMessage);
															break;
															
														case "ok":
															var Results = frame.Results;
															DOM.setInnerHTML(frameDetails.callingID + ".Display", Results.FileName);
															DOM.setValue(frameDetails.callingID, Results.FilePath);
															break;
													}
													frameDetails.callingID = "";
													frameDetails.ready = true;
													break;
											}
										}, 
						
			Ready:						function(displayName) {
											var id = displayName + "_fileframe";
											return ((this.Frames[id] != null) && this.Frames[id].ready);
										},
			
			Add:						function(displayName, fieldName, processFile) {
											var ID = displayName + "." + fieldName;
											this.Fields[ID] = {name: fieldName, processFile: processFile};
											return ID;
										},
										
			Render:						function(ID) {
										},
										
			Browse:						function(element) {
											var field = UIManager.FindField(element.id);
											if (field == null) {
												message.raise("FileManager", "Error", "Cannot browse file for uploading.", "Invalid Field ID " + ID, false);
												return;
											}

											id = this.FrameID(element.id);
											if (!this.Frames[id].ready) {
												message.raise("FileManager", "Error", "Cannot browse file for uploading.", "This file browser is already in use.", false);
												return;
											}
											this.Frames[id].callingID = element.id;
											this.Frames[id].ready = false;
											
											var controlOptions = 
												{
													"Title": field.Options.Get("Title", "Select File"),
													"Description": field.Options.Get("Description", "Select a file to upload for this form."),
													"Action": field.Options.Get("Action", ""),
													"Target": field.Options.Get("Target", "")
												};
											DialogManager.Open(id, controlOptions);
										},
										
			Save:						function() {
			
										}
		}
	}();
		


//****************************************************************************************
//	Field Object - manages the formating of individual fields for a display
//			Types
//				text		basic text
//				number		basic number
//				boolean		basic boolean
//
//				list		list of values
//				image		image
//				button		control button
//				link		link
//				file		file upload
//				
//****************************************************************************************
	function Field(name, expression, type, renderOptions, defaultOptions) {
		this.Name = name;													//	Name of Field
		this.Expression = expression;										//	The expression that determines the data to be displayed
		this.Type = type.toLowerCase();										//	The type of the field
		this.Options = new Options(renderOptions);							//	Controls the rendering of the field;
		this.ViewMode = this.Options.Get("ViewMode", "View");				//	Controls the mode of view - hide, view.
		this.EditMode = this.Options.Get("EditMode", "Edit");				//	Controls the mode of edit - hide, view, edit.
		this.Mandatory = this.Options.Get("Mandatory", "false", "boolean");	//	Specifies if the field is mandatory
		
		//	Set certain default values if necessary
		this.Options.Set("onchange", "UIManager.OnChange(this); " + this.Options.Get("OnChange", ""));
		
		if (type.toLowerCase() == "boolean")
			this.Options.SetIfNull("type", "checkbox");
			
		this.Options.SetIfNull("class", defaultOptions.Get("FieldClass", ""));

		//	Set HTML templates based on ViewMode/EditMode
		this.ListItems = [];
		
		//	Loads the list item array from an array
		this.LoadListItems =			function(listItems, display, value) {
											this.ListItems = [];
											if ((listItems != null) && (listItems instanceof Array)) {
												if (display != null) {
													value = (value != null ? value : display);
													for (var i = 0; i < listItems.length; i++)
														this.ListItems.push([listItems[i][value], listItems[i][display]]);
												} else {
													for (var i = 0; i < listItems.length; i++)
														this.ListItems.push([listItems[i], listItems[i]]);
												}
											}
										}
		
		//	Converts a string into list items
		this.ParseListItems =			function(listItems, itemDelim, valueDelim) {
											itemDelim = (itemDelim != null ? itemDelim : "||");
											valueDelim = (valueDelim != null ? valueDelim : "|");

											this.ListItems = [];
											var Items = listItems.split(itemDelim);
											var Item;
											for (var i = 0; i < Items.length; i++) {
												Item = Items[i].split(valueDelim);
												this.ListItems.push([(Item[1] != null ? Item[1] : Item[0]), Item[0]]);
											}
										}
		

		//	Takes the data input and returns the field HTML
		this.Render =					function(parentID, iData, data, edit) {
											if (edit && (this.EditMode.toLowerCase() != "none"))
												var result = HTML.Render(this.Name, this.Type, (this.EditMode.toLowerCase() == "edit"), this.Options);
											else if (!edit && (this.ViewMode.toLowerCase() != "none"))
												var result = HTML.Render(this.Name, this.Type, false, this.Options);
											else
												return "";
		
											//	Set ID of field
											result = result.replace(/\[ID\]/g, parentID + "." + this.Name + "." + iData);
											
											//	Set the iData value (if it exists)
											result = result.replace(/\[iData\]/gi, iData);
	
											// Set the Value placeholder
											if (this.Options.IsSet("Value")) {
												result = result.replace(/\[VALUE\]/g, global.format(this.Options.Get("Value"), this.Type));
											} else {
												switch (this.Type.toLowerCase()) {
													case "list":
														if (edit)
															result = result.replace(/\[VALUE\]/g, this.FormatListItems(data));
														else
															result = result.replace(/\[VALUE\]/g, this.Format(data));
														break;
															
													case "boolean":
														if (edit)
															result = result.replace(/\[VALUE\]/g, (this.Value(data) ? "checked" : ""));
														else
															result = result.replace(/\[VALUE\]/g, (this.Value(data) ? "X" : ""));
														break;
														
													case "file":
														result = result.replace(/\[VALUE\]/g, this.Options.Get("Text", "Upload File"));
														break;
															
													case "image":
														result = result.replace(/\[VALUE\]/g, this.Options.Get("Source", "") + this.Format(data));
														break;
															
													case "password":
														break;
														
													default:
														result = result.replace("[VALUE]", this.Format(data));
														break;
												}
											}
											
											//	Evaluate the field against the data
											result = result.replace(HTML.reField, global.indirect(data)); 
											return result;
										}
		
		//	returns teh raw value of this field in data
		this.Value = 					function(data) {
											var result = null;
											try {
												if (HTML.reField.test(this.Expression)) 			//	calculated Field
													result = eval("\"" + this.Expression.replace(HTML.reField, "' + data.$1 + '") + "\"");
												else
													result = eval("data." + this.Expression);
											}
											catch (e) {}
											return result;
										}
										
		//	Format the field based on data
		this.Format = 					function(data) {
											var result = "";
											var value = this.Value(data);
											if (value != null) {
												value = (global.typeOf(value) == "array" ? value : [value])
												for (var i = 0; i < value.length; i++)
													result += (result != "" ? ", " : "") + global.format(value[i], this.Type);
											}
											return result;
										}
								
		//	Format the list items of the field
		this.FormatListItems = 			function(data) {
											var result = "";
											var value = this.Value(data);
											value = (value != null ? value : "");
											value = "[" + (global.typeOf(value) == "array" ? value.join("][") : value) + "]";
											for (var i = 0; i < this.ListItems.length; i++)
												result += "<option value='" + this.ListItems[i][1] + "'" + (value.indexOf("[" + this.ListItems[i][1] + "]") >= 0 ? " selected>" : ">") + this.ListItems[i][0] + "</option>";
											return result;
										}

		//	Get the value of this field.
		this.Extract =					function(parentID, iData, data) {
											var value = "";

											// Test to see if it is an editable field and not calculated
											if (HTML.reField.test(this.Expression))
												return true;

											var field = DOM.getElementById(parentID + "." + this.Name + "." + iData);
											if (field != null) {
												switch (this.Type.toLowerCase()) {
													case "list":
														if (this.Options.IsSet("Multiple")) {							// Multi Value
															value = new Array();
															for (var i = 0; i < field.length; i++) {
																if (field[i].selected)
																	value.push(global.parse(field[i].value.toString(), this.Type));
															}
														} else {
															value = global.parse(field.value.toString(), this.Type);	// Single Value
														}
														break;
														
													case "boolean":
														if ((field.tagName.toLowerCase() == "input") && (field.type.toLowerCase() == "checkbox"))
															value = field.checked;										// checkbox
														else
															value = global.isEmpty(field.innerHTML);
														break;
														
													case "file":
														value = field.value;
														break;
															
													case "image":
														value = field.src.replace(parameters.host + this.Options.Get("Source", ""), "");
														break;
															
													default:															// All other fields
														if (field.tagName.toLowerCase() == "input")
															value = (field.value != null ? global.parse(field.value.toString(), this.Type) : null);
														else
															value = global.parse(field.innerHTML, this.Type);
														break;
												}
											} else {
												value = null;
											}
												
											eval("data." + this.Expression + " = value");
											
											return !(this.Mandatory && global.isEmpty(value));
										}
	}
	
	
//****************************************************************************************
//	Panel Object - defines the layout of the fields
//****************************************************************************************
	function Panel(name, renderOptions) {
		this.Name = name;								//	Name of panel
		this.Options = new Options(renderOptions);		//	Options that control rendering of the panel

		this.Display = null;							//	Display this panel  associated with
		this.Prepared = false;							//	Indicates if the Panel has been prepared
		
		this.HTML = "";									//	Source HTML
		this.Fields = [];								//	Parsed HTML Object
		

		//	Prepares the Panel for rendering
		this.Parse =					function(html) {
											var FieldDef, Field, FieldAttributes;
											var IdDef;
											var SnippetOptions, SnippetHTML;
											
											this.Fields = [];
											
											var Snippet, reSnippet, SnippetMatch

											for (var i = 0; i < this.Display.Snippets.length; i++) {
												Snippet = this.Display.Snippets[i];
												reSnippet = new RegExp("<" + Snippet.name + "[^>]*?>", "gm");
												while ((SnippetMatch = reSnippet.exec(html)) != null)
												{
													SnippetHTML = Snippet.html;
													SnippetOptions = new Options(SnippetMatch[0]);
													for (var j = 0; j < Snippet.items.length; j++)
														SnippetHTML = SnippetHTML.replace("[" + Snippet.items[j] + "]", SnippetOptions.Get(Snippet.items[j], ""));
													html = html.replace(SnippetMatch, SnippetHTML);
												}
											}
											
											this.HTML = html;

											var reFields = /<field[^>]*?>/gim
											while ((FieldDef = reFields.exec(html)) != null)
											{
												Field = new Object()
												Field.Raw = FieldDef[0];
												Field.Attributes = new Options(FieldDef[0]);
												Field.Name = Field.Attributes.Get("name", "none");
	
												if (this.Display.Fields[Field.Name] != null) {
													this.Fields.push(Field);
													this.HTML = this.HTML.replace(FieldDef[0], "<" + Field.Name.toUpperCase() + ">");
													this.Display.Fields[Field.Name].Options.Parse(FieldDef[0], false);
												} else {
													this.HTML = this.HTML.replace(FieldDef[0], "");
												}
											}
										}
										
		//	Returns the HTML for this panel based on the Data
		this.Render =					function(data, iData, edit, displayIfEmpty) {
											var fldHTML, tmpHTML;
											var result = this.HTML;
											var ParentID = this.Display.Name + "." + this.Name + "." + (edit ? "edit" : "view");

											if (data instanceof DataRecord)
												data = data.Data;

											if ((data == null) && !displayIfEmpty)
												return "";
												
											for (var iFld = 0; iFld < this.Fields.length; iFld++) {
												if (this.Display.Fields[this.Fields[iFld].Name] != null) 
													fldHTML = this.Display.Fields[this.Fields[iFld].Name].Render(ParentID, iData, data, edit)
												else
													fldHTML = "";
													
												result = result.replace("<" + this.Fields[iFld].Name.toUpperCase() + ">", fldHTML);
											}
											return result;
										}
									
		//	Returns the data extracted from the panel
		this.Extract =					function(data, iData) {
											var ParentID = this.Display.Name + "." + this.Name + ".edit";
											var FieldID;
											var IsOK = true;

											if (data instanceof DataRecord)
												data = data.Data;

											if (data == null)
												return false;
												
											for (var iFld = 0; iFld < this.Fields.length; iFld++) {
												if (this.Display.Fields[this.Fields[iFld].Name] != null) 
													IsOK = this.Display.Fields[this.Fields[iFld].Name].Extract(ParentID, iData, data) && IsOK
											}
											
											return IsOK;
										}
	}
	
	
	
//****************************************************************************************
//	Display Object
//****************************************************************************************
	function Display(name, renderOptions) {
	
		this.Name = name;								//	Name of Display
		this.Options = new Options(renderOptions);		//	Controls the display render;
		
		this.Snippets = [];								//	Snippets
		this.Panels = new Object();						//	Display Panels associated with the Display
		this.Fields = new Object();						//	Display Fields associated with the Display
		this.ID	= new Object();							//	Elements identified by an ID
		
		//	Initialises the FileManager
		this.FileSupport =				function(processingFile) {
											if (FileManager == null) {
												alert("Unable to add file support to " + this.Name + ". Cannot access FileManager.");
												return;
											}
											FileManager.Init(this.Name, processingFile);
										};
		
		//	Adds a snippet of HTML
		this.Snippet =					function(name, html) {
											var item;
											var Snippet = {name: name, html: html, items: []};
											var reItems = /\[([A-Z]*?)\]/gm;
											while ((item = reItems.exec(html)) != null)
												Snippet.items.push(item[1]);
											
											this.Snippets.push(Snippet);
										}


		//	Creates a new Panel
		this.Panel =					function(name, html, renderOptions) {
											var NewPanel = new Panel(name, renderOptions);
											NewPanel.Display = this;
											NewPanel.Parse(html);
											this.Panels[name.toLowerCase()] = NewPanel;
											
											var reID = /ID\s*=\s*(['"]?)(.*?)\1/ig;					// Extract the ID from the Panel HTML
											while ((ID = reID.exec(NewPanel.HTML)) != null)
												this.ID[ID[2].toLowerCase()] = {'id': ID[2]};

											return NewPanel;
										};
										
		//	Creates a new Field
		this.Field =					function(name, expression, type, renderOptions) {
											var NewField = new Field(name, expression, type, renderOptions, this.Options);

											if (type.toLowerCase() == "file") {
												if (FileManager == null) {
													alert("Cannot access FileManager. Unable to add file field.");
													return null;
												}
												
//												if (!FileManager.Ready(this.Name)) {
//													alert("Filesupport has not been initialised. Unable to add file field.");
//													return null;
//												}
												
												NewField.Options.SetIfNull("onclick", "FileManager.Browse(this)");
												NewField.FileID = FileManager.Add(this.Name, name);
											}
											
											this.Fields[name] = NewField;
											return NewField;
										};
		
		//	Sets style attributes of various elements that have IDs set.
		this.SetStyle =					function(ID, Action, Value) {
											if (this.ID[ID.toLowerCase()] != null)
												this.ID[ID.toLowerCase()][Action.toLowerCase()] = Value;
										}
														
		//	Render the display
		this.Render =					function(data, edit) {
											var html = [], panel;
										
											if ((data == null) && !this.DisplayIfEmpty)
												return "";
												
											if (global.typeOf(data) != "array")
												data = [data];
											
											html.push("<div class='panel" + (this.Options.Get("border", "true", "boolean") ? " border" : "") + "'>");

											if (this.Panels.header != null)
												html.push(this.Panels.header.Render(data[0], "h", false, true));
											
											for (var iData = 0; iData < data.length; iData++) {
												if (iData % 2 == 0)
													panel = (this.Panels.even != null ? this.Panels.even : this.Panels.item);
												else
													panel = (this.Panels.odd != null ? this.Panels.odd : this.Panels.item);
													
												if (panel != null)
													html.push(panel.Render(data[iData], iData, edit, this.Options.Get("DisplayIfEmpty", "true", "boolean")));
											}

											if (this.Panels.footer != null)
												html.push(this.Panels.footer.Render(data[0], "f", false, true));
												
											html.push("</div>");

											return html.join("");
										};
										
		//	Display the display at the target
		this.Display =					function(data, edit, target) {
											var html = this.Render(data, edit);
											DOM.setInnerHTML(target, html);
											
											for (var id in this.ID) {
												if (this.ID.hasOwnProperty(id))
													for (var style in this.ID[id])
														if (this.ID[id].hasOwnProperty(style) && (style != "id"))
															DOM.setStyle(id, style, this.ID[id][style]);
											}
										};
										
		//	extract data a given panel
		this.Extract =					function(data, iRow) {
											var IsOK = true;
											if (global.typeOf(data) != "array")
												data = [data];
											
											for (var iData = 0; iData < data.length; iData++) {
												if ((iRow == null) || (iRow == iData)) {
													if (iData % 2 == 0)
														panel = (this.Panels.even != null ? this.Panels.even : this.Panels.item);
													else
														panel = (this.Panels.odd != null ? this.Panels.odd : this.Panels.item);
														
													if (panel != null)
														IsOK = panel.Extract(data[iData], iData) && IsOK;
												}
											}
											
											return IsOK;
										};
	}


//****************************************************************************************
//	Dialog Manager
//****************************************************************************************

// NOTES: USe JSON to define form fields to add to teh dialog. Store these as string in the 
// form to recreate it each time the dialog is created.

	var DialogManager = function() {
	
		return {
			Dialogs: {}, 
			Active: "",
		
			New :						function(name, srcFile, callback) {
											if (DialogManager.Dialog(name) == null) {
												var frame = document.createElement("iframe");
												frame.setAttribute("id", name);
												frame.setAttribute("name", name);
												frame.setAttribute("src", srcFile);
												frame.setAttribute("class", "dialog hide");
												frame.setAttribute("frameborder", "0");
												document.body.appendChild(frame);

												this.Dialogs[name] = {dialog: window.frames[name], callback: callback};
											} else {
												alert("Cannot create dialog called " + name + ". A dialog with that name already exists.");
											}
										},
										
			Dialog :					function(name) {
											if (DialogManager.Dialogs[name] != null)
												return DialogManager.Dialogs[name].dialog;
											else
												return null;
										},
										
			Callback :					function(name) {
											if (DialogManager.Dialogs[name] != null) {
												var dialog = DialogManager.Dialogs[name];
												if (dialog.callback != null)
													dialog.callback(dialog.dialog);
											}
										},
										
			Open :						function(name, controlOptions) {
											var dialog = this.Dialog(name);
											if (dialog != null) {
												dialog.frameElement.className = dialog.frameElement.className.replace("hide", "show")
												dialog.reset(controlOptions);
												Active = name;
											}
										},
										
			Close :						function(name) {
											name = (name != null ? name : Active);
											var dialog = this.Dialog(name);
											if (dialog != null) {
												dialog.frameElement.className = dialog.frameElement.className.replace("show", "hide");
												this.Callback(name);
											}
										}
		}
	}();
										



//****************************************************************************************
//	Global Displays Object
//****************************************************************************************

//****************************************************************************************
//	UI manager manages the various UI elements. 
//	ID always has format of::		DISPLAY.PANEL.EDITMODE.FIELDNAME.iDATA

	var UIManager = function() {

		return {
//****************************************************************************************
//	Several global methods
			ParseID :					function(elementID) {
											var objects = elementID.split(".");
											if (objects.length == 5)
												return {Display: objects[0], Panel: objects[1], EditMode: objects[2], Field: objects[3], iData: objects[4]};
											else
												return null;
										},

			FindField : 				function(elementID) {
											var objects = UIManager.ParseID(elementID);
											if ((objects != null) && (UIManager.Displays[objects.Display] != null) && (UIManager.Displays[objects.Display].Fields[objects.Field] != null))
												return UIManager.Displays[objects.Display].Fields[objects.Field];
											else
												return null;
										},
	
			OnChange : 					function(element) {
											field = UIManager.FindField(element.id);
											var fieldValue = element.value;

											if ((fieldValue != "") && (field != null) && (field.Type.toLowerCase() != "list") && (field.Type.toLowerCase() != "boolean")) {
												fieldValue = global.parse(fieldValue, field.Type);
												if (fieldValue != null) {
													element.value = global.format(fieldValue, field.Type);
													return true;
												} else {
													alert("Invalid " + field.Type.toLowerCase() + " value. Please try again.");
													window.setTimeout("DOM.setFocus('" + element.id + "')", 10);
													return false;
												}
											}
											return true;
										},
										
			//	Clears the target 
			Clear : 					function(target) {
											DOM.setInnerHTML(target, "");
										},

			//	Sets the target visibility 
			Visible : 					function(target, visible) {
											DOM.setStyle(target, "display", (visible ? "none" : "block"));
										},


//****************************************************************************************
//	Display support

			Displays: [],

//	Creates and returns a new display
			Display :		 			function(name) {
											this.Displays[name] = new Display(name);
											return this.Displays[name];
										},

//****************************************************************************************
//	Button support

			Buttons: [],

			ButtonCount: 0,
			LockedButton:	null, 

//	Creates and returns a new Button
			Button :					function(name, text, toolTip, controlOptions) {
											this.Buttons[name] = new Button(name, text, toolTip, controlOptions);
											return this.Buttons[name];
										},

			Button_Link:				function(URL, Target, Lock) {
											this.URL = URL;
											this.Target = Target;
											this.Lock = Lock;
										},
	
			Button_Render:				function() {
											var html = HTML.Render(this.Name, "button", true, this.Options);
											html = html.replace("[ID]", this.ID);
											html = html.replace("[VALUE]", this.Text);
											return html;
										},
	
			Button_Click:				function() {
											if (this.Clicked)
												return false;
		
											if ((UIManager.LockedButton != null) && (this != UIManager.LockedButton)) {
												UIManager.LockedButton.Clicked = false;
												UIManager.LockedButton = null;
											}

											if (this.Lock) {
												this.Clicked = true;
												UIManager.LockedButton = this;
											}

											if (this.URL != null) {
												try {
													eval(this.URL);
												}
												catch (e) {}
											}
										 },
	
			Button_SetState:			function(State, Value) {
											var TheButton = DOM.getElementById(this.ID);
											if (TheButton != null) {
												switch(State.toLowerCase()) {
													case "visible":
														TheButton.style.display = (global.parse(Value, "boolean") ? "block" : "hidden");
														break;
														
													case "enable":
														TheButton.disabled = !global.parse(Value, "boolean");
														break;
												}
											}
										}

		}
	}();
	var UI_Displays = UIManager.Displays;
	var UI_Buttons = UIManager.Buttons;
	var UI_Tabsets = UIManager.Tabsets;

