
	// TODO: clean up floating functions

	// -------------------------------------------------------------------
	// NewWindow
	// -------------------------------------------------------------------
	function NewWindow(theURL,winName,features) {
		if(!features) features = "width=860, height=1024,resizable=1,scrollbars=1,toolbar=1,location=1,directories=1,status=1,menubar=1,copyhistory=no";
		window.open(theURL,winName,features);
	}
	
	// -------------------------------------------------------------------
	// NoSubmit
	// -------------------------------------------------------------------
	function NoSubmit(charCode) {
		if(!charCode && window.event) charCode = window.event.keyCode;
		if(charCode == 13 || charCode == 3) {
			return false;
		}
		else {
			return true;
		}
	}
	
	// -------------------------------------------------------------------
	// DoSubmit
	// -------------------------------------------------------------------
	function DoSubmit(charCode, clickButton, form) {
		//wfx.Alert("DoSubmit");
		if(!$(form)) {
			wfx.Alert("No form specified for submit!");
		}
		else {
			if(!charCode) charCode = window.event.keyCode;
	
			if(charCode == 13 || charCode == 3) {
				button = $(form+clickButton);
				if(!button) {
					wfx.Alert("The button command '"+clickButton+"' does not exist");
				}
				else {
					if(button.href) {
						location.href = button.href;
					}
					else {
						button.onclick();
					}
				}
				return false;
			}
			else {
				return true;
			}
		}
	}

	// -------------------------------------------------------------------
	// SetClass
	// -------------------------------------------------------------------
	function SetClass(itemID, newClass, formID) {
		if(formID) {
			document.forms[formID].elements[itemID].className = newClass;
		}
		else {
			var item = $(itemID);
			if(item)
				item.className = newClass;
		}
	}

	// -------------------------------------------------------------------
	// SetField
	// -------------------------------------------------------------------
	function SetField(formID, fieldID, val) {
		//wfx.Alert(formID+"."+fieldID);
		if(formID) {
			if(document.forms[formID]) {
				var field = document.forms[formID].elements[fieldID];
				if(field) {
					field.value = val;
				}
				else {
					ERROR("Failed to load field "+fieldID+" from from "+formID+".");
				}
			}
		}
	}

	// -------------------------------------------------------------------
	// createCookie
	// -------------------------------------------------------------------
	function createCookie(name,value,days) {
		//wfx.Alert("createCookie("+name+", "+value+", "+days+")");
		if (days) {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
		}
		else var expires = "";
		document.cookie = name+"="+value+expires+"; path=/";
	}
	
	// -------------------------------------------------------------------
	// readCookie
	// -------------------------------------------------------------------
	function readCookie(name) {
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
		}
		return null;
	}
	
	// -------------------------------------------------------------------
	// eraseCookie
	// -------------------------------------------------------------------
	function eraseCookie(name) {
		//wfx.Alert("eraseCookie("+name+")");
		createCookie(name,"",-1);
	}

//-----------------------------------------------------------------------------------------------------------------------------
//: wfx
//-----------------------------------------------------------------------------------------------------------------------------
// This provides the global namespace for all wfx code. This file should contain only definitions for 
// primitive objects unique to the wfx framework. 
//
// Structure:
// Any new code should be added as a new object literal within the wfx context (ie wfx.NewObject). 
// Any object with an Init function will be called at domready and Unload when the user changes the 
// page.
//-----------------------------------------------------------------------------------------------------------------------------
var wfx = {
	Version:"1.0",	// The version of this code
	kWeb:null,		// The base url of the site for retrieving assets 	 	(provided by PHP)
	kPage:null,		// A unique ID for the current page 				(provided by PHP)
	
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Init
	//-----------------------------------------------------------------------------------------------------------------------------
	// This initializes all of the packages attached to wfx. The re param is set to true during 
	// reinitialization (after an ajax load)
	//-----------------------------------------------------------------------------------------------------------------------------
	Init: function(re) {
		wfx.log("wfx.Init");
		
	//	Clientcide.setAssetLocation(kWeb+"src/core/js/assets/");
	//	wfx.log(kWeb+"src/core/js/assets/");

		// Run the init function for all of the wfx packages
		$each(wfx, function(p) { 
			if($type(p) == "object") {
				if(p.Init) p.Init(re);
			}
		});
		
		if(!re) {
			//document.body.onUnload = function() {wfx.Alert('test');};
			//document.body.addEvent('unload', function() {wfx.Alert('test');});
			//document.body.addListener("unload", wfx.Unload);
		}
		
		
		// Initialize the lightbox last in case any other modules add elements to the page
		if( $(document.body).get('html').match(/rel=?.lightbox/i) ) new Lightbox();
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: ReInit
	//-----------------------------------------------------------------------------------------------------------------------------
	// This sends the Init command again but with re set to true so that each Init handler can resetup
	// if needed.
	//-----------------------------------------------------------------------------------------------------------------------------
	ReInit: function() {
		//wfx.log("wfx.ReInit");
		wfx.Init(true);
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Unload
	//-----------------------------------------------------------------------------------------------------------------------------
	// This is called when the page is unloaded from the browser, either by the user reloading, going to
	// a different page, or closing the browser.
	//-----------------------------------------------------------------------------------------------------------------------------
	Unload: function(re) {
		//wfx.log("wfx.Unload");
		// Run the init function for all of the wfx packages
		$each(wfx, function(p) { 
			if($type(p) == "object") {
				if(p.Unload) p.Unload(re);
			}
		});
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: log
	//-----------------------------------------------------------------------------------------------------------------------------
	// This is an alias for console.log but it first tests that the console is available
	//-----------------------------------------------------------------------------------------------------------------------------
	log: function(m) {
		if(kDebugOn) {
			if(!Browser.Engine.trident) {
				if($defined(m) && $defined(console.log)) console.log(m);
			}
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: error
	//-----------------------------------------------------------------------------------------------------------------------------
	// This is an alias for console.log but it first tests that the console is available
	//-----------------------------------------------------------------------------------------------------------------------------
	error: function(m) {
		if(!Browser.Engine.trident) {
			if($defined(m) && $defined(console.error)) console.error(m);
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Encode
	//-----------------------------------------------------------------------------------------------------------------------------
	// All data sent through Ajax must be properly treated using url encoding with JSON structure.
	//-----------------------------------------------------------------------------------------------------------------------------
	Encode: function(d) {
		return encodeURIComponent(JSON.encode(d));
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Decode
	//-----------------------------------------------------------------------------------------------------------------------------
	// This reverses the Encode function, returning the original input string
	//-----------------------------------------------------------------------------------------------------------------------------
	Decode: function(d) {
		return decodeURIComponent(d);
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Serialize
	//-----------------------------------------------------------------------------------------------------------------------------
	// This function will create a PHP serialzied object. PHP will be able to unserialize this and use it
	// directly. This is currently not used in favor of JSON.
	//-----------------------------------------------------------------------------------------------------------------------------
	Serialize: function(obj) {
		//wfx.log("wfx.Utils.Init");
		var s = "";
		var total = 0;
		for(var i in obj) {
			++ total;
			s += "s-" +
				String(i).length + "-\""+String(i) + "\"--s-" +
				String(obj[i]).length + "-\"" + String(obj[i]) + "\"-";
		}
		s = "a-" + total + "-_" + s + "_";
		return (s);
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Ajax - send a cmd through ajax
	//-----------------------------------------------------------------------------------------------------------------------------
	// This packages the ajax request for PHP to receive. 
	// T = Target : the target div to receive the result
	// X = AJAX : signals to PHP that the request is ajax in nature
	// The T value is optional and indicates to PHP that a response
	// is expected. The R value should always be present for an ajax
	// request, otherwise PHP will return the whole page.
	//
	// TODO: Add loading gif in target and/or form when submitting Ajax calls
	//-----------------------------------------------------------------------------------------------------------------------------
	Ajax: function(params, options) {
		var 	d = {method:'post', data:"AJ=1&", evalScripts:true},
			f = $(params.form),
			t = $(params.target),
			b = null,
			p = null,
			s = null;
			
		//wfx.log("Ajax("+params.cmd+")"); 
		if(options) {
			$extend(d, options);
		}
		
		if(params.target && !$chk(t)) {
			wfx.error("The target '"+params.target+"' does not exist");
		}
		if($chk(t)) {
		// If a target is defined, then a response is expected
			//wfx.log("target:"+t.getProperty('id')); 
			//b = t.getStyle('outline');
			t.setStyle('outline', '2px solid red');
			
			p = t.getPosition();
			s = $('ajaxStatus');
			s.setStyles({
				display:"block",
				top:p.y,
				left:p.x
			});
			
			d.data += "T="+params.target+"&";
			d.update = t;
			d.onComplete = function() { 
				t.setStyle('outline', 'none');
				s.setStyle('display', 'none');
				// A reinit event is sent for packages to reinitialize
				window.fireEvent('reinit');
				t.fireEvent('update');
			}
		}
		//wfx.log("cmd:"+params.cmd);
		d.data += "CMD="+params.cmd;
		if($chk(f)) {
			//wfx.log("form:"+f.getProperty('id'));
			//f.CMD.value = params.cmd;
			d.data += "&"+f.toQueryString();
			//wfx.log("data:"+d.data);
		}
		//else {
		//}
		if($chk(params.args)) d.data += "&"+params.args;
		
		//new Ajax('index.php', d).request();
		d.url = window.location.href;//'index.php';
		new Request(d).send();//{url:'index.php', data:d}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: AjaxResponses
	//-----------------------------------------------------------------------------------------------------------------------------
	// This keeps track of all AjaxResponses by storing each calls unique id. This is helpful in tracking
	// which callbacks have already been processed
	//-----------------------------------------------------------------------------------------------------------------------------
	AjaxResponses:{},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: AjaxResponse
	//-----------------------------------------------------------------------------------------------------------------------------
	// This handles a response from Ajax returning JSON plus debugging and error information. Even
	// when debugging is disabled, PHP needs a way of reporting errors through the response.
	// NOTE: This method is not called from this file but rather, Json data returned from PHP is 
	// encapsulated in this function for automatic processing. So if the result of an Ajax request is Json
	// it will look like: wx.AjaxResponse(jsonData, debug, error);
	//-----------------------------------------------------------------------------------------------------------------------------
	AjaxResponse: function(data, dbg, err, uniqid) {
		//wfx.log("wfx.AjaxResponse");
		if($defined(uniqid)) {
			if(wfx.AjaxResponses[uniqid]) {
				wfx.error("This AjaxResponse "+uniqid+" has already been evaluated");
				return;
			}
			//wfx.AjaxResponses[uniqid] = 1;
		}
		if(dbg && $defined(wfx.Debug)) {
			//wfx.log("show debug");
			wfx.Debug.Add(dbg);
		}
		if(err) {
			wfx.ShowError(err);
		}
		if(data) {
			if(wfx.GetAjaxResponseType(data) == "JSON") return eval(data);
			else return data;
			//return eval(data);
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: EvalAjaxResponse
	//-----------------------------------------------------------------------------------------------------------------------------
	// Use this function to eval a response from Ajax. It adds special error checking.
	//-----------------------------------------------------------------------------------------------------------------------------
	EvalAjaxResponse: function(response) {
		//wfx.log("wfx.EvalAjaxResponse");
		
		if(!$defined(response)) {
			wfx.ShowError("Invalid response received in wfx.EvalAjaxResponse("+response+")");
			return null;
		}
		if(response.contains("Fatal error")) {
			wfx.ShowError(response);
			return null;
		}
		//if(wfx.GetAjaxResponseType(response) == "HTML") {
		//	return response;
		//}
		//else {
			return eval('('+response+')');
		//}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: GetAjaxResponseType
	//-----------------------------------------------------------------------------------------------------------------------------
	// This is used when 
	//-----------------------------------------------------------------------------------------------------------------------------
	GetAjaxResponseType: function(response) {
		var type = "HTML";
		if($type(response) == "object") {
			type = "JSON";
		}
		else {
			//wfx.log("response:"+$type(response));
			if(response.contains("---JSON---")) type = "JSON";
		}
		return type;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Alert
	//-----------------------------------------------------------------------------------------------------------------------------
	// TODO: implement custom Alert display
	//-----------------------------------------------------------------------------------------------------------------------------
	Alert: function(e) {
		alert(e);
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Confirm
	//-----------------------------------------------------------------------------------------------------------------------------
	// TODO: implement custom Confirm display
	//-----------------------------------------------------------------------------------------------------------------------------
	Confirm: function(e) {
		return confirm(e);
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: ShowError
	//-----------------------------------------------------------------------------------------------------------------------------
	ShowError: function(e) {
		//wfx.log("ERROR("+e+")");
		wfx.error(e);
	/*
		var v = false;
		if(!$defined(wfx.ErrorWin)) {
			wfx.ErrorWin = new wfx.Window('dbg', {Title:'Debug'});
			v = wfx.ErrorWin.Views.Add('Main');
	 		wfx.ErrorWin.SetTitle("Error");
		}
		if(!v) v = wfx.ErrorWin.Views.Get('Main');
	 	v.innerHTML = e;
	 */
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: IconUrl
	//-----------------------------------------------------------------------------------------------------------------------------
	IconUrl: function(i) {
		var u = kWeb+"src/core/icons/"+i;
		if(u.indexOf(".png") == -1 && u.indexOf(".gif") == -1) {
			u += ".png";
		}
		return u;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: RequestLogin
	//-----------------------------------------------------------------------------------------------------------------------------
	// Present the user with a login dialog
	//-----------------------------------------------------------------------------------------------------------------------------
	RequestLogin: function() {
		wfx.Alert("RequestLogin");
	}
}; // wfx
window.addEvent('domready', wfx.Init);
window.addEvent('reinit', wfx.ReInit);
window.addListener('beforeunload', wfx.Unload);

//-----------------------------------------------------------------------------------------------------------------------------
//: Objects
//-----------------------------------------------------------------------------------------------------------------------------
// This is global storage for all objects created. Any time an object is created, a reference to it
// should be added to wfx.Objects[] so that other features (such as page unloading) can be more
// effective and iterate through all known objects.
//-----------------------------------------------------------------------------------------------------------------------------
wfx.Objects = {
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Init
	//-----------------------------------------------------------------------------------------------------------------------------
	Init: function(re) {
		//wfx.log("wfx.Objects.Init");
		
		//setTimeout("wfx.Objects.Save();", 10000);
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Save
	//-----------------------------------------------------------------------------------------------------------------------------
	// This will iterate through all objects and have them save their current data
	//-----------------------------------------------------------------------------------------------------------------------------
	Save: function() {
		//wfx.log("wfx.Objects.Save");
		/*
		var a = "";
		for(var o in wfx.Objects) {
			//wfx.log(o+":"+$type(wfx.Objects[o]));
			if($type(wfx.Objects[o]) == "element") {
				var x = wfx.Objects[o];
				if(x.options.StoreData) {
					x.Save();
					if(a) a += "&";
					a += x.id+"="+wfx.Encode(x.Data);
				}
			}
		}
		if(a) {
			wfx.Ajax({cmd:"cmdAjaxSave", args:a}, {evalResponse:true, async:false});
		}
		*/
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Add
	//-----------------------------------------------------------------------------------------------------------------------------
	Add: function(obj) {
		//wfx.log("wfx.Objects.Add("+obj.id+")");
		var index = obj.id;
		var x = 1;
		while($defined(wfx.Objects[index])) {
			index = obj.id+"-"+x;
			x++;
			if(x > 5) break;
		}
		wfx.Objects[index] = obj;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Unload
	//-----------------------------------------------------------------------------------------------------------------------------
	Unload: function() {
		//wfx.log("wfx.Objects.Unload");
	//	wfx.Objects.Save();
	}
}; // Objects

//-----------------------------------------------------------------------------------------------------------------------------
//: Object
//-----------------------------------------------------------------------------------------------------------------------------
// An object is an element extended to support data handling functions primarily for loading and 
// saving to the database. 
//-----------------------------------------------------------------------------------------------------------------------------
wfx.Object = new Class({
	Implements: [Options],
	DataType:'Data',
	Data: {
	//	DataType:'Data'
	},
	options: {
		DataType:'Data',
		StoreData:false,		// This made optional so it can be turned on/off per object
		OnLoad:null		// Insert a callback method here to perform after the object is updated
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: initialize
	//-----------------------------------------------------------------------------------------------------------------------------
	initialize: function(id, el, options) {
		//wfx.log("Object:"+id+".initialize:"+el);
		
		var self = null;
		if($type(el) == "string") {
			self = $(document.createElement(el));
		}
		else {
		// Assign a prexisting element
			self = el;
		}
		$extend(self, this);
		self.show();

		self.id = id;
		
		self.setOptions(options);
		self.SetupData();
		
		return self;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: SetupData
	//-----------------------------------------------------------------------------------------------------------------------------
	SetupData: function() {
		//wfx.log("Object:"+this.id+".SetupData");
//		this.Data = {};
		this.id = this.id;
		
		if($defined(this.options)) {
			this.DataType = this.options.DataType;
		}
		
		wfx.Objects.Add(this);
		
	//	if(this.options.StoreData) {
	//		var id = (this.options.DataID) ? this.options.DataID : this.id;
	//		//wfx.log("DataID:"+id);
	//		if(!$defined(wfx.Data[id])) wfx.Data[id] = {};		// Create data storage for the object
	//		this.Data = wfx.Data[id];	// Create a pointer to the wfx.Data object, so it can be accessed as this.Data
//			this.id = this.id;		// Every object must have a unique ID property
	//	}
		//wfx.log("Add Object:"+this.id);
//		wfx.Objects[this.id] = this;		// Store a global reference to the object

		// Setting the DataType ensures that PHP handles the data correctly
		//if(!$defined(this.DataType)) {
//			if(this.options.DataType) this.DataType = this.options.DataType;
//			else this.DataType = "Data";
		//}
//		//wfx.log("DataType:"+this.DataType);
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Save
	//-----------------------------------------------------------------------------------------------------------------------------
	// This method should be overridden by any classes that have special needs to save data. During the
	// Save operation, data should only be set to the Data node and avoid making Ajax calls if possible.
	// The Data node will be saved through Ajax later in one fell swoop.
	//-----------------------------------------------------------------------------------------------------------------------------
	Save: function() {
		//wfx.log("Object:"+this.id+".Save");
		// The base class does nothing here.
		//wfx.Data.Save();
	//	var a = this.id+"="+wfx.Encode(this.Data);
	//	wfx.Ajax({cmd:"cmdAjaxSave", args:a}, {evalResponse:true, async:false});
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Load
	//-----------------------------------------------------------------------------------------------------------------------------
	// This provides on-demand loading of data previously stored. Unlike the Save command, this method
	// does use Ajax and handles the application of the received data through the Loaded method.
	//-----------------------------------------------------------------------------------------------------------------------------
	Load: function() {
		//wfx.log("Object:"+this.id+".Load");
		wfx.Ajax({cmd:"cmdAjaxLoad", args:"ID="+this.id+"&DataType="+this.DataType}, 
			{evalResponse:false, onComplete:this.Loaded.bind(this), async:false});
		// async is disabled to prevent conflicts between saving and loading data before adequate time
		// is given to handle the response.
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Loaded
	//-----------------------------------------------------------------------------------------------------------------------------
	// This receives the result of an Ajax request made by the Load method. The response is expected
	// to be JSON or executable javascript code that will evaluate to an object or value. The data is
	// updated to the Data node, only affecting new values. A class may override this method to 
	// perform any custom updating, or use it like notification.
	//-----------------------------------------------------------------------------------------------------------------------------
	Loaded: function(response, skipEvent) {
		//wfx.log("Object:"+this.id+".Loaded");
		
		var success = false;
		var html = undefined;
		var data = wfx.EvalAjaxResponse(response);
		var type = wfx.GetAjaxResponseType(response);

		if(!$defined(data)) {
			wfx.ShowError("There was an error handling the AjaxResponse in wfx.Object.Loaded");
			return succcess;
		}
		else {
			success = true;
			if(type == "JSON") {
			// We can interpret JSON data directly as a javascript object
				var count = 0;
				for (var key in data) {
					count++;
					if(count > 0) break;
				}
				if(count) {
					$extend(this.Data, data);
					success = true;
					//wfx.log("DATA LOADED SUCCESSFULLY");
				}
				else {
					//wfx.log("NO DATA LOADED");
				}
			}
			else {
				//wfx.log("RESPONSE IS HTML");
			}
			if(!skipEvent) this.fireEvent('update');
			
			if(this.options.OnLoad) this.options.OnLoad(this, data);
		}
		
		return success;
	}
}); // Object
//wfx.Object.implement(new Options);

//-----------------------------------------------------------------------------------------------------------------------------
//: Page
//-----------------------------------------------------------------------------------------------------------------------------
// This manages the data for the current page. A page is a fixed url location and does not contain 
// any content itself but wraps a document in the appropriate headers and manages the general 
// access settings. The content of the page comes from loading the assigned document or procedure.
// The page headers are generated by PHP, whereas this object is here just to provide support.
//-----------------------------------------------------------------------------------------------------------------------------
wfx.Page = new Class({
	Extends: wfx.Object,
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: initialize
	//-----------------------------------------------------------------------------------------------------------------------------
	// Since only one page can be loaded at a time, the constructor only returns a reference to the
	// already existing page object. This does not call the Object initialize method.
	//-----------------------------------------------------------------------------------------------------------------------------
	initialize: function() {
		//wfx.log("wfx.Page.initialize:"+kPage);
		
		var p = $(kPage);
		if(p) {
			$extend(p, this);
			
			p.id = kPage;
			p.DataType = "Page";
		}
		//p.SetupData();

		return p;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Load
	//-----------------------------------------------------------------------------------------------------------------------------
	Load: function() {
		//wfx.log(this.id+".Load");
		//wfx.Ajax({cmd:"cmdAjaxLoad", args:"ID="+this.id+"&DataType=Page"}, 
		//	{evalResponse:false, onComplete:this.Loaded.bind(this)});
		this.parent();
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Save
	//-----------------------------------------------------------------------------------------------------------------------------
	Save: function() {
		//wfx.log(this.id+".Save");
		//this.Data.Content = wfx.Data.Encode(this.innerHTML);
		this.parent();
	}
}); // Page

//-----------------------------------------------------------------------------------------------------------------------------
//: View
//-----------------------------------------------------------------------------------------------------------------------------
// This creates a special div that manages the visibility of its children. Each child is added with a
// unique id and can be switched on or off by the View. Use Add for inserting new content and then
// use Select for choosing which child is visible. Note: for a visible user interface use Tabs.
//-----------------------------------------------------------------------------------------------------------------------------
wfx.View = new Class({
	Extends: wfx.Object,
	Current:null,
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: initialize
	//-----------------------------------------------------------------------------------------------------------------------------
	initialize: function(id, options) {
		//wfx.log("wfx.View.Init");
		var self = this.parent(id, 'div', options);
		self.set({'class':'view', id:id});
		self.Add('MainView');
		return self;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Add
	//-----------------------------------------------------------------------------------------------------------------------------
	// This adds a new layer to the View. It is highly recommended that you use an ID that will be
	// universally unique, though the Select and Get functions will only search within the View.
	//-----------------------------------------------------------------------------------------------------------------------------
	Add: function(id, content) {
		//wfx.log("wfx.View.Add("+id+")");
		
		var v = new Element('div', {id:id});
		this.appendChild(v);
		
		if($defined(content)) {
			if($type(content) == "string") {
				v.innerHTML = content;
			}
			else {
				v.appendChild(content);
			}
		}

		this[id] = v;
		this.Select(id);
		
		v.setStyles({
			'width':'100%',
			'height':'100%'
		});
		v.onResize = function() {
			//wfx.log("subView.onResize");
			v.getChildren().each( function(child) {
				if(child.onResize) {
					child.onResize();
				}
			});
		};
		return v;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Select
	//-----------------------------------------------------------------------------------------------------------------------------
	// Show the specified view and hide all others.
	//-----------------------------------------------------------------------------------------------------------------------------
	Select: function(view) {
		//wfx.log("wfx.View.Select:"+view);
		this.Current = view;
		this.getChildren().each(
			function(ch) {
				if(ch.id == view) {
					//wfx.log(ch.id+".show");
					ch.show();
				}
				else {
					//wfx.log(ch.id+".hide");
					ch.hide();
				}
			}
		);
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Get
	//-----------------------------------------------------------------------------------------------------------------------------
	// Return the specified view element. This is more reliable than using $(id) incase the id is not unique.
	//-----------------------------------------------------------------------------------------------------------------------------
	Get: function(view) {
		//wfx.log("wfx.View.Get:"+view);
		if(!$defined(view)) view = this.Current;
		var ch = this.getChildren();
		var found = false;
		for(var x=0; x<ch.length; x++) {
			if(ch[x].id == view) {
				found = ch[x];
				break;
			}
		}
		return found;
	}
});

//-----------------------------------------------------------------------------------------------------------------------------
//: Window
//-----------------------------------------------------------------------------------------------------------------------------
// This Window class creates virtual window using DHTML. This is not to be confused with a 
// traditional window, which is a Popup in wfx. Windows automatically store their position and size.
// TODO: implement Window scroll options (noScroll, scrollY, scrollX, auto)
// TODO: improve Window graphics and framing and add a hovering shadow
//-----------------------------------------------------------------------------------------------------------------------------
wfx.Window = new Class({
	Extends: wfx.Object,
//	Implements: [Modalizer],
//	modalOptions: {},
	options: {
		Style:'',
		Title:'',
		ShowTitle:true,
		Width:300, //'250px',
		Height:200, //'250px',
		Left:200,
		Top:200,
		Movable:true,
		Resizable:true,
		Closable:true,
		StoreData:false,
		Visible:true,
		Bounded:false,
		Center:true,
		IsModal:false,
		onClose:$empty
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: initialize
	//-----------------------------------------------------------------------------------------------------------------------------
	initialize: function(id, options) {
		//wfx.log("Window:"+id+".initialize");
		options.DataType = "Data";
		var self = this.parent(id, 'div', options);
		document.body.appendChild(self);
		self.Create();
		
		return self;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Create
	//-----------------------------------------------------------------------------------------------------------------------------
	Create: function() {
		//wfx.log("Window:"+this.id+".Create");

		// Hide the window to prevent flashing
		this.hide();

		if(this.options.IsModal) {
			//wfx.log("Setup Modal");
			this.Modal = new Modalizer();
			
			//this.Modal.setModalStyle({zIndex:1000, 'background-color':'none', opacity:0.5});
	//		var self = 
			//this.Modal.parent(this, 'div', options);
			this.Modal.setModalOptions({
				hideOnClick: true,
				onModalHide: this.Close.bind(this)
			});
			this.Modal.setModalStyle({
				'z-index':999,
				opacity:0.2
			});
			//this.Modal.modalOptions.onModalHide = this.Close.bind(this.Modal);
			//self.set({'class':'wfxMenu', id:id});
			this.Modal.modalHide(); 
		}

		var c = this.options.Style ? "vw"+this.options.Style : "";
		this.setProperty('class', 'vw '+c);
		
		//if(this.options.ShowTitle) {
			this.Header	= this.addElement('div', {id:this.id+'H', 'class':'vwH'});
			this.Title 		= this.Header.addElement('div', {id:this.id+'T', 'class':'vwT'});
			
			this.Header
		//}
		if(!this.options.ShowTitle) this.Header.hide();

		this.Content = this.addElement('div', {id:this.id+'C', 'class':'vwC'});

		if(this.options.Title) {
			this.Title.innerHTML = this.options.Title;
		}


		if(this.options.IsModal) {
			this.options.Movable 	= false;
			this.options.Resizable = false;
			this.options.Closable 	= false;
		}
		else {
			this.CloseButton 	= this.Header.addElement('div', {id:this.id+'X', 'class':'vwX'});
			this.Footer  		= this.addElement('div', {id:this.id+'F', 'class':'vwF'});
			this.FooterText  	= this.Footer.addElement('div', {id:this.id+'FT', 'class':'vwFT'});
			this.ResizeHandle 	= this.Footer.addElement('div', {id:this.id+'R', 'class':'vwR'});

			var cont = '';
			if(this.options.Bounded) cont = document.body;
			if(this.options.Movable) {
				this.makeDraggable({
					handle:this.Header,
					onStart: this.StartDrag.bind(this),
					onComplete: this.EndDrag.bind(this),
					container:cont
				}); 
			}
	
			if(this.options.Resizable) {
				this.makeResizable({
					handle:this.ResizeHandle, 
					onDrag: this.onResize.bind(this),
					onComplete: this.Save.bind(this)
				});
			}
			if(this.options.Closable) {
			// Add a close button
				this.CloseButton.addEvent('mousedown', function(ev) { ev.stopPropagation(); });
				this.CloseButton.addEvent('mouseup', this.Close.bindWithEvent(this));
			}
			else {
				this.CloseButton.hide();
			}
		}
		
		//if(this.options.onClose) {
		//	this.addEvent('close', this.options.onClose);
		//	this.options.onClose();
		//}
			
		// Setup the internal view for managing the window content
		this.Views = new wfx.View(this.id+'View');
		this.Content.appendChild(this.Views);

		if(this.options.StoreData) {
			this.Load();
			//if(this.Data.V) this.show();
		}
	
		this.SetPosition(this.options.Left, this.options.Top);
		this.SetSize(this.options.Width, this.options.Height);
		this.Setup();
		this.Show();
		//this.onResize();
		
	//	if(this.options.Center && !this.options.Load) {
		// Only recenter the window if its new and prior settings have not been loaded
	//		this.Center();
	//	}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Setup
	//-----------------------------------------------------------------------------------------------------------------------------
	Setup: function() {
		//wfx.log("Window:"+this.id+".Setup");
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: SetTitle
	//-----------------------------------------------------------------------------------------------------------------------------
	SetTitle: function(t) {
		//wfx.log("Window:"+this.id+".SetTitle");
		if(this.options.ShowTitle) {
			this.Title.innerHTML = t;
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: StartDrag
	//-----------------------------------------------------------------------------------------------------------------------------
	StartDrag: function() {
		//wfx.log("Window:"+this.id+".StartDrag");
		this.setOpacity(0.5);
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: EndDrag
	//-----------------------------------------------------------------------------------------------------------------------------
	EndDrag: function() {
		//wfx.log("Window:"+this.id+".EndDrag");
		this.setOpacity(1);
		this.Save();
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Center
	//-----------------------------------------------------------------------------------------------------------------------------
	Center: function() {
		//wfx.log("Window:"+this.id+".Center");
		var w = Window.getSize();//.size;
		var c = this.getCoordinates();
		
		var width = c.width;
		var height = c.height;
		if(!width) width = this.Data.W;
		if(!height) height = this.Data.H;
		
		this.setStyles({
			left: (w.x * 0.5) - (width * 0.5),
			top: (w.y * 0.5) - (height * 0.5)
		});
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Check
	//-----------------------------------------------------------------------------------------------------------------------------
	Check: function() {
		//wfx.log("Window:"+this.id+".Check");
		var w = window.getSize();//.size;
		var c = this.getCoordinates();
		
		this.setStyles({
			left:(c.left <= 0) ? 0 : (c.left < w.x) ? c.left : w.x - c.width,
			top:(c.top <= 0) ? 0 : (c.top < w.y) ? c.top : w.y - c.height
		});
	},
	/*
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Check
	//-----------------------------------------------------------------------------------------------------------------------------
	Check: function() {
		//wfx.log("Window:"+this.id+".Check");
		
		var w = window.getSize();//.size;
		
		var d = this.Data;
		this.Data.X 	= (isNaN(d.X) || d.X <= 0) ? 0 : (d.X < w.x) ? d.X : w.x - d.W;
		this.Data.Y 	= (isNaN(d.Y) || d.Y <= 0) ? 0 : (d.Y < w.y) ? d.Y : w.y - d.H;
		this.Data.W 	= (isNaN(d.W) || d.W <= 0) ? 150 : (d.W < w.x) ? d.W : w.x;
		this.Data.H 	= (isNaN(d.H) || d.H <= 0) ? 150 : (d.H < w.y) ? d.H : w.y;
	},
	*/
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: SetPosition
	//-----------------------------------------------------------------------------------------------------------------------------
	SetPosition: function(x, y) {
		//wfx.log("Window:"+this.id+".SetPosition("+x+","+y+")");
		this.setStyles({
			left:x+"px",
			top:y+"px"
		});
		this.Data.X 	= x;
		this.Data.Y 	= y;
		this.onResize();
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: SetSize
	//-----------------------------------------------------------------------------------------------------------------------------
	// TODO: implement Window auto height feature so it doesn't have to be set manually
	//-----------------------------------------------------------------------------------------------------------------------------
	SetSize: function(w, h) {
		//wfx.log("Window:"+this.id+".SetSize("+w+","+h+")");
		this.setStyles({
			width:w+"px",
			height:h+"px"
		});
		this.Data.W 	= w;
		this.Data.H 	= h;
		this.onResize();
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Save
	//-----------------------------------------------------------------------------------------------------------------------------
	Save: function() {
		//wfx.log("Window:"+this.id+".Save");
		if(this.isVisible()) {
			var p = this.getPosition();
			var s = this.getInnerSize().size;
			//this.Data.ID	= this.id;
			this.Data.X 	= p.x;
			this.Data.Y 	= p.y;
			this.Data.W 	= s.x;
			this.Data.H 	= s.y;
			this.Data.V	= this.isVisible() ? 1 : 0;
		}
		this.parent();
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Loaded
	//-----------------------------------------------------------------------------------------------------------------------------
	Loaded: function(response) {
		//wfx.log("Window:"+this.id+".Loaded");
		
		// We'll let the Object handle the data import
		if(!this.parent(response)) {
		// No data was loaded from the request
			this.Center();
		}
		else {
			this.Check();
			this.setStyles({
				left:this.Data.X,
				top:this.Data.Y,
				width:this.Data.W,
				height:this.Data.H
			});
			
			if(this.Data.V || (!$defined(this.Data.V) && this.options.Visible)) {
				this.Show();	
			}
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Close
	//-----------------------------------------------------------------------------------------------------------------------------
	Close: function(ev) {
		//wfx.log("Window:"+this.id+".Close");
		if(this.isVisible()) {
			this.fireEvent('onClose');
			this.Save();
			this.Data.V = 0;
			this.hide();
			if(this.options.IsModal) {
				this.Modal.modalHide(); 
			}
		}
		if(ev) ev.stopPropagation();
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Open
	//-----------------------------------------------------------------------------------------------------------------------------
	Open: function() {
		//wfx.log("Window:"+this.id+".Open");
		if(!this.isVisible()) {
			this.show();
			this.Save();
			this.onResize();
			if(this.options.IsModal) {
				this.Modal.modalShow(); 
			}
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Show
	//-----------------------------------------------------------------------------------------------------------------------------
	Show: function() {
		//wfx.log("Window:"+this.id+".Show");
		this.Open();
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Hide
	//-----------------------------------------------------------------------------------------------------------------------------
	Hide: function() {
		//wfx.log("Window:"+this.id+".Hide");
		this.Close();
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Toggle
	//-----------------------------------------------------------------------------------------------------------------------------
	Toggle: function() {
		//wfx.log("Window:"+this.id+".toggle");
		var v = this.isVisible() ? 1 : 0;
		if(v) {
			this.Save();
			this.Data.V = 0;
			this.Close();
		}
		else {
			this.Save();
			this.Open();
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: IsOpen
	//-----------------------------------------------------------------------------------------------------------------------------
	IsOpen: function() {
		return this.isVisible();
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: onResize
	//-----------------------------------------------------------------------------------------------------------------------------
	onResize: function() {
		//wfx.log("Window:"+this.id+".onResize");
		var 	s 	= this.getSize(),
			hs	= this.Header.getSize(),
			fs	= 0;
		if(this.Footer) fs	= this.Footer.getSize().y;

		var height = s.y - (hs.y + fs);
		// //wfx.log("s.y:"+s.y);
		// //wfx.log("hs.y:"+hs.y);
		// //wfx.log("fs:"+fs);
		// //wfx.log("height:"+height);
		this.Content.setStyle("height", height+"px");

		// Resize each child view to match
		//this.Views.setStyle("height", height+"px");
		//this.Views.getChildren().setStyle("height", height);
		//this.Views.getChildren().each(function(child) {child.onResize();});

		// broadcast the event in case any other actions are needed
		this.fireEvent('resize');
	}
}); // Window

//-----------------------------------------------------------------------------------------------------------------------------
//: ContextualWindow
//-----------------------------------------------------------------------------------------------------------------------------
// TODO: Have window resize to automatically fit content
//-----------------------------------------------------------------------------------------------------------------------------
wfx.ContextualWindow = new Class({
	Extends: wfx.Window,
//	Implements: [Modalizer],
//	modalOptions: {},
	options: {
		Style:'Contextual',
		Title:'',
		ShowTitle:false,
		Width:200, //'250px',
		Height:50, //'250px',
		Left:0,
		Top:0,
		Movable:false,
		Resizable:false,
		Closable:false,
		StoreData:false,
		Visible:true,
		Bounded:false,
		Center:false,
		IsModal:true,
		onClose:$empty
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: initialize
	//-----------------------------------------------------------------------------------------------------------------------------
	initialize: function(id, options) {
		//wfx.log("ContextualWindow:"+id+".initialize");
		var self = this.parent(id, options);
		//self.Setup();
		
		return self;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Setup
	//-----------------------------------------------------------------------------------------------------------------------------
	Setup: function() {
		//wfx.log("ContextualWindow:"+this.id+".Setup");
		this.parent();

		this.Modal.setModalStyle({
			'z-index':999,
			opacity:0.01
		});

		// Make the window hide as soon as the mouse moves out over the modalizer
		var modal = this.Modal.toElement();
		modal.addEvent("mouseover", this.Modal.modalHide.bind(this.Modal));
	}
}); // wfx.ContextualWindow

//-----------------------------------------------------------------------------------------------------------------------------
//: Button
//-----------------------------------------------------------------------------------------------------------------------------
// This creates a button object which can be used with or without forms. This creates simple text,
// icon or image based buttons.
//
// TODO: Implement images for Buttons
//-----------------------------------------------------------------------------------------------------------------------------
wfx.Button = new Class({
	Extends: wfx.Object,
	Disabled:false,
	EventsBackup:null,
	OutlineBackup:null,
	options: {
		Action:null,
		Style:'button',
		Label:'New Button',
		Title:null,
		Link:'', /*javascript:null(0);*/
		Submit:false,
		ShowLabel:true,
		Icon:false
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: initialize
	//-----------------------------------------------------------------------------------------------------------------------------
	initialize: function(id, options, props) {
		//wfx.log("wfx.Button: "+id);
		var self = this.parent(id, 'a', options);
				
		self.setProperty('class', self.options.Style);
		self.set(props);
		
		if(self.options.ShowLabel) {
			self.innerHTML = self.options.Label;
		}
		var title = self.options.Title;
		if(!title) title = self.options.Label;
		if(title) self.setProperty('title', title);

		if(self.options.Icon) {
			var img = self.addElement('img');
			var icon = self.options.Icon;
			if(icon.indexOf("http:") != 0) {
				icon = kWeb+"src/core/icons/"+self.options.Icon+".png";
			}
			img.setProperty('src', icon);
		}
		if(self.options.Link) {
			self.setProperty('href', self.options.Link);
		}
		if(self.options.Action) {
			//wfx.log("buttonClick");
			self.addEvent('click', self.options.Action);
		}
		
		self.EventsBackup = $(document.createElement("a"));
		//	self.addEvent('mouseover', function() { 
		//		var pos = getPosition(this);
		//		//wfx.log("x:"+pos.x+", y:"+pos.y);
		//	});
		
		if($defined(props)) {
			if(props.disabled == true) {
				self.Disable();
			}
		}
		
		return self;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Enable
	//-----------------------------------------------------------------------------------------------------------------------------
	Enable: function() {
		//wfx.log("wfx.Button.Enable");
		if(this.Disabled) {
		// We make sure the control has already been disabled once, and then restore the saved
		// backup of its events.
			this.setProperty('href', this.HrefBackup);
			this.cloneEvents(this.EventsBackup);
			this.setStyle('outline', this.OutlineBackup);
			this.setProperty('class', this.options.Style);
			this.Disabled = false;
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Disable
	//-----------------------------------------------------------------------------------------------------------------------------
	Disable: function() {
		//wfx.log("wfx.Button.Disable");
		// We need to disable the button. To do this we first need to make a backup of its events
		// and then clear them so nothing happens when the user clicks on it.
		if(!this.Disabled) {
			this.EventsBackup.cloneEvents(this);
			this.HrefBackup = this.getProperty('href');
			this.setProperty('href', null);
			this.removeEvents();
			this.OutlineBackup = this.getStyle('outline');
			this.setProperty('class', 'button_disabled');
			this.Disabled = true;
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: SetLabel
	//-----------------------------------------------------------------------------------------------------------------------------
	SetLabel: function(label) {
		//wfx.log("wfx.Button.SetLabel");
		this.innerHTML = label;
	}
	
}); // Button

//-----------------------------------------------------------------------------------------------------------------------------
//: InputFitlers
//-----------------------------------------------------------------------------------------------------------------------------
// These functions are event handlers intended to be used with input fields. They offer standard 
// entry restrictions.
//
// TODO: implement additional InputFilters
//-----------------------------------------------------------------------------------------------------------------------------
wfx.InputFitlers = {
	Numbers: function(ev) {
		var validChar = "0123456789";
		return validChar.indexOf(ev.key) >= 0;
	}
};

//-----------------------------------------------------------------------------------------------------------------------------
//: Input
//-----------------------------------------------------------------------------------------------------------------------------
// This creates various types of form inputs. Notice that this class is not derrived from Object 
// because it doesn't make sense for every input to individually store its value. Instead, you must
// use a form. Don't overlook all the properties you can set to define the type of control you need.
//
// TODO: implement overlay text for empty text fields (that disappears once clicked)
// TODO: implement auto-complete for text fields using Ajax
// TODO: implement an object browser/chooser which loads previews of objects from PHP
//-----------------------------------------------------------------------------------------------------------------------------
wfx.Input = new Class({
	Extends: wfx.Object,
	options: {
		Label:false,
		Filter:null
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: initialize
	//-----------------------------------------------------------------------------------------------------------------------------
	initialize: function(id, options, props) {
		//wfx.log("Input:"+id+".initialize");
		var type = "input";
		if($defined(options.Type)) {
			if(options.Type == "textarea") {
				type = "textarea";
			}
			else
			if(options.Type == "select") {
				type = "div";
			}
			else {
				props.type = options.Type;
			}
		}
		
		var self = this.parent(id, type, options);
		self.set(props);
		
		if(options.Filter) {
			var filterFunc = null;
			if($type(options.Filter) == "function") {
				filterFunc = options.Filter;
			}
			else
			if(wfx.InputFitlers[options.Filter]) {
				filterFunc = wfx.InputFitlers[options.Filter];
			}
			
			if(filterFunc) {
				self.addEvent('keypress', filterFunc.bindWithEvent(this));
			}
			else {
				wfx.error("Unknown input filter specified: "+options.Filter+", wfx.Input");
			}
		}
		
		// Both the id and name properties must be set for form elements to submit
		self.setProperty('name', id);
		
		if(options.Type == "select") {
			//wfx.log("build select choices");
			self.Select = self.addElement('select');
			self.Choices = {};
			for(var key in options.Choices) {
				//wfx.log("option:"+key);
				var opt = self.Select.addElement('option', {value:key});
				if(options.Value == key) opt.setProperty("selected", "selected");
				opt.innerHTML = options.Choices[key];
			}
		}

		self.addEvent('change', self.onChange.bind(self));

		if($defined(options.Value)) self.SetValue(options.Value);
		
		return self;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: SetValue
	//-----------------------------------------------------------------------------------------------------------------------------
	SetValue: function(value) {
		//wfx.log("Input:"+this.id+".SetValue("+value+")");
		
		if(this.options.Type == "textarea") {
			this.innerHTML = value;
		}
		else
		if(this.options.Type == "checkbox") {
			this.checked = value == 1 ? "checked" : "";
		}
		else
		if(this.options.Type == "select") {
			for(var x = 0; x < this.Select.length; x++) {
				//wfx.log("checking:"+this.Select[x].value);
				if(this.Select[x].value == value) {
					this.Select[x].selected = true;
				//	this.Select[x].setProperty('selected', 'selected');
				}
				else {
					this.Select[x].selected = false;
				}
			}
		}
		else {
			this.setProperty('value', value);
		}
		this.fireEvent('change');
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: GetValue
	//-----------------------------------------------------------------------------------------------------------------------------
	GetValue: function() {
		//wfx.log("Input:"+this.id+".GetValue");
		
		var value = null;
		
		if(this.options.Type == "textarea") {
			//wfx.log('textarea');
			value = this.value;//innerHTML;
		}
		else
		if(this.options.Type == "checkbox") {
			value = this.checked ? 1 : 0;
		}
		else
		if(this.options.Type == "select") {
			//wfx.log('this.Select.options.length:'+this.Select.options.length);
			//wfx.log('this.Select.selectedIndex:'+this.Select.selectedIndex);
			if(this.Select.options.length && this.Select.selectedIndex < this.Select.options.length) {
				value = this.Select.options[this.Select.selectedIndex].value;
			}
		}
		else {
			//wfx.log('input');
			value = this.getProperty('value');
		}
		//wfx.log("value:"+value);
		
		return value;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Enable
	//-----------------------------------------------------------------------------------------------------------------------------
	Enable: function() {
		//wfx.log("wfx.Input:"+this.id+".Enable");
		if(this.options.Type == "select") {
			this.Select.setProperty('disabled', '');
		}
		else {
			this.setProperty('disabled', '');
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Disable
	//-----------------------------------------------------------------------------------------------------------------------------
	Disable: function() {
		//wfx.log("wfx.Input:"+this.id+".Disable");
		if(this.options.Type == "select") {
			this.Select.setProperty('disabled', 'disabled');
		}
		else {
			this.setProperty('disabled', 'disabled');
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: onChange
	//-----------------------------------------------------------------------------------------------------------------------------
	onChange: function() {
		//wfx.log("Input:"+this.id+".onChange");
		if(this.Data) {
			//wfx.log('Data:'+this.value);
			this.Data = this.value;
		}
	}
}); // Input

//-----------------------------------------------------------------------------------------------------------------------------
//: $form
//-----------------------------------------------------------------------------------------------------------------------------
// This is a quick wrapper for form elements already on the page. You can get the form object by
// calling $form(formID) which will return the element extended with the Form.prototype.
//-----------------------------------------------------------------------------------------------------------------------------
function $form(el) {
	var f = $(el);
	if(!$chk(f)) {
		//wfx.log('no form');
		return false;
	}
	var found = false;
	var id = f.getProperty('id');
	//wfx.log("$form("+id+")");
	if($chk(f)) {
		while($type(f) == "element") {
			if(f.get('tag') == "form") {
				found = true;
				break;
			}
			else {
				f = f.getParent();
				//wfx.log("getParent");
				if(!$chk(f)) {
					wfx.error("Failed to find form element for "+id);
					break;
				}
			}
		}
		//wfx.log("$form: id="+id+", form="+f.getProperty('id'));
	}
	else wfx.error("The form '"+id+"' does not exist");
	if(!found) f = false;
	else $extend(f, wfx.Form.prototype);
	return f;
}

//-----------------------------------------------------------------------------------------------------------------------------
//: Forms
//-----------------------------------------------------------------------------------------------------------------------------
// This creates and manages an HTML form. 
//-----------------------------------------------------------------------------------------------------------------------------
wfx.Forms = {
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Add
	//-----------------------------------------------------------------------------------------------------------------------------
	Add: function(form) {
		//wfx.log("wfx.Forms.Add("+form.id+")");
		var index = form.id;
//		var x = 1;
//		while($defined(wfx.Objects[index])) {
//			index = obj.id+"-"+x;
//			x++;
//			if(x > 5) break;
//		}
		wfx.Forms[index] = form;
	}
};

//-----------------------------------------------------------------------------------------------------------------------------
//: Form
//-----------------------------------------------------------------------------------------------------------------------------
// This creates and manages an HTML form. 
//
// TODO: Add a group control to organize related controls visually
// TODO: Improve table layout allowing for more than 2 columns and easier insertion of elements.
//-----------------------------------------------------------------------------------------------------------------------------
wfx.Form = new Class({
	Implements: [Options],
	//Extends: wfx.Object,
	Table:null,
	Fields:{},
	Buttons:{},
	//Implements: [Options, Events],
	options: {
		Layout:'Table',  //Div
		UseAjax:false,
		AjaxOptions:{},
		UseJson:false,
		AutoCreate:false,
		onChange:false,
		Validate:null
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: initialize
	//-----------------------------------------------------------------------------------------------------------------------------
	initialize: function(id, options, props) {
		//wfx.log("wfx.Form:"+id);
		var self = $(document.createElement('form'));//this.parent(id, 'div', options);
		$extend(self, this);
		self.show();
		self.id = id;
		self.setOptions(options);

		if(!$defined(props)) props = {};
		if(!$defined(props.method)) props.method = "POST";
		self.set(props);
		
		if(!$defined(self.options.AjaxOptions.evalResponse)) {
			self.options.AjaxOptions.evalResponse = true;
		}

		if(self.options.Layout == 'Table') {
			var table = self.addElement('table');
			table.addClass('FormTable');
			self.Table = table.addElement('tbody');
			//self.Table.setStyle('border', 'none');
		}
		if(self.options.AutoCreate) {
			self.AutoCreate();
		}
		self.addEvent("change", self.onChange.bind(self));
		//self.Data.Modified = false;

	//	var parentWin = this.GetParentWindow();
	//	parentWin.addEvent('resize', function() {
	//		//wfx.log('textarea resize');
	//		i.AutoHeight();
	//	});
	
		wfx.Forms.Add(self);

		return self;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: AutoHeight
	//-----------------------------------------------------------------------------------------------------------------------------
	AutoHeight: function() {
		//wfx.log('wfx.Form.AutoHeight');
	//	var size = this.getParent().getSize();
	//	this.setStyle('height', size.y);
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: AutoCreate
	//-----------------------------------------------------------------------------------------------------------------------------
	AutoCreate: function(exclude) {
		for(var d in this.Data) {
			this.AddInput(d, {type:'text'}, {Label:d});
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: AddInput
	//-----------------------------------------------------------------------------------------------------------------------------
	// TODO: implement 'hover tips'. This should show instructions or explanations
	//-----------------------------------------------------------------------------------------------------------------------------
	AddInput: function(id, options, props) {
		//wfx.log("AddInput: "+id);
		
		if(this.Fields[id]) {
			wfx.error("Input["+id+"] already exists");
			return null;
		}
		if(!$defined(props)) props = {};
		var i = new wfx.Input(id, options, props);
		
		// which are displayed when the user clicks on a dashed underline or something.
		var label = i.options.Label;
		if(i.options.Description) {
			label = "<div title='"+i.options.Description+"'>"+label+"</div>";
		}
		if(i.options.Type == 'textarea') {
		//	if(label) this.AddRow(label, null, {'id':id+"Row"}, options.insertAfter);
		//	this.AddRow(null, i);
			this.AddRow(label, i);
		}
		else
		if(i.options.Type == 'hidden') {
			this.appendChild(i);
		}
		else {
			this.AddRow(label, i, {'id':id+"Row"}, options.insertAfter);
		}
		
		this.Fields[id] = i;
		
		var self = this;
		if(options.Submit) {
			i.addEvent('keypress', function(ev) {
				if(ev.key == 'enter') {
					ev.preventDefault();
					self.Submit(options.Submit);
				}
			});
		}
		
		//return i;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: AddButton
	//-----------------------------------------------------------------------------------------------------------------------------
	AddButton: function(id, options, props, insertAfter) {
		//wfx.log("AddButton: "+id);
		if(this.Buttons[id]) {
			wfx.error("Button["+id+"] already exists");
			return null;
		}
		if(!$defined(props)) props = {};
		//if(!$defined(options.Value) && $defined(this.Data[id])) {
		//	options.Value = this.Data[id];
		//	options.Data = this.Data;
		//}
		var b = new wfx.Button(id, options, props);
		//if(b.options.NewRow) this.AddRow('', b);
		//else 
		this.appendChild(b);
		var self = this;
		if(options.Submit) {
			b.addEvent('click', function() { self.Submit(id); });
		}
		this.Buttons[id] = b;
		return b;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: AddRow
	//-----------------------------------------------------------------------------------------------------------------------------
	AddRow: function(col1, col2, props, insertAfter) {//label, field, id) {
		//wfx.log("AddRow");
		var r = null;
		var tr = 'tr';
		var td = 'td';
		if(this.options.Layout != 'Table') {
			tr = 'div';
			td = 'div'
		}

		// Create row container
		//wfx.log(props);
		r = new Element('tr', {'class':'row'});
		if($defined(props)) r.setProperties(props);
		
		var col1span = 1;
		var col1class = "label";
		var col2span = 1;
		var col2class = "field";
		
		if(col1 && !col2) {
			col1span = 2;
			col1class = "labelspan";
		}
		if(!col1 && col2) {
			col2span = 2;
			col2class = "fieldspan";
		}
		
		if(col1) {
		// Create a 2 column row with label and field
			//var l = r.addElement('td', );
			//var l = new Element('td', {'class':col1class, 'colspan':col1span});//, {'colspan':col1span});
			var l = r.addElement('td', {'class':col1class, 'colspan':col1span});
			l.innerHTML = col1;
		}
		if(col2) {
			//var f = r.addElement('td', {'class':col2class, 'colspan':col2span});
			var f = r.addElement('td', {'colspan':col2span});
			if($type(col2) == "string") {
				f.innerHTML = col2;
			}
			else {
				f.appendChild(col2);
			}
		}

		if(this.options.Layout == 'Table') {
			//wfx.log('Table Layout');
			if($defined(insertAfter)) {
				var item;
				if($defined(this.Fields[insertAfter])) {
				// If a field is specified, assume the whole row is meant
					item = this.getElement("#"+insertAfter+"Row");
				}
				//wfx.log("insertAfter:"+insertAfter);
				r.inject(item, 'after');
			}
			else {
				this.Table.appendChild(r);
			}
		}
		else {
			//wfx.log('List Layout');
			this.appendChild(r);
		}

		return r;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: AddRowHeadings
	//-----------------------------------------------------------------------------------------------------------------------------
	AddRowHeadings: function(label, field) {
		this.AddRow(label, field, {'class':'heading'});
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: RemoveInput
	//-----------------------------------------------------------------------------------------------------------------------------
	RemoveInput: function(id) {
		if($defined(this.Fields[id])) {
			this.Fields[id].destroy();
			this.Fields[id] = undefined;
			
			$(id+"Row").destroy();
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Enable
	//-----------------------------------------------------------------------------------------------------------------------------
	Enable: function(id) {
		if($defined(this.Fields[id])) {
			this.Fields[id].Enable();
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Disable
	//-----------------------------------------------------------------------------------------------------------------------------
	Disable: function(id) {
		if($defined(this.Fields[id])) {
			this.Fields[id].Disable();
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Show
	//-----------------------------------------------------------------------------------------------------------------------------
	// TODO: Improve Show and Hide for form elements so that the whole row gets hidden
	//-----------------------------------------------------------------------------------------------------------------------------
	Show: function(id) {
		if($defined(this.Fields[id])) {
			this.Fields[id].show();
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Hide
	//-----------------------------------------------------------------------------------------------------------------------------
	Hide: function(id) {
		if($defined(this.Fields[id])) {
			this.Fields[id].hide();
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: SetFocus
	//-----------------------------------------------------------------------------------------------------------------------------
	SetFocus: function(name) {
		//wfx.log("wfx.Form.SetFocus:"+name);
		this.Fields[name].focus();
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: SetValue
	//-----------------------------------------------------------------------------------------------------------------------------
	SetValue: function(name, v) {
		//wfx.log("wfx.Form.SetValue("+name+", "+v+")");
		if(this.Fields[name]) {
			if($defined(this.Fields[name].SetValue)) {
				this.Fields[name].SetValue(v);
			}
			else 
			if($defined(this.Fields[name].value)) {
				this.Fields[name].value = v;
			}
		}
		else wfx.error("The form '"+this.id+"' does not contain the field '"+name+"'");
		
		this.fireEvent('change');
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: GetValue
	//-----------------------------------------------------------------------------------------------------------------------------
	GetValue: function(name) {
		//wfx.log("wfx.Form.GetValue:"+name);
		if(this.Fields[name]) {
			if($defined(this.Fields[name].GetValue)) {
				return this.Fields[name].GetValue();
			}
			else 
			if($defined(this.Fields[name].value)) {
				return this.Fields[name].value;
			}
		}
		return null;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: GetData
	//-----------------------------------------------------------------------------------------------------------------------------
	GetData: function() {
		//wfx.log("wfx.Form.GetData()");
		var data = {};//{ DataType:this.DataType };
		for(var i in this.Fields) {
		//	//wfx.log(i);
			data[i] = this.GetValue(i);
			//if($defined(this.Fields[i].value)) {
			//	data[i] = this.Fields[i].value;
			//	//wfx.log(i+"="+this.Fields[i].value);
			//}
		}
		return data;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: SetData
	//-----------------------------------------------------------------------------------------------------------------------------
	// This take a data object (such as a Json response object) and updates each matching field in the
	// form. 
	//-----------------------------------------------------------------------------------------------------------------------------
	SetData: function(data) {
		//wfx.log("wfx.Form.SetData()");
		for(var i in data) {
		//	//wfx.log(i);
			if(this.Fields[i]) {
				//wfx.log("Updating Field: "+i);
				this.SetValue(i, data[i]);
			}
			else {
				//wfx.log("Field not found: "+i);
			}
		}
		return data;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: toQueryString
	//-----------------------------------------------------------------------------------------------------------------------------
	toQueryString: function() {
		//wfx.log("wfx.Form.toQueryString()");
		var data = "";//"&DataType="+this.DataType;
		for(var i in this.Fields) {
			//wfx.log(i+"="+this.GetValue(i));
			data += "&"+i+"="+this.GetValue(i);
			//if($defined(this.Fields[i].value)) {
			//	data[i] = this.Fields[i].GetValue();
			//	//wfx.log(i+"="+this.Fields[i].value);
			//}
		}
		return data;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: GetParentWindow
	//-----------------------------------------------------------------------------------------------------------------------------
	GetParentWindow: function() {
		//wfx.log("wfx.Form.GetParentWindow");
		var parent = this.getParent('.vw');
		if(!parent) parent = document;
		return parent;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: ReloadValues
	//-----------------------------------------------------------------------------------------------------------------------------
	ReloadValues: function() {
		//wfx.log("wfx.Form.ReloadValues");
		if(this.options.Data) {
			for(var i in this.Fields) {
		//		//wfx.log(i);
				if($defined(this.Fields[i].value)) {
					this.Fields[i].value = this.options.Data[i];
					//wfx.log(i+"="+this.Fields[i].value);
				}
			}
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Submit
	//-----------------------------------------------------------------------------------------------------------------------------
	Submit: function(withCmd) {
		//wfx.log("wfx.Form.Submit("+withCmd+")");
		if(this.options.Validate) {
			var v = this.options.Validate(this, withCmd);
			if(!v) {
				//wfx.log("FORM INVALID");
				return;
			}
			else {
				//wfx.log("FORM VALID");
			}
		}
		if(!this.options.UseAjax) {
		// When Ajax is not being used, the traditional approach of submitting the form and refreshing
		// the page is used. We do this by calling the built-in JavaScript form submit method.
			if(!$defined(this.Fields['CMD'])) {
				this.AddInput('CMD', {Type:'hidden', Value:withCmd}, {});			
			}
			this.submit();
		}
		else {
		// When Ajax is enabled for the form, the submit is passed in the background without reloading
		// the page. There are two ways in which the form data can be handled, shown below.
			//wfx.log("AjaxOptions");
			//for(var d in this.options.AjaxOptions) {
			//	//wfx.log(d +"="+this.options.AjaxOptions[d]);
			//}
			if(this.options.UseJson) {
			// Here we take the form as an object (or the object it represents) and encode it with
			// Json as a single argument.
				//wfx.log("JSON");
				var arg = this.GetValue('ID')+"="+wfx.Encode(this.GetData());
			//	//wfx.log("arg:"+arg);
				wfx.Ajax({cmd:withCmd, args:arg}, this.options.AjaxOptions);//{evalResponse:true, async:this.options.Async});
			}
			else {
			// Using a more traditional approach, each form value will be added to the query string as
			// a variable. This is done automatically by wfx.Ajax
				wfx.Ajax({cmd:withCmd, form:this.id}, this.options.AjaxOptions);//{evalResponse:true, async:this.options.Async, isSuccess:this.options.on});
			}
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: onChange
	//-----------------------------------------------------------------------------------------------------------------------------
	onChange: function(event) {
		//wfx.log("wfx.Form.onChange");
		//this.Data.Modified = true;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: onResize
	//-----------------------------------------------------------------------------------------------------------------------------
	onResize: function() {
		//wfx.log("wfx.Form.onResize");
		//wfx.log(this.id);
		//this.Data.Modified = true;
		var size = this.getParent().getSize();
		this.setStyle('height', size.y);
		
		this.getElements('textarea').each( function(input) {
			//if(input.type == "textarea") {
				var s = input.getParent().getSize();
			//	input.setStyle('height', s.y-20);
				//wfx.log("input height:"+s.y);
			//}
		});
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Destroy
	//-----------------------------------------------------------------------------------------------------------------------------
	Destroy: function() {
		//wfx.log("wfx.Form.Destroy");
		wfx.Forms[this.id] = undefined;
		this.destroy();
	}
});
//wfx.Form.implement(new Options, new Events);

//-----------------------------------------------------------------------------------------------------------------------------
//: Tabs
//-----------------------------------------------------------------------------------------------------------------------------
// This creates a multi-tabbed view, showing and hiding the content based on user interation.
//-----------------------------------------------------------------------------------------------------------------------------
wfx.Tabs = new Class({
	Extends: wfx.Object,
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: initialize
	//-----------------------------------------------------------------------------------------------------------------------------
	initialize: function(id, options) {
		//wfx.log("wfx.Tabs.Init");
		var self = this.parent(id, 'div', options);
		self.set({'class':'tabs'});

		// create a UL for the self
		self.headings = self.addElement('ul', {'class':'tabs', id:id+"H"});
		
		// create a UL for the tab content
		self.contents = self.addElement('ul', {'class':'tabsC', id:id+"C"});
		
		return self;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Add
	//-----------------------------------------------------------------------------------------------------------------------------
	Add: function(id, name, content) {
		//wfx.log("wfx.Tabs.Add");
		
		var h = this.headings.addElement('li', {id:id});
		if($type(name) == "string") {
			h.innerHTML = name;
		}
		else {
			h.appendChild(name);
		}
		var c = this.contents.addElement('li', {id:id+"C"});
		if($type(content) == "string") {
			c.innerHTML = content;
		}
		else {
			c.appendChild(content);
		}
		
		h.addEvents({
			click:this.Select.bind(this, h)
		});
		h.setStyle('cursor', 'pointer');
		
		//this.Select(h);
		return h;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Select
	//-----------------------------------------------------------------------------------------------------------------------------
	Select: function(tabID) {
		//wfx.log("wfx.Tabs.Select");
		
		//wfx.log("select: "+tabID);
		
		var hs = this.headings.getElements('li');
		var tab = null;
		
		if($type(tabID) == 'string') {
		// We need to find the tab object by name or id
			for(var i=0; i<hs.length; i++) {
				//wfx.log("li: "+hs[i].id);
				if(hs[i].id == tabID || hs[i].innerHTML == tabID) {
					tab = hs[i];
					break;
				}
			}
		}
		
		if(!tab) {
			wfx.error("The specified tab ("+tabID+") does not exist");
			return;
		}
		
		// loop through all the tabs and deselect all but the one
		hs.each(
			function(li) {
				//wfx.log("li: "+li.getProperty('id'));
				li.setProperty('class', (li == tab) ? 'selected' : 'deselect');
			}
		);
		
		// loop through all the content and hide all but the selected
		var c = $(tab.getProperty('id')+"C");
		this.contents.getElements('li').each(
			function(li) {
				//wfx.log("li: "+li.getProperty('id'));
				li.setStyle('display', (li == c) ? 'block' : 'none');
			}
		);
	}
}); // Tabs


//-----------------------------------------------------------------------------------------------------------------------------
//: Menu
//-----------------------------------------------------------------------------------------------------------------------------
// This creates an application-style menu bar with hierarchical submenus. This class uses the
// modalizer to help control interactivity, since mouse over and out events are unreliable on their
// own. The display of the menu is controlled by a simple set of CSS rules based on wfxMenu.
//-----------------------------------------------------------------------------------------------------------------------------
wfx.Menu = new Class({
	Extends: wfx.Object,
	Implements: [Events, Modalizer],
	options: {
		Overlap:10
	},
	modalOptions: {},
	Menus: null,
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: initialize
	//-----------------------------------------------------------------------------------------------------------------------------
	initialize: function(id, options) {
		//wfx.log("wfx.Menu.Init");

		this.setModalStyle({zIndex:1000, 'background-color':'none', opacity:0.5});
		var self = this.parent(id, 'div', options);
		self.modalOptions.onModalHide = this.Dismiss.bind(self);
		self.set({'class':'wfxMenu', id:id});

		// Create the primary list element for the menu. This will be the horizontal bar.
		self.Menus = [self.addElement('ul', {id:id+"UL"})];
				
		return self;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Invoke
	//-----------------------------------------------------------------------------------------------------------------------------
	// This method instantiates the first submenu, using the modalizer to temporarily capture mouse
	// input from the whole page. The floating submenu is then displayed in front.
	//-----------------------------------------------------------------------------------------------------------------------------
	Invoke: function(parentItem) {
		//wfx.log("wfx.Menu.Invoke");
		this.modalShow(); 
		
		// When the modalizer is invoked, it pops over the original menu. To prevent the modalizer
		// from immediately disappearing (due to mouseover) we need to create a copy of the menu
		// item that will float above the modalizer layer temporarily.
		//wfx.log("cloning: "+parentItem.id);
		var pos = parentItem.getPosition();
		this.menuTemp = parentItem.clone(true, true);
		parentItem.parentNode.appendChild(this.menuTemp);
		this.menuTemp.setStyles({'z-index':1001, position:'absolute', top:pos.y, left:pos.x});//, background:'red'
		this.menuTemp.addClass('over');
		
		var m = this.toElement();
		var self = this;
		m.addEvent('mouseover', function(event) {
			self.modalHide();
			event.stop();
		});
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Dismiss
	//-----------------------------------------------------------------------------------------------------------------------------
	Dismiss: function() {
		//wfx.log("wfx.Menu.Dismiss");
		this.menuTemp.dispose();
		for(var n=1; n<this.Menus.length; n++) {
			this.Menus[n].invisible();
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Add
	//-----------------------------------------------------------------------------------------------------------------------------
	// This adds a series of list items (LI) to an existing menu. If the list contains sub-children, this 
	// will be expanded into a submenu. Each submenu is a virtual child of a menu item.
	//-----------------------------------------------------------------------------------------------------------------------------
	Add: function(items, parentItem, depth) {
		//wfx.log("wfx.Menu.Add");
		
		if(!depth) depth = 0;
		var parentMenu = null;
		if(!$defined(parentItem)) {
			parentItem = null;
			parentMenu = this.Menus[0];
		}
		else {
			parentItem = $(parentItem);
			parentMenu = $(parentItem.id+"UL");
		}
		
		if(!$defined(this.Items)) this.Items = [];
		
		var self = this;
		for(var i in items) {
			//wfx.log("   Adding:"+i);
			this.Items[i] = parentMenu.addElement('li', {id:i});
			//this.Items[i] = newItem;
			
			if(i == "divider") {
				this.Items[i].innerHTML = "<hr>";
			}
			else {
				var h = "";
				h += "<div class='wfxMenuIcon'>";
				if(items[i].Icon) {
					h += "<img src='"+wfx.IconUrl(items[i].Icon)+"'>";
				}
				h += "</div>";
				h += "<div class='wfxMenuLabel'>"+items[i].Label+"</div>";
				h += "<div class='wfxMenuStatusIcon'>";
				if($defined(items[i].Children)) {
					h += "<img src='"+wfx.IconUrl('resultset_next')+"'>";
				}
				else 
				if(items[i].StatusIcon) {
					h += "<img id='"+i+"Status' src='"+wfx.IconUrl(items[i].StatusIcon)+"'>";
				}
				h += "</div>";
				this.Items[i].innerHTML = h;
				
				if($defined(items[i].Status)) this.Items[i].Status = items[i].Status;
				
				
				this.Items[i].addEvent('mouseover', function(event) { 
					this.addClass('over'); 
					
					// We need to additionally close all submenus. If the current menu item has a
					// submenu, it will be displayed by the other mouseover event installed.
					for(n=1; n<self.Menus.length; n++) {
						if(depth <= self.Menus[n].depth) {
							self.Menus[n].invisible();
						}
					}
				});
				
				this.Items[i].addEvent('mouseout', function(event) { 
					this.removeClass('over'); 
					event.stop();
				});
				this.Items[i].Action = items[i].Action;
				this.Items[i].addEvent('click', function(event) { 
					this.Action.call();
					self.Dismiss();
					event.stop();
				});
				for(var e in this.Items[i].$events) {
					//wfx.log("event:"+e);
				}
			
				if($defined(items[i].Children)) {
					this.AddList(this.Items[i], parentMenu, depth);
					this.Add(items[i].Children, this.Items[i], depth+1);
				}
			}
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: AddList
	//-----------------------------------------------------------------------------------------------------------------------------
	// This adds a new submenu for an item. To avoid problems with Z order and nested divs, we'll
	// create the new UL elements at the document level. 
	//-----------------------------------------------------------------------------------------------------------------------------
	AddList: function(parentItem, parentMenu, depth) {
		parentItem = $(parentItem);
		//wfx.log("wfx.Menu.AddList:"+parentItem.id);
		
		// Create a new menu layer. It is placed at the end of the document to avoid display issues
		// however this also means that the UL items do not have a parent-child relationship in the DOM.
		// Relationships are stored instead by this class and the display mimics hierarchy using dynamic 
		// positions.
		var n = this.Menus.length;
		//wfx.log("menu count:"+n);
		this.Menus[n] = document.createElement('ul');
		this.Menus[n].set({'class':'wfxMenuSub'});
		this.Menus[n].id = parentItem.id+"UL";
		this.Menus[n].invisible();
		this.Menus[n].depth = depth;
		this.Menus[n].parentMenu = parentMenu;
		document.body.appendChild(this.Menus[n]);
		
		var self = this;
		var menu = this.Menus[n];
		parentItem.addEvent('mouseover', function() {
			//wfx.log("mouseover "+this.id);
			if(depth == 0) {
				self.Invoke(parentItem);
			}
			var coords = this.getCoordinates();
			var pos;
			
			if(!depth) {
			// Align the list as a drop down menu
				pos = {x: coords.left, y: coords.top + coords.height};
			}
			else {
			// Align the menu as a side flyout menu
				pos = {x: (coords.left + coords.width) - self.options.Overlap, y: coords.top};
			}
			
			menu.setPosition(pos);
			menu.visible();
		});
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: GetStatus
	//-----------------------------------------------------------------------------------------------------------------------------
	GetStatus: function(itemID) {
		//wfx.log("wfx.Menu.GetStatus");
		return $(itemID).Status;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: SetStatus
	//-----------------------------------------------------------------------------------------------------------------------------
	SetStatus: function(itemID, status, icon) {
		//wfx.log("wfx.Menu.SetStatus:"+itemID);
		$(itemID).Status = status;
		$(itemID+"Status").src = wfx.IconUrl(icon);
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Enable
	//-----------------------------------------------------------------------------------------------------------------------------
	Enable: function(itemID) {
		//wfx.log("wfx.Menu.Enable:"+itemID);
		//$(itemID).Status = status;
		//$(itemID+"Status").src = wfx.IconUrl(icon);
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Disable
	//-----------------------------------------------------------------------------------------------------------------------------
	Disable: function(itemID) {
		//wfx.log("wfx.Menu.Disable:"+itemID);
		//this.Items[itemID].addEvent('click', function(ev) { wfx.Alert('test'); ev.stop(); });//
	//	this.Items[itemID].removeEvents(['mouseover']);
	//	this.Items[itemID].setOpacity(0.5);
		this.Items[itemID].removeEvents();
	//	for(var e in this.Items[itemID].$events) {
	//		//wfx.log("event:"+e);
	//	}
	}
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Select
	//-----------------------------------------------------------------------------------------------------------------------------
	//Select: function(menu) {
	//	//wfx.log("wfx.Menu.Select");
	//	//wfx.log("select: "+menu);//.getProperty('id'));
	//	var hs = this.headings.getElements('li');
	//	if($type(menu) == 'string') {
		// We need to find the menu object by name or id
	//		for(var i=0; i<hs.length; i++) {
	//			//wfx.log("li: "+hs[i].id);
	//			if(hs[i].id == menu || hs[i].innerHTML == menu) {
	//				menu = hs[i];
	//				break;
	//			}
	//		}
	//	}
		
		// loop through all the menu and deselect all but the one
	//	hs.each(
	//		function(li) {
	//			//wfx.log("li: "+li.getProperty('id'));
	//			li.setProperty('class', (li == menu) ? 'selected' : 'deselect');
	//		}
	//	);
	//	
	//	// loop through all the content and hide all but the selected
	//	var c = $(menu.getProperty('id')+"C");
	//	this.contents.getElements('li').each(
	//		function(li) {
	//			//wfx.log("li: "+li.getProperty('id'));
	//			li.setStyle('display', (li == c) ? 'block' : 'none');
	//		}
	//	);
	//}
	
}); // Menu

//-----------------------------------------------------------------------------------------------------------------------------
//: Login
//-----------------------------------------------------------------------------------------------------------------------------
wfx.Login = {
	Data:null,
	Container:null,
	Form:null,
	
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: initialize
	//-----------------------------------------------------------------------------------------------------------------------------
	initialize: function(container, data) {
		//wfx.log("wfx.Login.initialize");
		wfx.Login.Data = eval(data);
		
		if(!wfx.Login.Container) {
			wfx.Login.Container = $(container);
			wfx.Login.Container.Message = $(document.createElement('div'));
			wfx.Login.Container.Contents = $(document.createElement('div'));
			wfx.Login.Container.appendChild(wfx.Login.Container.Message);
			wfx.Login.Container.appendChild(wfx.Login.Container.Contents);
		}
	
		wfx.Login.Update();
	},
	
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: destroy
	//-----------------------------------------------------------------------------------------------------------------------------
	destroy: function() {
		wfx.Login.Container.Contents.destroy();
		wfx.Login.Container.Message.destroy();
		wfx.Login.Container.destroy();
		
		wfx.Login.Container = null;
	},

	//-----------------------------------------------------------------------------------------------------------------------------
	//: Update
	//-----------------------------------------------------------------------------------------------------------------------------
	// 
	//-----------------------------------------------------------------------------------------------------------------------------
	Update: function() {
		//wfx.log("wfx.Login.Update");
	
		if(wfx.Login.Data.UserAccess) {
			//wfx.log("LOGGED IN");
			wfx.Login.ShowInfo();
		}
		else {
			//wfx.log("NOT LOGGED IN");
			wfx.Login.ShowForm();
		}
		
	}, // Update
	
	//-----------------------------------------------------------------------------------------------------------------------------
	//: ShowInfo
	//-----------------------------------------------------------------------------------------------------------------------------
	// 
	//-----------------------------------------------------------------------------------------------------------------------------
	ShowInfo: function() {
		//wfx.log("wfx.Login.ShowInfo");
	
		wfx.Login.Container.Message.innerHTML = "<b>You are currently logged in as:</b><br>";
	
		wfx.Login.Form = new wfx.Form('loginInfo', {Validate:wfx.Login.Validate});
		wfx.Login.Form.AddRow("Login", wfx.Login.Data.Login);
		wfx.Login.Form.AddRow("Access", wfx.Login.Data.UserAccess);
		wfx.Login.Form.AddButton("cmdReLogin", 	{Label:'Re-Login', Submit:false, Action:wfx.Login.ShowForm},		{});
		wfx.Login.Form.AddButton("cmdLogout", 	{Label:'Logout', Submit:false, Action:wfx.Logout},		{});
		
		wfx.Login.Container.Contents.empty();
		wfx.Login.Container.Contents.appendChild(wfx.Login.Form);
	}, // ShowInfo
	
	//-----------------------------------------------------------------------------------------------------------------------------
	//: ShowForm
	//-----------------------------------------------------------------------------------------------------------------------------
	// TODO: Fix login form so that the browser is able to remember logins and passwords.
	//-----------------------------------------------------------------------------------------------------------------------------
	ShowForm: function() {
		//wfx.log("wfx.Login.ShowForm");
	
		if(!$defined(wfx.Login.Data.Message)) wfx.Login.Data.Message = "Please login";
		wfx.Login.Container.Message.innerHTML = "<b>"+wfx.Login.Data.Message+"</b><br>";//
		
		wfx.Login.Form = new wfx.Form('loginForm', {Validate:wfx.Login.Validate, UseAjax:true, AjaxOptions:{onSuccess:wfx.Login.Complete, evalResponse:false}});
	
		wfx.Login.Form.AddInput('Login', 			{Label:'Login', Type:'text'});//, Value:wfx.Login.Data.Login});//, Submit:'cmdLogin'
		wfx.Login.Form.AddInput('Password', 			{Label:'Password', Submit:'cmdLogin', Type:'password', Value:""});
		wfx.Login.Form.AddButton("cmdLogin", 		{Label:'Login', Submit:true},		{});
		wfx.Login.Form.AddButton("cmdLoginCancel", 	{Label:'Cancel'},		{});//*Action:wfx.Login.OverlayWindow.Close});
		wfx.Login.Form.Buttons.cmdLoginCancel.addEvent('click', function() {
			if(wfx.Login.OverlayWindow) wfx.CloseLoginPopup();
			else history.back();
		});
		
		wfx.Login.Container.Contents.empty();
		wfx.Login.Container.Contents.appendChild(wfx.Login.Form);
		wfx.Login.Form.SetFocus('Login');
	}, // ShowForm
	
	//-----------------------------------------------------------------------------------------------------------------------------
	//: Complete
	//-----------------------------------------------------------------------------------------------------------------------------
	// 
	//-----------------------------------------------------------------------------------------------------------------------------
	Complete: function(responseText, repsonseXML) {
		//wfx.log("wfx.Login.Complete");
		//wfx.log("responseText:"+responseText);
		//wfx.log("repsonseXML:"+repsonseXML);
		wfx.Login.Data = eval(responseText);
	
		//wfx.log("wfx.Login.Data");
		for(var d in wfx.Login.Data) {
			//wfx.log(d +"="+wfx.Login.Data[d]);
		}
	
		wfx.Login.Update();
		
		if(wfx.Login.Data.UserAccess > 1) {
			window.location.reload();
		}
	}, // Complete
	
	//-----------------------------------------------------------------------------------------------------------------------------
	//: Validate
	//-----------------------------------------------------------------------------------------------------------------------------
	// 
	//-----------------------------------------------------------------------------------------------------------------------------
	Validate: function(form, cmd) {
		//wfx.log("wfx.Login.Validate");
		
		var valid = true;
		if(cmd == "cmdLogin") {
			if(!form.GetValue('Login')) {
				//wfx.log("No login");
				valid = false;
				wfx.Login.Container.Message.innerHTML = "<div class='warning'>Please enter your login name</div>";
				wfx.Login.Form.SetFocus('Login');
			}
			else
			if(!form.GetValue('Password')) {
				//wfx.log("No password");
				valid = false;
				wfx.Login.Container.Message.innerHTML = "<div class='warning'>Please enter your password</div>";
				wfx.Login.Form.SetFocus('Password');
			}
		}
	
		return valid;
	} // Validate
	
}; // Login

//-----------------------------------------------------------------------------------------------------------------------------
//: ShowLogin
//-----------------------------------------------------------------------------------------------------------------------------
// 
//-----------------------------------------------------------------------------------------------------------------------------
wfx.ShowLogin = function(container, data) {
	//wfx.log("wfx.ShowLogin("+container+", "+data+")");
	wfx.Login.initialize(container, data);
}; // ShowLogin

//-----------------------------------------------------------------------------------------------------------------------------
//: ShowLoginPopup
//-----------------------------------------------------------------------------------------------------------------------------
// TODO: implement login popup as modal window
//-----------------------------------------------------------------------------------------------------------------------------
wfx.ShowLoginPopup = function() {
	//wfx.log("wfx.ShowLoginPopup()");
	
	wfx.Ajax({cmd:"cmdLogin"}, {onSuccess:wfx.ShowLoginPopupLoad});
	
	wfx.Login.Overlay = new Element('div', {
		'class': 'overlay',
		styles: {
			zIndex:1000,
			opacity:0.8
		}
	});
	wfx.Login.Overlay.inject(document.body);
	//wfx.Login.Overlay.setStyle('opacity', 0.8);

	wfx.Login.Overlay.setStyles({
		'top': window.getScroll().y, 
		'height': window.getSize().y
	});
	wfx.Login.Overlay.addEvent('click', wfx.CloseLoginPopup);

	var overlayFx = new Fx.Tween(wfx.Login.Overlay, {property: 'opacity', duration: 500}).set(0);
	overlayFx.start(0.8);

	wfx.Login.OverlayWindow = new Element('div', {
		styles: {	
			width: '300px', 
		/*	height: '200px', */
			marginLeft: '-150px',
			display: 'block',
			zIndex:1001
		}
	}).inject(document.body).addClass('overlayWindow');

	wfx.Login.OverlayTitle = new Element('div', {'class':'title'}).inject(wfx.Login.OverlayWindow);
	wfx.Login.OverlayTitle.innerHTML = kCompanyName;//document.title;// "Login";

	wfx.Login.OverlayContent = new Element('div', {
		'class': 'overlayContent'
	}).inject(wfx.Login.OverlayWindow);
	
	wfx.Login.OverlayContent.setProperty('id', 'logincontent');

	var top = (window.getScroll().y + (window.getSize().y / 15)).toInt();
	wfx.Login.OverlayWindow.setStyles({
		top: top,
		display: ''
	});
	
}; // ShowLoginPopup

//-----------------------------------------------------------------------------------------------------------------------------
//: ShowLoginPopupLoad
//-----------------------------------------------------------------------------------------------------------------------------
// 
//-----------------------------------------------------------------------------------------------------------------------------
wfx.ShowLoginPopupLoad = function(responseText, repsonseXML) {
	//wfx.log("wfx.ShowLoginPopupLoad()");
	
	wfx.Login.initialize('logincontent', eval(responseText));
}; // ShowLoginPopupLoad


//-----------------------------------------------------------------------------------------------------------------------------
//: CloseLoginPopup
//-----------------------------------------------------------------------------------------------------------------------------
// 
//-----------------------------------------------------------------------------------------------------------------------------
wfx.CloseLoginPopup = function() {
	//wfx.log("wfx.CloseLoginPopup()");
	
	wfx.Login.OverlayContent.destroy();
	wfx.Login.OverlayWindow.destroy();
	wfx.Login.Overlay.destroy();
	
	wfx.Login.destroy();
	
}; // CloseLoginPopup

//-----------------------------------------------------------------------------------------------------------------------------
//: Logout
//-----------------------------------------------------------------------------------------------------------------------------
// 
//-----------------------------------------------------------------------------------------------------------------------------
wfx.Logout = function() {
	//wfx.log("wfx.Logout");
	window.location = kWeb+"logout";
}

wfx.DebugBuffer = null;
//-----------------------------------------------------------------------------------------------------------------------------
//: Debug
//-----------------------------------------------------------------------------------------------------------------------------
wfx.Debug = {
	LastID:null,
	LastErrorID:null,
	Win:null,
	Count:0,

	//-----------------------------------------------------------------------------------------------------------------------------
	// Init
	//-----------------------------------------------------------------------------------------------------------------------------
	Init: function(re) {
		//wfx.log("wfx.Debug.Init");
		
		wfx.Debug.Window = $('debugWindow');//new Element('div', {'class': 'debugWindow'});
		//wfx.Debug.Window.inject(document.body);
		
		if($defined(wfx.DebugBuffer)) {
			if(wfx.DebugBuffer.length > 0) {
				wfx.Debug.Add(wfx.DebugBuffer);
				wfx.DebugBuffer = null;
			}
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	// Add
	//-----------------------------------------------------------------------------------------------------------------------------
	Add: function(content) {
		//wfx.log("wfx.Debug.Add");
		wfx.Debug.Count++;
		
		var id = 'dbg'+wfx.Debug.Count;
		var dbg = new Element('div', {'class': 'debugBlock'});
		dbg.setProperty('id', id);

		wfx.Debug.Window.appendChild(dbg);

		var dbgTitle = new Element('div', {'class': 'debugBlockTitle'});
		var cmdStart = content.indexOf("CMD=");
		var title = id;
		if(cmdStart != -1) {
			var cmdEnd = content.indexOf("<br>", cmdStart);
			title = content.substring(cmdStart+4, cmdEnd);
			
			var idStart = content.indexOf("ID=");
			if(idStart != -1) {
				var idEnd = content.indexOf("<br>", idStart);
				title += ":"+content.substring(idStart+3, idEnd);
			}
		}
		if(title == "dbg1") title = "onPageLoad";
		
		dbgTitle.innerHTML = title;
		dbgTitle.inject(dbg);

		var dbgContent = new Element('div', {'class': 'debugBlockContent'});
		dbgContent.innerHTML = content;
		dbgContent.inject(dbg);
		dbgContent.hide();
		
		dbgTitle.addEvent('click', function(ev) {
			if(dbgContent.isVisible()) {
				dbgContent.hide();
			}
			else {
				dbgContent.show();
			}
		});
		
		/*
		var id = 'dbg'+wfx.Debug.Count;
		b = new wfx.Button(id, {Icon:'bug', Label:'', Action:wfx.Debug.Show.bind(this, id), Style:'dbgBug'});
		document.body.appendChild(b);
		var c = document.body.addElement('div', {id:id+'Data', 'class':'hidden'});
		c.innerHTML = content;
		//wfx.App.Page.appendChild(b);
		//var c = wfx.App.Page.addElement('div', {id:id+'Data', 'class':'hidden'});
		//c.innerHTML = content;
		*/
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	// Show
	//-----------------------------------------------------------------------------------------------------------------------------
	Show: function(id) {
		//wfx.log("wfx.Debug.Show");
		/*
		var v = false;
		if(!wfx.Debug.Win) {
			wfx.Debug.Win = new wfx.Window('dbg', {Title:'Debug'});
			v = wfx.Debug.Win.Views.Add('Main');
			wfx.Debug.Win.Show();
		}
		if(wfx.Debug.LastID == id) {
			wfx.Debug.Win.Toggle();
		}
	 	wfx.Debug.Win.SetTitle(id);
		
		if(!v) v = wfx.Debug.Win.Views.Get('Main');
	 	v.innerHTML = $(id+"Data").innerHTML;
	 	wfx.Debug.LastID = id;
	 	*/
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	// Clear
	//-----------------------------------------------------------------------------------------------------------------------------
	Clear: function() {
		wfx.Debug.Window.empty();
	}
	
}; // Debug


//-----------------------------------------------------------------------------------------------------------------------------
//: ShowContactForm
//-----------------------------------------------------------------------------------------------------------------------------
// 
//-----------------------------------------------------------------------------------------------------------------------------
wfx.ShowContactForm = function(id) {
	wfx.log("wfx.ShowContactForm");
	
	if(!id) id = 'ContactForm';

	var form = new wfx.Form("ContactFormForm", {UseAjax:true, UseJson:true, AjaxOptions:{async:false}});
	$(id).appendChild(form);
	
	form.AddRow(' ', "<div id='emailAddressLink' ><a onclick='wfx.ContactShowEmail();'>Click here for email address</a></div>");//"<a href='mailto:steve@walkerfx.com'>Steven Walker &lt;steve@walkerfx.com&gt;</a>");//"steve at walkerfx dot com");//
	form.AddInput('Name', 		{Label:'Name', 			Type:'text'}, 		{});
	form.AddInput('Email', 		{Label:'Email', 			Type:'text'}, 		{});
//	form.AddInput('Subject', 		{Label:'Subject', 		Type:'text'}, 		{});
//	form.AddRow('Message', " ");
	form.AddInput('Message', 		{Label:'Message', Type:'textarea'}, 		{});
	
	var errorDiv = document.createElement('div');
	errorDiv.id = 'ContactFormError';
	form.appendChild(errorDiv);

	form.AddButton('cmdContact', 	{Label:'Send Message', Submit:false});
	form.Buttons.cmdContact.addEvent('click', function(e) {
		if(!form.GetValue('Name') || !form.GetValue('Email') || !form.GetValue('Message')) {
			//alert('Please provide your name.');
			errorDiv.innerHTML = "Please fill in all of the fields above.";
		}
		else {
			wfx.Ajax({cmd:"cmdContact", form:form},
				{evalResponse:false, onComplete:wfx.ContactFormSubmitted.bind(form)}); 
		}
	});
};

wfx.ContactFormSubmitted = function() {
	wfx.log("wfx.ContactFormSubmitted:"+this.id);
	//alert('Sumbitted');
	this.empty();
	this.innerHTML = "<h1>Thank you!</h1>I will respond to your message as soon as possible.";
};

wfx.ContactShowEmail = function() {
	$('emailAddressLink').innerHTML = "<a href='mailto:steve"+"@walkerfx.com'>Steven Walker &lt;steve@"+"walkerfx.com&gt;</a>";
}

//-----------------------------------------------------------------------------------------------------------------------------
//: AutoLightbox
//-----------------------------------------------------------------------------------------------------------------------------
// This finds any images on the page that are lightbox candidates and makes them into a lightbox 
// link. It is assumed that images with the property rel='lightbox' are preview sized images with a
// full size counterpart. These images should be organized in directories named 'preview' and 'full',
// so that this script is easily able to remap the source path to the full sized image for lightbox.
//
// TODO: Customize LightBox display: add page links, move close to the top of the window
//-----------------------------------------------------------------------------------------------------------------------------
wfx.AutoLightbox = {

	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Init
	//-----------------------------------------------------------------------------------------------------------------------------
	Init: function(re) {
		//wfx.log("wfx.AutoLightbox.Init");
		
		$$("img[rel^=lightbox]").each( function(img) {
			//wfx.log(img.src);
			var src = img.src.replace("preview/", "full/");
			src = src.replace("png", "jpg");
			var link = new Element('a', {rel:img.getProperty('rel'), href:src});
			link.wraps(img);

			// the rel property is removed to prevent this script being applied twice to the same image
			img.removeProperty('rel');
		});
	}
	
}; // AutoLightbox

//-----------------------------------------------------------------------------------------------------------------------------
//: AutoBoxin
//-----------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------
wfx.AutoBoxin = {

	//-----------------------------------------------------------------------------------------------------------------------------
	//:: Init
	//-----------------------------------------------------------------------------------------------------------------------------
	Init: function(re) {
		wfx.log("wfx.AutoBoxin.Init");
		
		$$("div[rel^=boxin]").each( function(div) {
			var children = div.getChildren();
			
			if(false) {//Browser.Engine.trident) {
			
			}
			else {
				var wrap = new Element('div');
				wrap.setProperties({'class':div.getProperty('class'), 'id':div.id});
				wrap.wraps(div);
				
				div.removeProperties('id', 'class', 'rel');
				
				var table = new Element('table', {'class':'boxinTable'});
				var tbody = new Element('tbody');
				var trow 	= new Element('tr', {'class':'boxinTopRow'});	
				var crow 	= new Element('tr', {'class':'boxinCenterRow'});	
				var brow 	= new Element('tr', {'class':'boxinBotRow'});	
	
				var tl 	= new Element('td', {'class':'boxinTopLeft'});	
				var tc 	= new Element('td', {'class':'boxinTopCenter'});
				var tr 	= new Element('td', {'class':'boxinTopRight'});
				var l 		= new Element('td', {'class':'boxinLeft'});
				var c 	= new Element('td', {'class':'boxinCenter'});
				var r 		= new Element('td', {'class':'boxinRight'});
				var bl 	= new Element('td', {'class':'boxinBotLeft'});
				var bc 	= new Element('td', {'class':'boxinBotCenter'});
				var br 	= new Element('td', {'class':'boxinBotRight'});
				
				wrap.appendChild(table);
				c.appendChild(div);
				
				table.appendChild(tbody);
				tbody.appendChild(trow);
					trow.appendChild(tl);
					trow.appendChild(tc);
					trow.appendChild(tr);
					
				tbody.appendChild(crow);
					crow.appendChild(l);
					crow.appendChild(c);
					crow.appendChild(r);
					
				tbody.appendChild(brow);
					brow.appendChild(bl);
					brow.appendChild(bc);
					brow.appendChild(br);
				
			//	children.each( function(item) {
			//		c.appendChild(item);
			//	});
			//	c.adopt(children);
			//	div.empty();
			//	div.appendChild(table);
				
				// the rel property is removed to prevent this script being applied twice to the same image
				//div.removeProperty('rel');
			}
		});
		
	}
	
}; // AutoBoxin

//-----------------------------------------------------------------------------------------------------------------------------
//: ArticleSet
//-----------------------------------------------------------------------------------------------------------------------------
// This provides functions supporting ArticleSets during regular page interaction
//-----------------------------------------------------------------------------------------------------------------------------
wfx.ArticleSet = {

	//-----------------------------------------------------------------------------------------------------------------------------
	//:: SelectArticle
	//-----------------------------------------------------------------------------------------------------------------------------
	SelectArticle: function(article, source) {
		wfx.log("wfx.ArticleSet.SelectArticle");

		source = $(source);
		var articleSetView = source.getParent(".ArticleSetView");
		if(!articleSetView) {
		// We need to search the whole page to locate the article set
			wfx.log('searching page');
			$$('#'+article).each(function(a, i) {
				wfx.log("article:"+a.id);
				if(!articleSetView) {
					articleSetView = a.getParent(".ArticleSetView");
				}
			});
		}
		if(!articleSetView) {
			wfx.log('failed');
		//	wfx.ShowError("Unable to locate the ArticleSetView!");
		}
		else {
			wfx.log('articleSetView:'+articleSetView.id);
			articleSetView.getElements('.Article').each(function(item, index) {
				item.getElements('a').each(function(a,x) {
					if(item.id == article) {
						a.addClass('selected');
						a.getParent('li').addClass('selected');
					}
					else {
						a.removeClass('selected');
						a.getParent('li').removeClass('selected');
					}
				});
			});
		}
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: LoadArticle
	//-----------------------------------------------------------------------------------------------------------------------------
	LoadArticle: function(articleSet, article, source) {
		wfx.log("wfx.ArticleSet.LoadArticle");
		
		wfx.ArticleSet.SelectArticle(article, source);
		
		var a = "ID="+articleSet+"&Article="+article;//+"&Module=Article&Instance=NEW";
		wfx.Ajax({cmd:"cmdArticleSetLoadArticle", args:a}, {onSuccess:function(response) {
			wfx.ArticleSet.ArticleLoaded(articleSet, article, response);
		}, evalResponse:true});
		
		// load article content
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	//:: ArticleLoaded
	//-----------------------------------------------------------------------------------------------------------------------------
	ArticleLoaded: function(articleSet, article, response) {
		wfx.log("wfx.ArticleSet.ArticleLoaded");
		
		var content = wfx.EvalAjaxResponse(response);
		var articleSet = $(articleSet);
		articleSet.innerHTML = content;
	}
	
}; // ArticleSet


//-----------------------------------------------------------------------------------------------------------------------------
//: ArticleSetView
//-----------------------------------------------------------------------------------------------------------------------------
// This provides functions supporting ArticleSetViews during regular page interaction
//-----------------------------------------------------------------------------------------------------------------------------
wfx.ArticleSetView = {

	//-----------------------------------------------------------------------------------------------------------------------------
	//:: SelectTab
	//-----------------------------------------------------------------------------------------------------------------------------
	SelectTab: function(articleSetView, index) {
		wfx.log("wfx.ArticleSetView.SelectTab("+articleSetView+", "+index);
		
		$(articleSetView).getElements('.wfxArticleSetViewTabPage').each(function(item, i) {
			if(index == i) {
				item.setStyle('display', 'block');
				item.addClass('selected');
			}
			else {
				item.setStyle('display', 'none');
				item.removeClass('selected');
			}
		});
		$(articleSetView).getElements('.wfxArticleSetViewTab').each(function(item, i) {
			if(index == i) {
				item.addClass('selected');
			}
			else {
				item.removeClass('selected');
			}
		});
	}
	
}; // ArticleSetView


//-----------------------------------------------------------------------------------------------------------------------------
//: ArticleCarousel
//-----------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------------
wfx.ArticleCarousel = {

	//-----------------------------------------------------------------------------------------------------------------------------
	//:: ShowSlide
	//-----------------------------------------------------------------------------------------------------------------------------
	ShowSlide: function(articleSet, article, source) {
		wfx.log("wfx.ArticleCarousel.ShowSlide");
		
		wfx.ArticleSet.SelectArticle(article, source);
		
		var articleIndex = 0;
		$(articleSet).getElements('.Article').each(function(item, index) {
			wfx.log(item.id);
			if(item.id == article) {
				articleIndex = index;
			}
		});
		
		var carousel = $(articleSet).getElement('.CarouselPlate');
		var slide = $(articleSet).getElement('.CarouselSlide');
		//var offset =  slide.getSize().x * articleIndex;
		var offset =  slide.getSize().y * articleIndex;
		
		//carousel.setStyle('left', -offset);
		var fx = new Fx.Tween(carousel);
		//fx.start('left', -offset);
		fx.start('top', -offset);
		
		//alert("ShowSlide");
		//var content = wfx.EvalAjaxResponse(response);
		//var articleSet = $(articleSet);
		//articleSet.innerHTML = content;
	}

}; // ArticleCarousel


/*
//-----------------------------------------------------------------------------------------------------------------------------
// : Debug
//-----------------------------------------------------------------------------------------------------------------------------
wfx.Debug = {
	LastID:null,
	LastErrorID:null,
	Win:null,
	Count:0,

	//-----------------------------------------------------------------------------------------------------------------------------
	// Init
	//-----------------------------------------------------------------------------------------------------------------------------
	Init: function(re) {
		//wfx.log("wfx.Debug.Init");
		
		$$('.dbgBug').each(
			function(d) {
				d.setProperty('href', "javascript:wfx.Debug.Show('"+d.id+"');");
			}
		);
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	// Add
	//-----------------------------------------------------------------------------------------------------------------------------
	Add: function(content) {
		//wfx.log("wfx.Debug.Add");
		wfx.Debug.Count++;
		var id = 'dbg'+wfx.Debug.Count;
		b = new wfx.Button(id, {Icon:'bug', Label:'', Action:wfx.Debug.Show.bind(this, id), Style:'dbgBug'});
		document.body.appendChild(b);
		var c = document.body.addElement('div', {id:id+'Data', 'class':'hidden'});
		c.innerHTML = content;
		//wfx.App.Page.appendChild(b);
		//var c = wfx.App.Page.addElement('div', {id:id+'Data', 'class':'hidden'});
		//c.innerHTML = content;
	},
	//-----------------------------------------------------------------------------------------------------------------------------
	// Show
	//-----------------------------------------------------------------------------------------------------------------------------
	Show: function(id) {
		//wfx.log("wfx.Debug.Show");
		var v = false;
		if(!wfx.Debug.Win) {
			wfx.Debug.Win = new wfx.Window('dbg', {Title:'Debug'});
			v = wfx.Debug.Win.Views.Add('Main');
			wfx.Debug.Win.Show();
		}
		if(wfx.Debug.LastID == id) {
			wfx.Debug.Win.Toggle();
		}
	 	wfx.Debug.Win.SetTitle(id);
		
		if(!v) v = wfx.Debug.Win.Views.Get('Main');
	 	v.innerHTML = $(id+"Data").innerHTML;
	 	wfx.Debug.LastID = id;
	}
}; // Debug

*/
