/*!
 * Blast Mojo Framework
 *
 * Copyright (c) 2009, Blast Radius, Inc.
 * All rights reserved.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

dojo.provide("stdlib.behavior.AutoSuggest.SuggestNavigationBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.AutoSuggest.SuggestNavigationBehavior", mojo.command.Behavior, 
{
	suggestionIndex: -1,
	suggestion: null,
	execute: function(requestObj) {
		var e = requestObj.getEvent();
		var up = 38; // up arrow
		var down = 40; // down arrow
		var tabKey = 9; // tab key
		var suggestions = requestObj.getParams().suggestions;
		var suggestionsLength = suggestions.length;
		this.suggestionIndex = -1;
		for (var i = 0; i < suggestionsLength; i++) {
			if (dojo.hasClass(suggestions[i], "selected")) {
				this.suggestionIndex = i;
				break;
			}
		}

		if (e && e.which) {
			e = e;
			characterCode = e.which;
		} else {
			e = event;
			characterCode = e.keyCode;
		}
		
		if (suggestionsLength > 0) {
			switch (characterCode) {
				case up:
					this.suggestionIndex--;
					if (this.suggestionIndex < 0) {
						this.suggestionIndex = suggestionsLength - 1;
					}
					this.suggestion = suggestions[this.suggestionIndex];
					this.onNav();
					break;
				case down:
					this.suggestionIndex++;
					if (this.suggestionIndex >= suggestionsLength) {
						this.suggestionIndex = 0;
					}
					this.suggestion = suggestions[this.suggestionIndex];
					this.onNav();
					break;
			}
		}
	},
	onNav: function() {}
});
/*
	Class: stdlib.behavior.CheckBoxSelectionBehavior
	Author: Jaime Bueza
	
	Provides the ability to check/uncheck multiple or specific checkboxes
	at the same time.
	
	Paramters:
		element - {DOM Array}
		checked - {Boolean}
	
	Example:
		(start code)
		
		//Add an observer to an element to provide the UI the ability to check the checkboxes
		this.addObserver(mojo.queryFirst("#btn-select-all"), "onclick", "CheckBoxSelection", function(context, caller) {
			return {
				element: mojo.query("input[name='dataRecord']"),
				checked: true
			};
		});
		(end)
*/
dojo.provide("stdlib.behavior.CheckBoxSelectionBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.CheckBoxSelectionBehavior", mojo.command.Behavior, 
{
	execute: function(requestObj) {
		var params = requestObj.getParams(), els = params.element;
		if(!dojo.isArray(params.element)) {
			els = [params.element];
		}
		
		for(var i = 0, len = els.length; i < len; i++) {
			if(params.checked) {
				els[i].checked = true;
			} else {
				els[i].checked = false;
			}
		}
	}
});
dojo.provide("stdlib.behavior.ClearFormBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.ClearFormBehavior", mojo.command.Behavior, {
	execute: function(requestObj) {
		var params = requestObj.getParams();
		var formSet = requestObj.contextObj;
		var noload = false;
		var clearHidden = false;
		var clearImages = false;
		if (!params) params = {};
		if (params.noload != null) noload = params.noload;
		if (params.formSet != null) formSet = params.formSet;
		if (params.clearHidden != null) clearHidden = params.clearHidden;
		if (params.clearImages != null) clearImages = params.clearImages;

		if (!noload) {
			var inputs = mojo.query("input", formSet);
			for (var i = 0; i < inputs.length; i++) {

				switch (inputs[i].type) {
					case "hidden":
						if (clearHidden) inputs[i].value = "";
						break;

					case "image":
						if (clearImages) inputs[i].value = "";
						break;

					case "checkbox":
						if (inputs[i].checked) inputs[i].checked = false;
						break;

					case "radio":
						if (inputs[i].checked) inputs[i].checked = false;
						break;

					case "button":
						break;

					case "submit":
						break;

					default:
						// file and text
						inputs[i].value = "";
				}

			}
			var textareas = mojo.query("textarea", formSet);
			for (var i = 0; i < textareas.length; i++) {
				textareas[i].value = "";
			}
			var selects = mojo.query("select", formSet);
			for (var i = 0; i < selects.length; i++) {
				selects[i].selectedIndex = 0;
			}
		}
	}
});

/* 
	Class: stdlib.behavior.DisableBoxBehavior
	Author: Jaime Bueza
	
	Provides functionality to disable parts of the UI or the whole UI
	with a loading screen. Developers may specifiy the throbber className
	if they wish, but by default the generated throbber className will be
	"throbber". To define its presentation, do the following:
	
	Example:
		(start code)

		#disablebox {
			background: transparent  url("../../img/global/bg-loading-throbber.png") center center no-repeat;
			_background: transparent  url("../../img/global/bg-loading-throbber.gif") center center no-repeat; 
			_background: none;
			text-align: center;
		}
		#disablebox .throbber {
			position: absolute;
			background: url("../../img/global/icon-loading-throbber.gif");
			width: 16px;
			height: 16px;
		}
		
		(end)
	
	Parameters:
		target - {HTMLElement} The target element you wish to disable
		show - {Boolean} Shows the disablebox on/off
		throbberClass - {String} The specific className of the throbber.
		
		
		
		
		
*/
dojo.provide("stdlib.behavior.DisableBoxBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.DisableBoxBehavior", mojo.command.Behavior,
{
	_box: null,
	execute: function(requestObj) {
		var params = requestObj.getParams();
		if (!this._box) {
			this._box = mojo.queryFirst("#disablebox");
			if (!this._box) { //recovery + creation
				this._box = document.createElement("div");
				this._box.id = "disablebox";
				document.body.appendChild(this._box);
				this._box.style.position = "absolute";
			}
		}
		
		//Clean up
		this._box.innerHTML = "";

		if (requestObj.getParams().show) {
			var throbber = document.createElement("div");
			throbber.className = params.throbberClass || "throbber";
		
			if (requestObj.getParams().target) {
				var offset = dojo.coords(requestObj.getParams().target, true);
				this._box.style.top = offset.y + "px";
				this._box.style.left = offset.x + "px";
				this._box.style.width = offset.w + "px";
				this._box.style.height = offset.h + "px";
				
				//Shift up and left 8 px since the loader gif is 16x16. --- RBA only 24x24, so
				//we need to swap em for -12 instead of -8 -- TODO: FIX THIS FOR PARAMETER INSTEAD
				throbber.style.left = ((offset.w / 2) - 16) + "px";
				throbber.style.top = ((offset.h / 2)  - 16) + "px";
	
				this._box.appendChild(throbber);
				
				
			} else {
				var offset = {h:0,w:0};
				this._box.style.top = "0px";
				this._box.style.left = "0px";
				this._box.style.width = "100%";
				this._box.style.height = (document.all) ? document.body.offsetHeight + "px" : "100%";
				
				throbber.style.left = ((offset.w / 2) - 16) + "px";
				throbber.style.top = ((offset.h / 2)  - 16) + "px";
				
				this._box.appendChild(throbber);
			}
			this._box.style.zIndex = "9999";
			this._box.style.display = "block";
		} else {
			this._box.style.display = "none";
		}
	}
});
/* 
	Class: DragBehavior
*/
dojo.provide("stdlib.behavior.DragBehavior");
dojo.require("mojo.command.Behavior");
dojo.declare("stdlib.behavior.DragBehavior", mojo.command.Behavior, 
{
	selectedIndex: 0,
	execute: function(requestObj) {
		var params = requestObj.getParams();
		var evt = requestObj.eventObj,
			el = params.element,
			elCoords = dojo.coords(el),
			draggable = params.draggable,
			container = params.container,
			containerCoords = dojo.coords(container),
			orientation = params.orientation,
			tickSize = params.tickSize,
			direction, 
			dimension,
			prop,
			position;	
			
		if (orientation == "vertical") {
			direction = "y";
			dimension = "h";
			prop = "top";
			if(typeof params.position != "undefined" && !isNaN(parseInt(params.position))) { //Are we specifically setting the position via onInit
				position = params.position + containerCoords[direction];;
			} else {
				position = evt.clientY;
			}


		} else {
			direction = "x";
			dimension = "w";
			prop = "left";
			//Horizontal
			if(typeof params.position != "undefined" && !isNaN(parseInt(params.position))) { //Are we specifically setting the position via onInit
				position = params.position + containerCoords[direction];;
			} else {
	 			position = evt.clientX;
			}
		}
		
		var maxDimension = containerCoords[direction] + containerCoords[dimension] - elCoords[dimension];

		if(position >= maxDimension) { 
			el.style[prop] = (containerCoords[dimension] - elCoords[dimension] - 3) + "px"; //Offset of 3 pixels

		} else if (position <= containerCoords[direction] + 1){
			el.style[prop] = 0 + "px";
			
		} else {
			if(tickSize) {
				var relativePosition = (position - containerCoords[direction]);
				this.selectedIndex = Math.round(relativePosition / tickSize);
				el.style[prop] = this.selectedIndex * tickSize + "px";
			} else {
				el.style[prop] = (position - containerCoords[direction]) + "px";
			}
			
		}
	}
	
});
dojo.provide("stdlib.behavior.EnterKeyBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.EnterKeyBehavior", mojo.command.Behavior,
{
	execute: function(requestObj) {
		var e = requestObj.eventObj;
		var characterCode;
		if(e && e.which){
			e = e
			characterCode = e.which;
		} else{
			e = event
			characterCode = e.keyCode;
		}
		if(characterCode == 13){
			this.onResponse();
			return false 
		} else{
			return true 
		}
	},
	onResponse: function() {
	}
});
/* 
	Class: stdlib.behavior.IEPngFixBehavior
	Author: Jaime Bueza
	
	Uses a vml-based ie png fix solution by Drew Diller (http://www.dillerdesign.com/experiment/DD_belatedPNG/).
	This approach uses javascript but uses VML (10x faster) instead of a filter. In order to use this,
	pass a selector or a set of selectors into the behavior. 
	
	Below is a list of gotchas for using this solution:
	- cannot use 'body' as a selector
	- does not play well with <tr>, <td>
	
*/
dojo.provide("stdlib.behavior.IEPngFixBehavior");
dojo.require("mojo.command.Behavior");
dojo.declare("stdlib.behavior.IEPngFixBehavior", mojo.command.Behavior,
{
	execute: function(requestObj) {
		//Parameters:
		//	- selector (String) - CSS Selector of elements you wish to have the fix applied to.
		
		var selectors = requestObj.getParams().selector;
		if(!selectors) {
			throw new Error("stdlib.behavior.IEPngFixBehavior - parameter 'selector' cannot be empty.");
			return false;
		}
		
		
		//Check IE6.
		if(dojo.isIE == 6) DD_belatedPNG.fix(selectors);
	
	}
});
dojo.provide("stdlib.behavior.InsertHtmlBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.InsertHtmlBehavior", mojo.command.Behavior,
{
	execute: function(requestObj) {

		// element - DOM element to apply CSS action to
		// action - action to perform [before|after|append|prepend|replace|empty|replace-innerHTML]
		// insertHtml - HTML string insert

		var elms = requestObj.getParams().element;
		var action = requestObj.getParams().action;
		var insertHtml = requestObj.getParams().insertHtml;

		if (elms && action) {
			if (!dojo.isArray(elms)) elms = [elms];
			
			elmsLength = elms.length;
			for (var i = 0; i < elmsLength; i++) {
				elm = elms[i];
				isIE = elm["insertAdjacentHTML"];
				var insertElement = insertHtml;
				if (!isIE && typeof insertHtml == "string") {
					if (insertHtml.length == 0) {
						action = "empty";
					} else {
						var range = elm.ownerDocument.createRange();
						range.setStartBefore(elm);
						insertElement = range.createContextualFragment(insertHtml);
					}
				}
				
				if (action.length > 0) {
					switch (action) {
						case "empty":
							elm.innerHTML = "";
							break;
						case "before":
							if (isIE) {
								elm.insertAdjacentHTML("beforeBegin", insertHtml);
							} else {
								elm.parentNode.insertBefore(insertElement, elm);
							}
							break;
						case "after":
							if (isIE) {
								elm.insertAdjacentHTML("afterEnd", insertHtml);
							} else {
								if (elm.nextSibling) {
									elm.parentNode.insertBefore(insertElement, elm.nextSibling);
								} else {
									elm.parentNode.appendChild(insertElement);
								}
							}
							break;
						case "prepend":
							if (isIE) {
								elm.insertAdjacentHTML("afterBegin", insertHtml);
							} else {
								elm.insertBefore(insertElement, elm.firstChild);
							}
							break;
						case "append":
							if (isIE) {
								elm.insertAdjacentHTML("beforeEnd", insertHtml);
							} else {
								elm.appendChild(insertElement);
							}
							break;
						case "replace":
							if (isIE) {
								elm.innerHTML = insertHtml;
							} else {
								elm.innerHTML = "";
								elm.appendChild(insertElement);
							}
							break; 
					}
				}
			}
		}		
	}
});
dojo.provide("stdlib.behavior.MessagingBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.MessagingBehavior", mojo.command.Behavior, 
{
	execute: function(requestObj) {
		mojo.Messaging.publish(requestObj.paramsObj.topic, requestObj.paramsObj.message);
	}
});
dojo.provide("stdlib.behavior.PopulateDateBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.PopulateDateBehavior", mojo.command.Behavior, 
{
	months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
	
	execute: function(requestObj) {
		var params = requestObj.getParams(), //Request Object's parameters.
			chosenMonth = params.month, //Specified Month from Controller.
			chosenYear = params.year,	//Specified Year from Controller.
			minYear = 1920, 			//Minimum value of the Year range.
			maxYear = params.year + 50;	//Maximum value of the Year range.

		var selectYear 	= mojo.queryFirst("select.date-year", params.target);
		var selectMonth = mojo.queryFirst("select.date-month", params.target);

		//Blow away all markup.
		selectYear.innerHTML = ""; 
		selectMonth.innerHTML = "";

		//Generate Years
		for(var i = minYear; i < maxYear; i++) {
			var option = new Option(i.toString(), i);
			if(i == chosenYear) option.selected = true;
			selectYear.options.add(option);
		}

		//Generate months
		for(var i = 0, len = this.months.length; i < len; i++) {
			var monthName = this.months[i]
			var monthValue = (i <= 8) ? "0" + (i + 1) : i + 1;
			var option = new Option(monthName, monthValue);
			if(i == chosenMonth) option.selected = true;
			selectMonth.options.add(option);
		}
	}
});
dojo.provide("stdlib.behavior.PopulateDaysBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.PopulateDaysBehavior", mojo.command.Behavior, 
{
	daysInMonth: function(iMonth, iYear) {
		return (new Date(iYear, iMonth, 0)).getDate();
	},
	execute: function(requestObj) {
		//target
		//default day || if null, then today will be selected
		//month
		//year

		var params = requestObj.getParams();
		if(!params.day) {
			params.day = (new Date()).getDate();
		}
		var selectDays 	= params.target;
		selectDays.innerHTML = "";
		var daysInMonth = this.daysInMonth(params.month, params.year);
		for(var i = 1; i <= daysInMonth; i++) {
			var dayValue = (i <= 9) ? "0" + (i) : i;

			var option = new Option(i, dayValue);
			if(i == params.day) option.selected = true;
			selectDays.options.add(option);
		}
	}
});
/* 
	Class: stdlib.behavior.PreventDefaultEventBehavior
	Author: Steven Luscher, Chad Oakenfold
	
	Attempts to stop the default event
*/
dojo.provide("stdlib.behavior.PreventDefaultEventBehavior");
dojo.require("mojo.command.Command");
dojo.declare("stdlib.behavior.PreventDefaultEventBehavior", mojo.command.Command, 
{
	execute: function(requestObj) {
	  /* Cancel the default event if possible */
    try {	
	 		var e = requestObj.eventObj;
			if (e["preventDefault"]) e.preventDefault();
			if (e["stopPropagation"]) e.stopPropagation();
			e.returnValue = false;
			return false;	  
		} catch(e) {}
  }
});
dojo.provide("stdlib.behavior.RedirectBehavior");
dojo.require("mojo.command.Behavior");
dojo.declare("stdlib.behavior.RedirectBehavior", mojo.command.Behavior,
{
	execute: function(requestObj) {
		//If you pass don't pass a URL, it can be assumed
		//that you intend to refresh the current page.
		var params 		= requestObj.getParams();
		var delay 		= 25;
		if (params) {
			var url 	= params.url; //Location of the redirect
			var removeHash 	= params.removeHash || false; //If removeHash doesn't exist, then it's false.
			var delay 	= params.delay || 25;	//25ms redirect delay by default
		}
		if(!url) {
			//We want to refresh the page.
			if (removeHash) {
				window.location = window.location.href.replace(/#.*/, "");
				setTimeout ("window.location.reload()", 750); //Safari hack to reload
			} else {
				window.location.reload();
			}
		} else {
			//We want to redirect the user to a specific URL.
			setTimeout(function() {
				window.location.href = url;
			}, delay);

		}
	}
});
dojo.provide("stdlib.behavior.RemoveElementsBehavior");

dojo.declare("stdlib.behavior.RemoveElementsBehavior", mojo.command.Behavior, {
	execute: function(requestObj) {

		var __className; // must be a string. cannot be an array of strings.
		var __targetId;  // must be a string. cannot be an array of strings.
		var __target;
		var __elements;
		var params = requestObj.paramsObj;
		if (params) {
			if (params.className != null ) __className = params.className;
			if (params.targetId != null ) __targetId = params.targetId;
			if (params.target != null) __target = params.target;
		}

		// Execution
		if ((__className != null) && (__targetId != null || __target != null)) {
			if (__targetId && !__target) {
				if (__targetId.indexOf("#") != 0) __targetId = "#" + __targetId;
				__target = mojo.queryFirst(__targetId);
			}
			__elements = mojo.query(__className, __target);
			if (__elements) {
				if (__elements.length > 0) {
					for (var i=0; i < __elements.length; i++) {
						if ((__elements[i])&&(__elements[i].parentNode)) __elements[i].parentNode.removeChild(__elements[i]);
					}
				} else {
					if ((__elements)&&(__elements.parentNode)) __elements.parentNode.removeChild(__elements);
				}
			}
		}
	}
});
dojo.provide("stdlib.behavior.SetHistoryBehavior");
dojo.require("mojo.command.Behavior");
dojo.require("mojo.History");

dojo.declare("stdlib.behavior.SetHistoryBehavior", mojo.command.Behavior,
{
	execute: function(requestObj) {
		if (requestObj.getParams()) {
			var clearHash; // if clearHash is true, everything after the hash is cleared
			var historyObj = mojo.History.getInstance();
			var params = requestObj.getParams();
			if (params) {
				if (typeof params.clearHash != "undefined") {
					if (params.clearHash) window.location.hash = "#";
				} else {
					var hash = historyObj._parseObj(params);
					mojo.History.getInstance().setHash(hash);
				}
			}
		}
	}
});
dojo.provide("stdlib.behavior.SubmitFormBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.SubmitFormBehavior", mojo.command.Behavior,
{
	execute: function(requestObj) {
		var params = requestObj.getParams();
		if (params && params.form) {
			if (params.form.tagName.toLowerCase() != "form") {
				params.form = mojo.queryFirst("form", params.form);
			}
			params.form.submit();
		}
	}
});
/* 	
	Class: stdlib.behavior.SwfObjectBehavior
	Author: Jaime Bueza
	
	Provides an application with the ability to integrate flash objects with swfobject 1.5.
		
	Notes:
		- Requires swfobject 1.5
		
	Implementation:
		HTML Markup:
		
		(start code)
			<div class="flash-component">
				<div id="flash-content">
					<h1>You need flash to view this site.</h1>
				</div> <!-- flash-content -->
			</div> <!-- flash-component -->
		(end)
		
		Controller addObservers() method:
		
		(start code)
		this.addObserver(this, "onInit", "InitSwfObject", function(context, caller) { 
			return {
				elementId: "flash-content", 
				contentName: "main_flash",
				containerId: "#flash-content", 
				src: "/flash/residential/internet/018.swf", 
				width: "779", 
				height: "312", 
				version: "9", 
				defaultBackground: "#FFFFFF", 
				expressInstallSrc: "/flash/expressinstall.swf",
				params: {} 
			} 
		});*
		(end)
*/
dojo.provide("stdlib.behavior.SwfObjectBehavior");
dojo.require("mojo.command.Behavior");
dojo.declare("stdlib.behavior.SwfObjectBehavior", mojo.command.Behavior, 
{
	/* 
		Function: execute
		
		Renders the flash object on to the UI.
		
		Parameters:
			{Object} requestObj 
			
		Request Object Parameters:
			{String} elementId 		- SWFObject writes an element to the page with this ID
			{String} src 			- Location of the flash object
			{String} containerId 	- 
			{Number} width			- width of the flash object, usually set by CSS, but swfobject also adds the width attribute.
			{Number} height			- Height of the flash object, usually set by CSS, but swfobect also adds the height attribute.
			
	*/
	execute: function(requestObj) {
		var params = requestObj.getParams();
		
		//We check to see if the SWFObject library has been loaded.
		if(!deconcept.SWFObject) {
			throw new Error("ERROR stdlib.behavior.SwfObjectBehavior.execute - SWFObject library cannot be found");
		}
		
		if(!params.elementId) {
			throw new Error("ERROR stdlib.behavior.SwfObjectBehavior.execute - elementId is not set");
		}
		if(!params.src) {
			throw new Error("ERROR stdlib.behavior.SwfObjectBehavior.execute - src is not set");
		}
		if(!params.containerId) {
			throw new Error("ERROR stdlib.behavior.SwfObjectBehavior.execute - containerId is not set");
		}
		
		if(!params.width || !params.height) {
			throw new Error("ERROR stdlib.behavior.SwfObjectBehavior.execute - width and/or height is not set");
		}

		if(!params.contentName) {
			params.contentName = "flash_module";
		}
		if(!params.version) {
			params.version = 9;
		}
		if(!params.defaultBackground) {
			params.defaultBackground = "#fff";
		}
		if(!params.wmode) {
			params.wmode = "window";
		}
		
		var so = new SWFObject(params.src, params.contentName, params.width, params.height, params.version, params.defaultBackground);	
		
		// The width must be > 214px and the height must be > 137px in order for Express Install to work.
		if (params.expressInstallSrc) { 
			so.useExpressInstall(params.expressInstallSrc);
		}
		so.addParam("base", params.basePath);
		so.addParam("wmode", params.wmode);
		so.addParam("allowFullScreen", params.allowFullScreen);
		so.addParam("allowScriptAccess", params.allowScriptAccess);
		so.addParam('flashvars',params.flashvars);
		so.write(params.elementId);
	}
});
dojo.provide("stdlib.behavior.TweenBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.TweenBehavior", mojo.command.Behavior,
{
	onComplete:function() {},
	onStart:function() {},
	_effect: null,
	execute: function(requestObj) {
		// element
		// width, height, x, y

		// set properties of animation
		var props = {};
		var duration;
		if (requestObj.getParams().width != null) props.width = requestObj.getParams().width;
		if (requestObj.getParams().height != null) props.height = requestObj.getParams().height;
		if (dojo.isIE && props.height == 0) props.height = 1;
		if (requestObj.getParams().x != null) props.left = requestObj.getParams().x;
		if (requestObj.getParams().y != null) props.top = requestObj.getParams().y;
		
		if (requestObj.getParams().duration != null) {
			duration =  requestObj.getParams().duration;
		} else {
			duration = 600;
		}
		
		// normalize elements into array
		var elements = requestObj.getParams().element;
		if (!dojo.isArray(elements)) {
			elements = [elements];
		}
		var elementLength = elements.length;

		var thisObj = this;
		
		for (var i = 0; i < elementLength; i++) {
			if (elements[i]) {
				if (elements[i].style.height == "auto" && props.height != null) {
					elements[i].style.height = dojo.coords(elements[i]).h + "px";
				}
				var fx = new Fx.Styles(elements[i], {
					duration: duration,
					transition: Fx.Transitions.Expo.easeInOut,
					onStart: function() {
						thisObj.onStart();
						if (dojo.isIE && this.from.height == "1") this.element.style.display = "block";

					},
					onComplete: function() {
						if (this.to.height == "1")   this.element.style.display = "none";
						if ((this.from.height == "0")||(this.from.height == "1")) this.element.style.height = "auto";
						if (this.element.style.height == "auto" && this.to.height > 0 && dojo.coords(this.element).h == 0) this.element.style.height = this.to.height + "px";

						thisObj.onComplete();
					}
				});
				this._effect = fx;
				fx.start(props);
			}
		}
	}
});
dojo.provide("stdlib.behavior.UpdateCssClassBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.UpdateCssClassBehavior", mojo.command.Behavior,
{
	execute: function(requestObj) {

// element - DOM element to apply CSS action to
// action - action to perform [add|remove|set|toggle]
// cssClass - CSS Class to apply action to

		if (!requestObj.paramsObj) return;
		var elmLength;											// empty var which will be used to store the length of the array
		var elms = requestObj.paramsObj.element;				// gets the parameter "element" from the controller
		var action = requestObj.paramsObj.action;
		var cssClass = requestObj.paramsObj.cssClass;


		// ERROR CHECKING
		if (!elms) {
			return;
		} else {
			if (typeof elms == 'object') {
				//check array to see that all items are objects
				if (dojo.isArray(elms) && elms.length > 0) {
					for (var i=0; i< elms.length; i++) {
						if (typeof elms[i] != 'object') {
							throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - element parameter is not an array of type Object');
							break;
						}
					}
				}
			} else {
				throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - element parameter is not a type Object');
			}
		}

		if (action == null || typeof action == 'undefined') {
			throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - action parameter is required');
		} else {
			if (typeof action != 'string') {
				throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - action parameter is not a type String');
			} else {
				if ((action != 'add') && (action != 'remove') && (action != 'set') && (action != 'toggle')) throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - action parameter is invalid');
			}
		}

		if (cssClass == null || typeof cssClass == 'undefined') {
			throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - CssClass parameter is required');
		} else {
			if (typeof cssClass == 'object') {
				//check array to see that all items are objects
				if (cssClass.length > 0) {
					for (var i=0; i< cssClass.length; i++) {
						if (typeof cssClass[i] != 'string') {
							throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - CssClass parameter is not an array of type String');
							break;
						}
					}
				}
			} else {
				if (typeof cssClass != 'string') throw new Error('ERROR stdlib.behavior.UpdateCssClassBehavior - CssClass parameter is not a type String');
			}
		}



// checks to see that an element has been passed
		if (elms) {

// helper function. checks to see if the elms variable is an array.
			var isArray = function(srcObj) {
				if (!srcObj.constructor || srcObj.constructor.toString().toLowerCase().indexOf("array") == -1) return false;
				return true;
			};


// if elms is not an array, make it an array
			if (!isArray(elms)) elms = [elms];

// if cssClass is not an array, make it an array
			if (!isArray(cssClass)) cssClass = [cssClass];

// gets the length of the cssClass array for performance issues
			cssLength = cssClass.length;

// gets the length of the elms array for performance issues
			elmLength = elms.length;

// loops through the elements
			for (var i = 0; i < elmLength; i++) {
				elm = elms[i];
				// loops through the css classes
				for (var j = 0; j < cssLength; j++) {
					css = cssClass[j];
					// perform the CSS action
					if (action.length > 0){
						// just a nicer way of doing an If/Else
						switch(action) {
							case "add" :
								dojo.addClass(elm, css);
								break;
							case "remove" :
								dojo.removeClass(elm, css);
								break;
							case "set" :
								elm.className = "";
								dojo.addClass(elm, css);
								break;
							case "toggle" :
								dojo.toggleClass(elm, css);
								break;
						}
					}
				}
			}
		}
	},
	onResponse: function() {
	}
});
dojo.provide("stdlib.behavior.UpdateFormFieldBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.UpdateFormFieldBehavior", mojo.command.Behavior, {
	execute: function(requestObj) {
		// this behavior will iterate thru a targeted form and assign "values" to
		// the appropriate form elements based on the element's "name"
		var formObj;
		var formChildren = new Array();
		var formArray = new Array();
		var formHTMLElements = ["INPUT", "SELECT", "TEXTAREA"]; // these are the valid form elements
		var params = requestObj.getParams();
		if (!params) params = {};
		var fields = params.fields; // 'fields' is an array of json objects that represent form input fields
		if (params.formId != null) formObj = mojo.queryFirst("#" + params.formId);
		if (params.formObj != null) formObj = params.formObj;

		if (formObj) {
			// getting the appropriate objects in the form
			for (var i = 0, iLen = formHTMLElements.length; i < iLen; i++) {
				var HTMLobj = mojo.query(formHTMLElements[i], formObj);

				for (var j = 0, jLen = HTMLobj.length; j < jLen; j++) {
					formChildren.push(HTMLobj[j]);
				}
			}

			// check fields and assign values
			for (var i = 0, iLen = fields.length; i < iLen; i++) {
				var objName = fields[i].name;
				var objValue = fields[i].value;
				for (var j = 0, jLen = formChildren.length; j < jLen; j++) {
					var fireOnChange = false;
				
					// fire onchange if values are different
//					if ((formChildren[j].tagName == "INPUT")&&(formChildren[j].value != objValue)) {
//						fireOnChange = true;
//					}

					if (formChildren[j].tagName == "SELECT") {
						if (formChildren[j].name == objName) {
							for (var k = 0, kLen = formChildren[j].options.length; k < kLen; k++) {
								var o = formChildren[j].options[k];
								if (o.value == objValue) formChildren[j].selectedIndex = k;
							}
						}
					} else if (formChildren[j].tagName == "TEXTAREA") {
						if (formChildren[j].name == objName) {
							if (formChildren[j].value == objValue) fireOnChange = true; //PC FF needs this
							if (formChildren[j].innerHTML == objValue) fireOnChange = true;
							formChildren[j].value = objValue; // PC FF needs this
							formChildren[j].innerHTML = objValue;
						}
					} else if (formChildren[j].tagName == "INPUT") {
						if (formChildren[j].name == objName) {
							if ((formChildren[j].type == "radio")||(formChildren[j].type == "checkbox")) {
								if (formChildren[j].value == objValue) {
									formChildren[j].checked = "checked";
								} else {
									formChildren[j].checked = "";
								}
							} else if ((formChildren[j].type == "text")||(formChildren[j].type == "password")||(formChildren[j].type == "hidden")) {
								if (formChildren[j].value != objValue) fireOnChange = true;
								formChildren[j].value = objValue;
							}
						}
					}

					if (fireOnChange) {
						//On IE
						if (formChildren[j].fireEvent) formChildren[j].fireEvent("onchange");

						//On Gecko based browsers
						if (document.createEvent) {
							var evt = document.createEvent("HTMLEvents");
							if(evt.initEvent) evt.initEvent("change", true, true);
							if(formChildren[j].dispatchEvent) formChildren[j].dispatchEvent(evt);
						}
					}

				}
			}


		}
	}
});
dojo.provide("stdlib.behavior.dialog.DialogBehavior");
dojo.require("mojo.command.Behavior");
dojo.declare("stdlib.behavior.dialog.DialogBehavior", mojo.command.Behavior, 
{
	onComplete: function() {},
	execute: function(requestObj) {
		//You may choose to pass in an ID or an HREF, if you pass in an
		//HREF, the dialog will fetch the content via xhr, else it grabs
		//the element's inner HTML of the specific ID, and shoves it into
		//the div.dialog's innerHTML.
		
		//Parameters
		// enabled: Boolean
		// width: Number
		// height: Number
		// href: (optional) String
		// id: (optional) String
		
		///TODO
		// add an icon param that loads the associated img src into ".dialog-component .dialog-component-title-icon" ?
		var params = requestObj.getParams();
			
		if(!params.elContainer) {
			params.elContainer = ".dialog-component";
		}
		
		if(!params.elContent) {
			params.elContent = ".dialog-component-content";
		}
		
		if(!params.elTitle) {
			params.elTitle = ".dialog-component-title";
		}
		if(!params.title) {
			params.title = "Default Dialog Text";
		}
		
		var flashElements = mojo.query("embed, object");
		
		//Find the Underlay
		var underlay = mojo.queryFirst("#underlay");
		
		if(!underlay) {
			underlay = document.createElement("div");
			underlay.id = "underlay";
			underlay.style.display = "block";
			document.body.appendChild(underlay);
		}
		
		var container = mojo.queryFirst(params.elContainer);
		if(!container) {
			
			//@Jaime Bueza: Forget the recovery, if the 
			//developer forgets to add the basic template markup
			//for the dialog, then he should be warned. So, let's warn 
			//him.
			
			
			throw new Error("stdlib.behavior.dialog.DialogBehavior - Unable to find the Dialog template");
			return;
		}

		var content = mojo.queryFirst(params.elContent, params.elContainer);
		var title = mojo.queryFirst(params.elTitle, params.elContainer);
		
		var thisObj = this;
		
		if (params.enabled && params.width && params.height) {
			title.innerHTML = params.title;
	
			if(!params.id) {
				dojo.xhrGet({
					url: params.href,
					load: function(data) {
						mojo.Model.set('mojo.dialog.content', data);
						thisObj.onComplete();
					}
				});
			} else {
				var contentOnPage = mojo.queryFirst(params.id);
				mojo.Model.set('mojo.dialog.content', data);
				thisObj.onComplete();
			}
			
			if(dojo.isFF && (navigator.appVersion.indexOf("Mac")!=-1)) {
				this.hideFlash(flashElements);
			}
			
			container.style.width = params.width + "px";
			container.style.height = params.height + "px";
			
			
			underlay.style.display = 'block';
			container.style.display = 'block';
			
			
			if(dojo.isIE) {
				mojo.queryFirst("html").style.overflowX = "hidden";
			} else {
				document.body.style.overflowX = "hidden";
			}
		

		}else{
			
			if(dojo.isFF && (navigator.appVersion.indexOf("Mac")!=-1)) {
				this.showFlash(flashElements);
			}
			
			underlay.style.display = 'none';
			container.style.display = 'none';
			
			if(dojo.isIE) {
				mojo.queryFirst("html").style.overflowX = "auto";
			} else {
				document.body.style.overflowX = "auto";
			}
			
		
		}
	},
	hideFlash: function(list) {
		for(var i = 0, len = list.length; i < len; i++) {
			list[i].style.display = "none";
		}
	},
	showFlash: function(list) {
		for(var i = 0, len = list.length; i < len; i++) {
			list[i].style.display = "block";
		}
	}
});
/* 
	Class: EscapeKeyBehavior
	
	Provides functionality for intercepting the Escape (ESC) keystroke. 
	
	Note:
		Perhaps this can be deprecated and we can have a generalized "KeyBehavior" 
		in stdlib, where you pass in an array of keystrokes to intercept.
*/
dojo.provide("stdlib.behavior.dialog.EscapeKeyBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.dialog.EscapeKeyBehavior", mojo.command.Behavior,
{
	execute: function(requestObj) {
		var e = requestObj.eventObj;
		var characterCode;
		if(e && e.which){
			e = e
			characterCode = e.which;
		} else{
			e = event
			characterCode = e.keyCode;
		}
		if(characterCode == 27){
			this.onResponse();
			return false 
		} else{
			return true 
		}
	},
	onResponse: function() {
	}
});
/*
	Class: PositionBehavior
	
*/
dojo.provide("stdlib.behavior.dialog.PositionBehavior");
dojo.require("mojo.command.Behavior");
dojo.declare("stdlib.behavior.dialog.PositionBehavior", mojo.command.Behavior, 
{
	execute: function(requestObj) {

		var params = requestObj.getParams();
		var underlay = mojo.queryFirst("#underlay");
		var container = mojo.queryFirst(".dialog-component");
		var content = mojo.queryFirst(".dialog-component .dialog-component-content");
		
		if(!container || !underlay || !content) {
			return;
		}

		var windowDimensions = {};
		var scrollPosition = 0;
		// the more standards compliant browsers (mozilla/netscape/opera/IE7) use window.innerWidth and window.innerHeight
		if (typeof window.innerWidth != 'undefined') {
		    windowDimensions.w = window.innerWidth;
		    windowDimensions.h = window.innerHeight;
			scrollPosition = window.scrollY + window.innerHeight;
		}
		// IE6 in standards compliant mode (i.e. with a valid doctype as the first line in the document)
		else if (typeof document.documentElement != 'undefined' && typeof document.documentElement.clientWidth != 'undefined' && document.documentElement.clientWidth != 0) {
		    windowDimensions.w = document.documentElement.clientWidth,
		    windowDimensions.h = document.documentElement.clientHeight;
			scrollPosition = /* (dojo.coords(mojo.queryFirst("body"), true)).h */ document.documentElement.scrollTop + document.documentElement.clientHeight;
		} else {
			windowDimensions.w = document.body.clientWidth;
			windowDimensions.h = document.body.clientHeight;
			scrollPosition = document.body.scrollTop + document.body.clientHeight;
		}

		//Remodulate the underlay dimensions.
		underlay.style.width = windowDimensions.w + "px"; 
		underlay.style.height = (dojo.coords(mojo.queryFirst("body"), true)).h /* windowDimensions.h */ + "px";

		//Remodulate the Dialog container dimensions.
		var containerCoords = dojo.coords(container, true);
		var contentCoords = dojo.coords(content, true);
		
		var centerY = Math.round(scrollPosition - (windowDimensions.h / 2)  - (containerCoords.h / 2));
		var centerX = Math.round((windowDimensions.w / 2) - (containerCoords.w / 2));

		container.style.top = centerY + "px";
		container.style.left = centerX + "px";
		
	}
});
dojo.provide("stdlib.command.AutoSuggest.GetSuggestionsCommand");
dojo.require("mojo.command.Command");
dojo.require("mojo.Model");

dojo.declare("stdlib.command.AutoSuggest.GetSuggestionsCommand", mojo.command.Command, {
	query: null,
	_clearTimeout: null,
	_lastValue: null,
	execute: function(requestObj) {
		if (requestObj.getParams().query != this.query) {
			this.query = requestObj.getParams().query.replace(/\s*$/g, ""); // get rid of trailing spaces
			clearTimeout(this._clearTimeout);
			if (this.query.length > 0) { // handle empty
				var thisObj = this;
				dojo.require(requestObj.getParams().serviceLocator);
				this._clearTimeout = setTimeout(function() {
					if (thisObj._lastValue != thisObj.query) {
						thisObj._lastValue = thisObj.query;
						var locator = eval(requestObj.getParams().serviceLocator);
						locator.getInstance().getService(requestObj.getParams().serviceName).invoke({query: thisObj.query}, thisObj);
					}
				}, 400);
			} else {
				mojo.Model.remove(requestObj.getParams().model);
			}
		}	
	},
	onResponse: function(data) {
		var modelPath = (this.getRequest().getParams().modelPath) ? "." + this.getRequest().getParams().modelPath : "";
		mojo.Model.set(this.getRequest().getParams().model, eval("data" + modelPath));
	},
	onError: function(error) {
	}
});
dojo.provide("stdlib.command.ClearModelCommand");
dojo.require("mojo.Model");

dojo.declare("stdlib.command.ClearModelCommand", mojo.command.Command, {
	execute: function(requestObj) {
		var model = requestObj.paramsObj.model;

		// ERROR CHECKING
		if (model == null || typeof model == 'undefined') {
			throw new Error('ERROR stdlib.command.ClearModelCommand - model parameter is required');
		} else {
			if (typeof model == 'array' || typeof model == 'object') {
				//check array to see that all items are string
				if (model.length > 0) {
					for (var i=0; i<model.length; i++) {
						if (typeof model[i] != 'string') {
							throw new Error('ERROR stdlib.command.ClearModelCommand - model parameter is not an array of type String');
							break;
						}
					}
				}
			} else {
				if (typeof model == 'string') {
					if (model == "") throw new Error('ERROR stdlib.command.ClearModelCommand - model parameter must be a non-empty string');
				} else {
					throw new Error('ERROR stdlib.command.ClearModelCommand - model parameter is not a type String');
				}
			}
		}

		// EXECUTION
		if (model) {
			if (typeof(model) == "string") model = [model];

			if (dojo.isArray(model)) {
				for (i=0; i<model.length; i++) {
					mojo.Model.remove(model[i]);
				}
			}
		}
	}
});

/* 
	Class: stdlib.command.GenericServiceCommand
	Author: Jaime Bueza
	
	Provides a generic command that can be used against a service.
	
	Parameters:
		serviceName - {String}
		serviceLocator - {String}
		serviceParams - {Object}
		model - {String}
		
	Example:
		(start code)
			this.addObserver("a.login", "onclick", "GenericServiceCommand", function(context, caller) {
				return {
					serviceName: "LoginService",
					serviceLocator: "app.service.Locator",
					serviceParams: {
						username: mojo.queryFirst("input[name='username']", context).value,
						password: mojo.queryFirst("input[name='password']", context).value
					},
					model: "member.login"
				};
			});
		(end)
*/
dojo.provide("stdlib.command.GenericServiceCommand");
dojo.require("mojo.command.Command");
dojo.declare("stdlib.command.GenericServiceCommand", mojo.command.Command, {
	_model: null,
	execute: function(requestObj) {
		var params = requestObj.getParams();
		//Warn the developer if we're not passing any parameters to the Generic Service Command.
		if(!params) {
			console.log("stdlib.command.GenericServiceCommand - Warning - No params passed.");
		}
		
		//Set the command's model so that we can access the reference in the onResponse/onError events.
		this._model = params.model;
		//Fetch the application specific service locator.
		dojo.require(params.serviceLocator);
		//Invoke the service
		(eval(params.serviceLocator)).getInstance().getService(params.serviceName).invoke(params.serviceParams, this);
	},
	onResponse: function(data) {
		if(this._model) mojo.Model.set(this._model, data); //If we have a model to set, then we can set it here.
	},
	onError: function(errors) {
		if(this._model) mojo.Model.set(this._model + ".errors", errors);
	}
});
dojo.provide("stdlib.command.InsertIntoModelCommand");
dojo.require("mojo.command.Command");
dojo.require("mojo.Model");

dojo.declare("stdlib.command.InsertIntoModelCommand", mojo.command.Command, {
	execute: function(requestObj) {
		//parameters {model:String, index:Number, value:Object}
		var __model;
		var __index;
		var __value;
		var __modelContents;
		var __error = false;
		var params = requestObj.getParams();
		if (!params) params = {};
		if (params.model != null) __model = params.model;
		if (params.index != null) __index = params.index;
		if (params.value != null) __value = params.value;


		// ERROR CHECKING
		if (__model == null || typeof __model == 'undefined') {
			throw new Error('ERROR stdlib.command.InsertIntoModelCommand - model parameter is required');
		} else {
			if (__model == '') throw new Error('ERROR stdlib.command.InsertIntoModelCommand - model parameter must be a non-empty string');
			if (typeof __model != 'string') {
				throw new Error('ERROR stdlib.command.InsertIntoModelCommand - model parameter must be type String');
			} else {
				if (!mojo.Model.contains(__model)) {
					throw new Error('ERROR stdlib.command.InsertIntoModelCommand - specified model does not exist');
				} else {
					__modelContents = mojo.Model.get(__model).length;
					if (typeof __modelContents != 'number') throw new Error('ERROR stdlib.command.InsertIntoModelCommand - specified model must be type Array');
				}
			}
		}

		if (__value == null || typeof __value == 'undefined') throw new Error('ERROR stdlib.command.InsertIntoModelCommand - value is not set');

		if (__index != null) {
			if (typeof __index != 'number') {
				throw new Error('ERROR stdlib.command.InsertIntoModelCommand - index parameter must be type Number');
			} else {
//				if (__index < 0) throw new Error('ERROR stdlib.command.InsertIntoModelCommand - index parameter cannot be less than zero');
			}
		}


		// ASSIGN ORDER
		var targetModel = mojo.Model.get(__model);
		if (targetModel.length != 0) {
			if (typeof __index == "undefined" || __index < 0 || __index >= targetModel.length) {
				var targetIndex = targetModel.length;
			} else {
				var targetIndex = __index;
			} 
		} else {
			var targetIndex = 0;
		}


		// RE-ORDER ARRAY
		if (targetModel.length == 0) {
			mojo.Model.add(__model, __value);
		} else {
			if (targetIndex == targetModel.length - 1) {
				mojo.Model.add(__model, __value);
			} else {
				targetModel.splice(targetIndex,0, __value);
				mojo.Model.set(__model, targetModel);
			}
		}


	},
	onResponse: function(data) {
	},

	onError: function(error) {
	}
});
dojo.provide("stdlib.command.MapControllersCommand");
dojo.require("mojo.command.Command");

dojo.declare("stdlib.command.MapControllersCommand", mojo.command.Command, {
	execute: function(requestObj) {
		
		var contextObj = null;
		if(requestObj.getParams()) {
			
			// parameters: contextObj: String or HTMLElement
			contextObj = requestObj.getParams().contextObj;
		}
		
		mojo.controller.Map.mapControllers(contextObj);
		

		
	}
});
dojo.provide("stdlib.command.PaginationCommand");
dojo.require("mojo.command.Command");


// passing in pageSize, total, and pageIndex

dojo.declare("stdlib.command.PaginationCommand", mojo.command.Command, 
{

    model: "paginationState",
	execute: function(requestObj) {
	    if (requestObj.getParams().model != null){
			this.model = requestObj.getParams().model;
		}
	    mojo.Model.remove(this.model);
		if (typeof requestObj.getParams().pageSize != "undefined" && typeof requestObj.getParams().total != "undefined") {
			if (requestObj.getParams().pageSize <= 0 || requestObj.getParams().total <= 0) {
				// reset all properties
				mojo.Model.set(this.model, {
					pageIndex: 0,
					pageSize: 0,
					total: 0,
					from: 0,
					to: 0,
					pageNext: -1,
					pagePrev: -1,
					pageTotal: 0,
					pages: []
				});
			} else {
				var pageState = {};
				pageState.pageSize = requestObj.getParams().pageSize;
				pageState.total = requestObj.getParams().total;
				pageState.pageIndex = 0;
				if (requestObj.getParams().pageIndex && requestObj.getParams().pageIndex > 0) {
					pageState.pageIndex = parseInt(requestObj.getParams().pageIndex);
				}
				pageState.pageTotal = Math.ceil(pageState.total / pageState.pageSize);
				if (pageState.pageIndex > pageState.pageTotal) {
					return;
				}
				pageState.from = (pageState.pageSize * pageState.pageIndex) + 1;
				pageState.to = pageState.pageSize * (pageState.pageIndex + 1);
				if (pageState.to > pageState.total) {
					pageState.to = pageState.total;
				}
				pageState.pageNext = ((pageState.pageIndex + 1) >= pageState.pageTotal) ? -1 : (pageState.pageIndex + 1);
				pageState.pagePrev = (pageState.pageIndex == 0) ? -1 : (pageState.pageIndex - 1);
				pageState.showPages = 8;
				if (requestObj.getParams().showPages && requestObj.getParams().showPages > 0) {
					pageState.showPages = requestObj.getParams().showPages;
				}
				var shift = Math.ceil(pageState.showPages/2);
				var start = 0;
				if ((pageState.pageIndex - shift) > 0) {
					start = pageState.pageIndex - shift;
					if (start > 0 && (pageState.pageTotal - pageState.pageIndex) < shift) {
						start = start - (shift - (pageState.pageTotal - pageState.pageIndex));
						if (start <= 0) {
							start = 0;
						}
					}
				}
				pageState.pages = [];
				for (var i = start; i < (start+pageState.showPages); i++) {
					if (i < pageState.pageTotal) {
						pageState.pages.push(i+1);
					}
				}
				mojo.Model.set(this.model, pageState);
			}
		}
	}
});
dojo.provide("stdlib.command.RemoveFromModelCommand");
dojo.require("mojo.command.Command");
dojo.require("mojo.Model");

dojo.declare("stdlib.command.RemoveFromModelCommand", mojo.command.Command, 
{
	execute: function(requestObj) {
		//parameters {model:String, index:Number, key:String, value:Object, firstOnly:Boolean}
		var __model;
		var __index;
		var __key;
		var __value;
		var __first = true;
		var __modelContents;
		var __error = false;
		var spliced = false;
		var params = requestObj.getParams();
		if (!params) params = {};
		if (params.model != null) __model = params.model;
		if (params.index != null) __index = params.index;
		if (params.value != null) __value = params.value;
		if (params.key != null)   __key   = params.key;
		if (params.firstOnly != null) __first = params.firstOnly;


		// ERROR CHECKING
		if (__model == null || typeof __model == 'undefined') {
			throw new Error('ERROR stdlib.command.RemoveFromModelCommand - model parameter is required');
		} else {
			if (__model == '') {
				throw new Error('ERROR stdlib.command.RemoveFromModelCommand - model parameter must be a non-empty string');
			} else {
				if (typeof __model != 'string') {
					throw new Error('ERROR stdlib.command.RemoveFromModelCommand - model parameter must be type String');
				} else {
					if (!mojo.Model.contains(__model)) {
						throw new Error('ERROR stdlib.command.RemoveFromModelCommand - specified model does not exist');
					} else {
						__modelContents = mojo.Model.get(__model).length;
						if (typeof __modelContents != 'number') throw new Error('ERROR stdlib.command.RemoveFromModelCommand - specified model must be type Array');
					}
				}
			}
		}

		if (__index == null || typeof __index == 'undefined') {
			if ((__key == null || typeof __key != 'string' || __key == '')||(__value == null || typeof __value == 'undefined' || __value == '')) {
				if (__key == null || typeof __key == 'undefined') {
					throw new Error('ERROR stdlib.command.RemoveFromModelCommand - either [index] parameter or [key and value] parameters are required');
				} else {
					if (__key == '') {
						throw new Error('ERROR stdlib.command.RemoveFromModelCommand - key parameter must be a non-empty string');
					} else {
						if (typeof __key != 'string') {
							throw new Error('ERROR stdlib.command.RemoveFromModelCommand - key parameter must be type String');
						} else {
							if (__value == null || typeof __value == 'undefined') throw new Error('ERROR stdlib.command.RemoveFromModelCommand - either [index] parameter or [key and value] parameters are required');
						}
					}
				}
			}
		} else {
			if ((__key != null) && (typeof __key != 'undefined') && (__key == '')) throw new Error('ERROR stdlib.command.RemoveFromModelCommand - key parameter must be a non-empty string');
			if (typeof __index != 'number') {
				throw new Error('ERROR stdlib.command.RemoveFromModelCommand - index parameter must be type Number');
			} else {
				if (__index < 0) {
					throw new Error('ERROR stdlib.command.RemoveFromModelCommand - index parameter cannot be less than zero');
				} else {
					if (mojo.Model.contains(__model)) {
						if (__index >= mojo.Model.get(__model).length) throw new Error('ERROR stdlib.command.RemoveFromModelCommand - index parameter is out of bounds');
					}
				}
			}
		}


		// RE-ORDER ARRAY
		//assume model, key, value and index is correct
		var targetModel = mojo.Model.get(__model);
		if ((__key != null) && (typeof __key != 'undefined') && (__key != '') && (__value != null) && (typeof __value != 'undefined') && (__value != '')) {
			if (__first) {
				//search for the first key/value combo and then delete
				for (i=0; i<targetModel.length; i++) {
					if (typeof targetModel[i][__key] != 'undefined') {
						if (targetModel[i][__key] == __value) {
							targetModel.splice(i,1);
							mojo.Model.set(__model, targetModel);
							break;
						}
					}
				}
			} else {
				//search and delete all key/value combinations
				for (i=targetModel.length-1; i>=0; i--) {
					if (typeof targetModel[i][__key] != 'undefined') {
						if (targetModel[i][__key] == __value) {
							targetModel.splice(i,1);
							spliced = true;
						}
					}
				}
				if (spliced) mojo.Model.set(__model, targetModel);
			}
		} else {
			if ((__index != null) && (typeof __index != 'undefined') && (typeof __index == 'number')) {
				//remove targeted index
				targetModel.splice(__index,1);
				mojo.Model.set(__model, targetModel);
			}
		}


	},
	onResponse: function(data) {
	},

	onError: function(error) {
	}
});
dojo.provide("stdlib.command.SetModelCommand");
dojo.require("mojo.command.Command");
dojo.require("mojo.Model");

dojo.declare("stdlib.command.SetModelCommand", mojo.command.Command, {
	execute: function(requestObj) {
		var __model = requestObj.paramsObj.model;
		var __set = requestObj.paramsObj.set;

		// ERROR CHECKING
		if (__model == null || typeof __model == 'undefined') {
			throw new Error('ERROR stdlib.command.SetModelCommand - model parameter is required');
		} else {
			if (typeof __model == 'string') {
				if (__model == '') throw new Error('ERROR stdlib.command.SetModelCommand - model parameter must be a non-empty string');
			} else {
				throw new Error('ERROR stdlib.command.SetModelCommand - model parameter must be type String');
			}
		}

		if (!__set) __set = mojo.Model.get(__model); //reset by default

		mojo.Model.set(__model, __set);
		requestObj.paramsObj.set = null;
	}
});
dojo.provide("stdlib.command.UpdateControllerParamCommand");
dojo.require("mojo.command.Command");

dojo.declare("stdlib.command.UpdateControllerParamCommand", mojo.command.Command, {
	execute: function(requestObj) {
		var __elm;
		var __control;
		var __parameter;
		var __value;

		var params = requestObj.getParams();
		if (params) {
			if (params.element != null) __elm = params.element;
			if (params.control != null) __control = params.control;
			if (params.params != null) __parameter = params.params;
			if (params.value != null) __value = params.value;
		}

		try {
			if ((__control!=null)&&(__parameter!=null)&&(__value!=null)) {
				if (__elm) {
					__elm.mojoControllers[__control].setValue(__parameter, __value);
				} else {
					requestObj.getController().getContextController(__control).setValue(__parameter, __value);
				}
			}
		} catch(err) {}

		
	},

	onResponse: function() {
	},

	onError: function() {
	}
});
dojo.provide("stdlib.command.UpdateObserversCommand");
dojo.require("mojo.controller.Controller");
dojo.require("mojo.command.Command");

dojo.declare("stdlib.command.UpdateObserversCommand", mojo.command.Command, {
	execute: function(requestObj) {
		var timeout = setTimeout(function() {
			mojo.controller.Controller.updateObservers(requestObj.getParams().controllerName);
			clearTimeout(timeout);
		}, 20);
		
		
	}
});
dojo.provide("stdlib.command.ValidateRulesCommand");
dojo.require("mojo.command.Command");
dojo.require("mojo.helper.Validation");
dojo.require("mojo.helper.view.Error");
dojo.require("mojo.query");

dojo.declare("stdlib.command.ValidateRulesCommand", mojo.command.Command, {
	_targetElement: null, // error messages will appear INSIDE the target (container) element
	_checkAll: true,
	_output: function(errorList, targetElement) {
		
	},
	execute: function(requestObj) {

		var rules;
		var formSet;
		var params = requestObj.getParams();
		if (params) {
			if (params.targetElement != null) this._targetElement = params.targetElement;
			if (params.checkAll != null) this._checkAll = params.checkAll;
			if (params.rules != null) rules = params.rules;
			if (params.formSet != null) formSet = params.formSet;
		}

		if (rules) {
		  
			if (this._targetElement != null) {
				this._targetElement.innerHTML = "";
				if (formSet) {
					var clearTags = ["label","inputs","textarea","select"];
					for (var i = 0; i < clearTags.length; i++) {
						var Tag = mojo.query(clearTags[i], formSet);
						for (var j = 0; j < Tag.length; j++) {
							dojo.removeClass(Tag[j], "error");
						}
					}
				}
			}
			if (typeof(rules) == "string") {
				dojo.require(rules);
				eval("requestObj.getParams().rules = " + rules);
			}
			var val = mojo.helper.Validation.getInstance();
			if ((formSet)&&(this._checkAll)) {
				var errorList = val.execute(requestObj.getParams().rules, formSet);
			} else {
				var errorList = val.execute(requestObj.getParams().rules, [requestObj.callerObj]);

			}
			
			if (errorList.length > 0) {
				if (this._targetElement != null) {
					mojo.helper.view.Error.showElementErrors(errorList, this._targetElement);
					for (var i=0; i<errorList.length; i++) {
						dojo.addClass(errorList[i].element, "error");
						if (errorList[i].element.parentNode.tagName == "LABEL") dojo.addClass(errorList[i].element.parentNode, "error");
					}
				} else {
				//	mojo.helper.view.Error.showElementErrors(errorList)
					for (var i = 0, len = errorList.length; i < len; i++) {
						var error = errorList[i];
						var err = document.createElement("span");
						err.className = "mojoValidationError";
						err.innerHTML = error.message;

						if(error.element.type == "checkbox") {
							if(error.element.parentNode.tagName == "LABEL") {
								dojo.place(err, error.element.parentNode, 'after');
							} else {
								dojo.place(err, error.element, 'after');
							}
						} else {
							dojo.place(err, error.element, 'after');
						}

						
					}
				}
				this.onError();
			} else if (requestObj.invocation) {
				this.onResponse();
				requestObj.invocation.proceed();
			}
		} else {
			console.debug("ERROR stdlib.command.ValidateRulesCommand - No rules passed");
		}
	},
	onResponse: function() {
	  if(this._targetElement.style.display != "none") this._targetElement.style.display = "none";
		
	},
	onError: function() {
	  if(this._targetElement.style.display != "block") this._targetElement.style.display = "block";
		
	}
});
/* 
	Class: stdlib.command.metrics.omniture.InitializeMetricsMap
	Author: Jaime Bueza
	
	Responsible for mapping page-specific properties for Omniture Metrics.
*/
dojo.provide("stdlib.command.metrics.InitializeMetricsMapCommand");
dojo.require("mojo.command.Command");
dojo.declare("stdlib.command.metrics.InitializeMetricsMapCommand", mojo.command.Command, 
{
	execute: function(requestObj) {
		var params = requestObj.getParams();
		var metricsMap = params.map;
		var map = eval(metricsMap);
		var pages = map.pages;
		
		
		for(var i = 0, len = pages.length; i < len; i++) {
			var metricsProperties = {};
			var pattern = pages[i].pattern;
			var properties = pages[i].properties;
			if (typeof(pattern) == "string") {
				//We're a css selector, so we try to find the selecotr on the current page, match it, map it.
				var currentPage = mojo.query(pattern);
				if(currentPage) {
					metricsProperties = properties;
				}
			} else if (typeof(pattern) == "function" || typeof(pattern) == "object") {
				var regex = new RegExp(pattern);
				if(regex.test(window.location.href)) {
					if(typeof(properties) == "function") {
						properties = properties();
					}
					metricsProperties = properties;
				}
			} else {
				throw new Error("ERROR stdlib.command.metrics.omniture.GetMetricsMapCommand - metricsMap for Pages contains invalid pattern");
			}
			for (key in metricsProperties) {
				s[key] = metricsProperties[key];
			}
		}		
		
	}
});

/*
	Class: stdlib.command.metrics.omniture.TransactionCommand
	Author: Jaime Bueza
*/
dojo.provide("stdlib.command.metrics.omniture.TransactionCommand");
dojo.require("mojo.command.Command");
dojo.declare("stdlib.command.metrics.omniture.TransactionCommand", mojo.command.Command, 
{
	onComplete: function() { 
		//Generic event that signifies a Track/Set operation has been completed.
	},
	onError: function() {
		//console.log("There was an error in the Metrics command.");
	},
	execute: function(requestObj) {
		var params = requestObj.getParams();		
		//if the dev doesn't specify which transactionType they want, it will default to "page".
		if(!params.transactionType) {
			s.t();
		} else if(params.transactionType == "customLink"){
			if (!params.properties) return;

			//We need to consolidate params.properties into an array.
			
			if(!dojo.isArray(params.properties)) {
				params.properties = [params.properties];
			}
			
			for(var i = 0, len = params.properties.length; i < len; i++) {
				var tmp = {};
				var callerName = params.callerName || 'anonymousTrigger';
				var linkVars = [];
				var linkEvents = [];
				for(key in params.properties[i]) {

					if(key.indexOf("prop") == 0 || key.indexOf("eVar") == 0) linkVars.push(key);
					if(key.indexOf("event") == 0) linkEvents.push(key);

					tmp[key] = s[key];
					s[key] = params.properties[i][key];
				}

				if (linkEvents.length) linkVars.push('events');

				s.linkTrackVars = linkVars.length ? linkVars.join(",") : "None";
				s.linkTrackEvents = linkEvents.length ? linkEvents.join(",") : "None";
				//Execute the transaction.
				if(requestObj.callerObj.href) {
					s.tl(requestObj.callerObj,'o');
				} else {
					//s.tl(requestObj.callerObj,'o', callerName);
					s.tl();
				}
				//Resets the original keys before the transaction occurs
				//TODO: Check to see if we're actually restoring the old
				//values of the s object prior to the transaction.
				for(key in tmp) {
					s[key] = tmp[key];
				}
			}
		}
	

	}
});
dojo.provide("stdlib.controller.AccordianController");
dojo.require("mojo.controller.Controller");

dojo.declare("stdlib.controller.AccordianController", mojo.controller.Controller, 
{
	params: {
		selectedIndex: {
			required: false,
			defaultValue: 0,
			type: Number
		},
		activeOn: {
			required: false,
			defaultValue: "onclick"
		},
		toggleClose: {
			required: false,
			defaultValue: false
		},
		direction: {
			required: false,
			defaultValue: "vertical"
		}
	},
	addObservers: function() {
		var accordianPanels = mojo.query("> .accordian-panel", this.getContextElement());
		var accordians = mojo.query("> .accordian-panel > .accordian", this.getContextElement());
		var accordianContents = mojo.query("> .accordian-panel > .accordian-content", this.getContextElement());
		
		this.addObserver("> .accordian-panel > .accordian", this.getValue("activeOn"), "UpdateClass", function(context, caller) { 
			var tabs = accordians;
			var index = 0;
			for (var i = 0; i < tabs.length; i++) {
				if (tabs[i] == caller) {
					index = i;
					break;
				}
			}
			if (this.getController().getValue("toggleClose") && index == this.getController().getValue("selectedIndex")) {
				this.getController().setValue("selectedIndex", -1);
			} else {
				this.getController().setValue("selectedIndex", index);
			}
		});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "Tween", function(context, caller, controller) { 	
			return {
			height: (controller.getValue("direction") == "vertical") ? 0 : null,
			width: (controller.getValue("direction") == "horizontal") ? 0 : null,
			element: mojo.query("> .open > .accordian-content", context)
		}});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
			element: accordianPanels,
			action: "remove",
			cssClass: "open"
		}});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
			element: accordianPanels[caller.getValue()],
			action: "add",
			cssClass: "open"
		}});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "Tween", function(context, caller, controller) {
			var elm = accordianContents[caller.getValue()];
			if (!elm) return;
			return {
			element: elm,
			height: (controller.getValue("direction") == "vertical") ? elm.scrollHeight : null,
			width: (controller.getValue("direction") == "horizontal") ? elm.scrollWidth : null
		}});	
	},
	addCommands: function() {
		this.addCommand("UpdateClass", "stdlib.behavior.UpdateCssClassBehavior");
		this.addCommand("Tween", "stdlib.behavior.TweenBehavior");
	},
	addIntercepts: function() {

	}
});
dojo.provide("stdlib.controller.AccordionController");
dojo.require("mojo.controller.Controller");

dojo.declare("stdlib.controller.AccordionController", mojo.controller.Controller, 
{
	params: {
		selectedIndex: {
			required: false,
			defaultValue: 0,
			type: Number
		},
		activeOn: {
			required: false,
			defaultValue: "onclick"
		},
		toggleClose: {
			required: false,
			defaultValue: false
		},
		direction: {
			required: false,
			defaultValue: "vertical"
		}
	},
	addObservers: function() {
		var accordionPanels = mojo.query("> .accordion-panel", this.getContextElement());
		var accordions = mojo.query("> .accordion-panel > .accordion", this.getContextElement());
		var accordionContents = mojo.query("> .accordion-panel > .accordion-content", this.getContextElement());
		
		this.addObserver("> .accordion-panel > .accordion", this.getValue("activeOn"), "UpdateClass", function(context, caller) { 
			var tabs = accordions;
			var index = 0;
			for (var i = 0; i < tabs.length; i++) {
				if (tabs[i] == caller) {
					index = i;
					break;
				}
			}
			if (this.getController().getValue("toggleClose") && index == this.getController().getValue("selectedIndex")) {
				this.getController().setValue("selectedIndex", -1);
			} else {
				this.getController().setValue("selectedIndex", index);
			}
		});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "Tween", function(context, caller, controller) { 	
			return {
			height: (controller.getValue("direction") == "vertical") ? 0 : null,
			width: (controller.getValue("direction") == "horizontal") ? 0 : null,
			element: mojo.query("> .open > .accordion-content", context)
		}});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
			element: accordionPanels,
			action: "remove",
			cssClass: "open"
		}});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
			element: accordionPanels[caller.getValue()],
			action: "add",
			cssClass: "open"
		}});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "Tween", function(context, caller, controller) {
			var elm = accordionContents[caller.getValue()];
			if (!elm) return;
			return {
			element: elm,
			height: (controller.getValue("direction") == "vertical") ? elm.scrollHeight : null,
			width: (controller.getValue("direction") == "horizontal") ? elm.scrollWidth : null
		}});	
	},
	addCommands: function() {
		this.addCommand("UpdateClass", "stdlib.behavior.UpdateCssClassBehavior");
		this.addCommand("Tween", "stdlib.behavior.TweenBehavior");
	},
	addIntercepts: function() {

	}
});
dojo.provide("stdlib.controller.AutoSuggestController");
dojo.require("mojo.controller.Controller");

dojo.declare("stdlib.controller.AutoSuggestController", mojo.controller.Controller, 
{
	params: {
		model: {
			required: false,
			defaultValue: "suggestions"
		},
		modelPath: {
			required: false,
			defaultValue: "suggestions"
		},
		serviceLocator: {
			required: true,
			defaultValue: "sample.service.Locator"
		},
		serviceName: {
			required: false,
			defaultValue: "getSuggestions"
		},
		inputName: {
			required: false,
			defaultValue: "suggest-input"
		}
	},
	addObservers: function() {
		this.addObserver("input.suggest-input", "onkeyup", "GetSuggestions", function(context, caller) { return {
			query: caller.value,
			model: this.getController().getValue("model"),
			modelPath: this.getController().getValue("modelPath"),
			serviceLocator: this.getController().getValue("serviceLocator"),
			serviceName: this.getController().getValue("serviceName")
		};});
		this.addObserver("input.suggest-input", "onkeydown", "SuggestNavigation", function(context, caller) { return {
			suggestions: mojo.query(".suggestion", context)
		};});
		this.addObserver(this.getCommand("SuggestNavigation"), "onNav", "UpdateClass", function(context, caller) { return {
			element: mojo.query(".suggestion", context),
			action: "remove",
			cssClass: "selected"
		};});
		this.addObserver(this.getCommand("SuggestNavigation"), "onNav", "UpdateClass", function(context, caller) { return {
			element: caller.suggestion,
			action: "add",
			cssClass: "selected"
		};});
		this.addObserver(this.getCommand("SuggestNavigation"), "onNav", "UpdateForm", function(context, caller) { 																			   															   
			return {
				formObj: context,
				fields: [{
					name: this.getController().getValue("inputName"),
					value: (caller.suggestion.innerHTML.split("\n")[0] || caller.suggestion.innerHTML.split("\n")[1]).replace(/\s*\<[^\>]+\>\s*/g, "")
				}]
			};
		});
		this.addObserver(".suggestion", "onmouseover", "UpdateForm", function(context, caller) { return {
			formObj: context,
			fields: [{
				name: this.getController().getValue("inputName"),
				value: (caller.innerHTML.split("\n")[0] || caller.innerHTML.split("\n")[1]).replace(/\s*\<[^\>]+\>\s*/g, "")
			}]
		};});
		this.addObserver(".suggestion", "onmouseover", "UpdateClass", function(context, caller) { return {
			element: caller, 
			action: "add",
			cssClass: "selected"
		};});
		this.addObserver(".suggestion", "onmouseout", "UpdateClass", function(context, caller) { return {
			element: caller,
			action: "remove",
			cssClass: "selected"
		};});
		this.addObserver("input.suggest-input", "onblur", "ClearModel", function(context, caller) { return {
			model: this.getController().getValue("model")
		};});
	},
	addCommands: function() {
		this.addCommand("SuggestNavigation", "stdlib.behavior.AutoSuggest.SuggestNavigationBehavior");
		this.addCommand("UpdateClass", 	"stdlib.behavior.UpdateCssClassBehavior");
		this.addCommand("GetSuggestions", "stdlib.command.AutoSuggest.GetSuggestionsCommand");
		this.addCommand("ClearModel", "stdlib.command.ClearModelCommand");
		this.addCommand("UpdateForm", "stdlib.behavior.UpdateFormFieldBehavior");
	},
	addIntercepts: function() {

	}
});
dojo.provide("stdlib.controller.DateController");
dojo.require("mojo.controller.Controller");

dojo.declare("stdlib.controller.DateController", mojo.controller.Controller, 
{
	params: {
		date: {
			defaultValue: new Date()
		}
	},
	addObservers: function() {	
		//Upon starting up this controller, set the date to what was specified in the sitemap.
		this.addObserver(this, "onInit", "PopulateDate", function(context, caller) { 
			//Retrieve the controller instances' date obj
			//This date obj can be current date if you did not specify a value from the SiteMap
			return {
				target: this.getContextElement(),
				month: this.getController().getValue("date").getMonth(),
				year: this.getController().getValue("date").getFullYear() 
			}
		});
		this.addObserver(this.getCommand("PopulateDate"), "execute", "PopulateDays", function(context, caller) { 
			return {
				target: mojo.queryFirst("> .date-day", context),
				day: (new Date()).getDate(),
				month: mojo.queryFirst("> .date-month", context).value,
				year: mojo.queryFirst("> .date-year", context).value
			}
		});
		
		this.addObserver("> .date-month", "onchange", "PopulateDays", function(context, caller) { 
			return {
				target: mojo.queryFirst("> .date-day", context),
				month: mojo.queryFirst("> .date-month", context).value,
				year: mojo.queryFirst("> .date-year", context).value
			}
		});
		this.addObserver("> .date-year", "onchange", "PopulateDays", function(context, caller) { 
			return {
				target: mojo.queryFirst("> .date-day", context),
				month: mojo.queryFirst("> .date-month", context).value,
				year: mojo.queryFirst("> .date-year", context).value
			}
		});
		this.addObserver(this.getConfig("params").date, "onChange", "PopulateDate", function(context, caller) {
			return {
				target: this.getContextElement(),
				month: this.getController().getValue("date").getMonth(),
				year: this.getController().getValue("date").getFullYear() 
			}
		});

	},
	addCommands: function() {
		this.addCommand("PopulateDate", "stdlib.behavior.PopulateDateBehavior");
		this.addCommand("PopulateDays", "stdlib.behavior.PopulateDaysBehavior");
	},
	addIntercepts: function() {

	}
});
/* 
	Class: stdlib.controller.DialogController
	Author: Jaime Bueza
	
	The Mojo Dialog Controller can be accessed by publishing messages with a topic called "dialog".
	
	In order to use this, you can simply use:
	
	(start code)
	mojo.Messaging.publish("dialog", { enabled: true, href: "/my-url-to-a-file.jsp", width: 500, height: 250 });
	(end)
	
	If you pass "url" (String), the Dialog Controller will fetch the html content and inject it into
	<div class="dialog">, which is automatically generated if it is not in the DOM.
	
	If you pass "id" (String), the Dialog Controller will fetch the innerHTML of the specific DOM Element
	by ID and inject the innerHTML into <div class="dialog">.
	
	In its entirety, you can render Dialogs internally (already in the DOM), or externally (on the fly in
	a remote location).
	
	There are two main behaviours which dictate the functionality of the Dialog.
		- DialogBehavior
			This behavior is responsible for rendering the dialog and fetching the markup, whether
			the content is external (remotely fetched via XHR) or internal (fetched via already on the DOM).
			
		- PositionBehavior
			This behavior is responsible for recalculating the dimensions of the Dialog based on content,
			and repositioning the Dialog to the center of the screen based on the dimensions of its content.
			
	Assumptions:
		- There can only be 1 dialog open at a time.
		
	Notes:
		- Perhaps we can pass a parameter to the Position behaviour to allow transitions (fading in, sliding, etc)?

*/
dojo.provide("stdlib.controller.DialogController");
dojo.require("mojo.controller.Controller");
dojo.declare("stdlib.controller.DialogController", mojo.controller.Controller, 
{
	params: {
		/* 
			Parameter: container {String}
				Override this parameter when you're extending the Dialog Controller.
		*/
		container: {
			required: false,
			defaultValue: ".dialog-component",
			type: String
		},
		/* 
			Parameter: title {String}
				Override this parameter when you're extending the Dialog Controller.
		*/
		title: {
			required: false,
			defaultValue: ".dialog-component .dialog-component-title",
			type: String
		},
		titleText: {
			required: false,
			defaultValue: "Hello World",
			type: String
		},
		content: {
			required: false,
			defaultValue: ".dialog-component .dialog-component-content",
			type: String
		},
		width: {
			defaultValue: 0,
			type: Number
		},
		height: {
			defaultValue: 0,
			type: Number
		}
	},
	addObservers: function() {
		var content = this.getValue("content"),
			title = this.getValue("title"),
			container = this.getValue("container"),
			titleText = this.getValue("titleText");
		
		//Trigger for initializing a Mojo Dialog. 
		this.addObserver(mojo.Messaging.getTopic("dialog"), "onPublish", "Dialog", function(context, caller) { 
		
			var msgObj = caller.getMessage();
			msgObj.elContainer = container;
			msgObj.elContent = content;
			msgObj.elTitle = title;
			if(!msgObj.title) { 
				msgObj.title = titleText;
			}

			this.getController().setValue("width", msgObj.width);
			this.getController().setValue("height", msgObj.height);

			//set msgObj into a model
			mojo.Model.set("stlib.dialog.params", msgObj);

			return msgObj;
		});


		//Re-update observers once the Dialog has instantiated itself.
		this.addObserver(this.getCommand("Dialog"), "onComplete", "MapControllers");
		this.addObserver(this.getCommand("Dialog"), "onComplete", "UpdateObservers", function(context, caller) {
			return {
				controllerName: this.getController().declaredClass
			};
		});
		
		//Accessibility feature of allowing the user to keypress "ESC" on their keyboard to close the dialog.
		this.addObserver(window, "onkeyup", "EscapeKey"); //TODO: keyCode vs charCode in IE--IE won't register ESC properly.
		this.addObserver(this.getCommand("EscapeKey"), "onResponse", "Dialog", function(context, caller) {
			return {
				enabled: false
			};
		});
				
		//Repositioning based on User Behaviour (if they resize, scroll, etc)
		this.addObserver(this.getCommand("Dialog"), "execute", "Position");
		this.addObserver(window, "onresize", "Position");
		this.addObserver(window, "onscroll", "Position");
		
		//Basic functionality
		this.addObserver(mojo.queryFirst(".btn-close"), "onclick", "Messaging", function(context, caller) {
			//Allows a user to close the dialog.
			return {
				topic: "dialog",
				message: {
					enabled: false
				}
			};
		});
				
	},
	addCommands: function() {	
		this.addCommand("ClearModel",				"stdlib.command.ClearModelCommand");
		this.addCommand("Messaging",				"stdlib.behavior.MessagingBehavior");
		this.addCommand("Dialog", 					"stdlib.behavior.dialog.DialogBehavior");
		this.addCommand("Position", 				"stdlib.behavior.dialog.PositionBehavior");
		this.addCommand("EscapeKey", 				"stdlib.behavior.dialog.EscapeKeyBehavior");
		this.addCommand("MapControllers", 			"stdlib.command.MapControllersCommand");
		this.addCommand("UpdateObservers", 			"stdlib.command.UpdateObserversCommand");
	},
	addIntercepts: function() {
		
	}
});
dojo.provide("stdlib.controller.FilmStripController");
dojo.require("mojo.controller.Controller");

dojo.declare("stdlib.controller.FilmStripController", mojo.controller.Controller, 
{
	params: {
		selectedIndex: {
			required: false,
			defaultValue: 0,
			type: Number
		},
		loop: {
			required: false,
			defaultValue: false,
			type: Boolean
		}
	},
	addObservers: function() {
		var pages = function(context) {
			return mojo.query("> .filmstrip-viewer > .filmstrip-content > .filmstrip-page", context);
		};
		
		this.addObserver("> .filmstrip-next", "onclick", "UpdateClass", function(context, caller) { 
			var tabs = pages(context);
			var index = this.getController().getValue("selectedIndex");
			index++;
			if (index >= pages(context).length) {
				if (this.getController().getValue("loop")) {
					this.getController().setValue("selectedIndex", 0);
				}
			} else {
				this.getController().setValue("selectedIndex", index);
			}
		});
		this.addObserver("> .filmstrip-prev", "onclick", "UpdateClass", function(context, caller) { 
			var tabs = pages(context);
			var index = this.getController().getValue("selectedIndex");
			index--;
			if (index < 0) {
				if (this.getController().getValue("loop")) {
					this.getController().setValue("selectedIndex", pages(context).length-1);
				}
			} else {
				this.getController().setValue("selectedIndex", index);
			}
		});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller, controller) {	return {
					element: mojo.query("> .filmstrip-next", context),
					action: (caller.getValue() >= pages(context).length-1) ? "add" : "remove",
					cssClass: "disabled"
		}});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller, controller) {	return {
					element: mojo.query("> .filmstrip-prev", context),
					action: (caller.getValue() <= 0) ? "add" : "remove",
					cssClass: "disabled"
		}});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "Tween", function(context, caller, controller) { return {
			x: (-1*pages(context)[caller.getValue()].offsetLeft),
			y: (-1*pages(context)[caller.getValue()].offsetTop),
			element: mojo.query("> .filmstrip-viewer > .filmstrip-content", context)
		}});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
			element: pages(context),
			action: "remove",
			cssClass: "selected"
		}});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
			element: pages(context)[caller.getValue()],
			action: "add",
			cssClass: "selected"
		}});
	},
	addCommands: function() {
		this.addCommand("UpdateClass", "stdlib.behavior.UpdateCssClassBehavior");
		this.addCommand("Tween", "stdlib.behavior.TweenBehavior");
	},
	addIntercepts: function() {

	}
});
dojo.provide("stdlib.controller.FormController");
dojo.require("mojo.controller.Controller");
dojo.declare("stdlib.controller.FormController", mojo.controller.Controller, 
{
	params: {
		isSubmitted: {
			required: false,
			defaultValue: false,
			type: Boolean
		},
		formSubmitCommand: {
			required: true,
			defaultValue: "FormSubmitCommand",
			type: String
		},
		formRules: {
			required: true,
			defaultValue: "stdlib.rules.Rules",
			type: String
		},
		modelErrors: {
			required: false,
			defaultValue: "stdlib.myModel",
			type: String
		},
		formId: {
			required: true,
			defaultValue: "#form",
			type: String
		},
		submitButtonId: {
			required: true,
			defaultValue: "#submit-form",
			type: String
		},
		cancelButtonId: {
			required: false,
			defaultValue: "#cancel-form",
			type: String
		}
	},
	addObservers: function() {
		//Parameters
		var rules = this.getValue("formRules"),
			errorsModel = this.getValue("modelErrors"),
			formId = this.getValue("formId");
		

		//Tooltips
		/*
		this.addObserver("span.info", "onmouseover", "ToolTip", function() { return { show: true }});
		this.addObserver("span.info", "onmouseout", "ToolTip", function() { return { show: false }});
		*/
		
		//Handles all "Enter" key submits.
		this.addObserver("input", "onkeydown", "EnterKey"); 
		
		//Handles onblur validation only if the user has clicked "submit", but has errors in it.
		this.addObserver("input", "onblur", "ValidateRules", function(context, caller) {
			if(!this.getController().getValue("isSubmitted")) return { rules: {}, formSet: mojo.query(formId)};
			return {
				rules: rules,
				formSet: mojo.query(formId)
			}
		});
		this.addObserver("textarea", "onblur", "ValidateRules", function(context, caller) {
			if(!this.getController().getValue("isSubmitted")) return { rules: {}, formSet: mojo.query(formId)};
			return {
				rules: rules,
				formSet: mojo.query(formId)
			}
		});
		this.addObserver("select", "onchange", "ValidateRules", function(context, caller) {
			if(!this.getController().getValue("isSubmitted")) return { rules: {}, formSet: mojo.query(formId)};
			return {
				rules: rules,
				formSet: mojo.query(formId)
			}
		});

		//Handles form submission.
		/*
		this.addObserver(this.getCommand(this.getValue("formSubmitCommand")), "onError", "DisableBox", function(context, caller) { 
			return { 
				target: context, show: false
			}
		});*/
		this.addObserver(this.getCommand(this.getValue("formSubmitCommand")), "onResponse", "ClearModel", function() { 
			return { 
				model: errorsModel 
			}
		});
		/*
		this.addObserver(this.getCommand(this.getValue("formSubmitCommand")), "onResponse", "DisableBox", function(context, caller) { 
			return { 
				target: context, show: false
			}
		});*/

		//Add an observer to the onclick of Submit to update the Controller's parameters for isSubmitted = true.
		this.addObserver(this.getValue("submitButtonId"), "onclick", "UpdateControllerParam", function(context, caller, controller) {
			
			return {
				control: this.getController().declaredClass,
				params: "isSubmitted", 
				value: true, 
				element: context
			}
		});
		
		//Re-run ValidateRules when isSubmitted changes values. 
		this.addObserver(this.getConfig("params").isSubmitted, "onChange", "ValidateRules", function(context, caller) {
			if(!this.getController().getValue("isSubmitted")) return { rules: {}, formSet: mojo.query(formId)};
			return {
				rules: rules, 
				formSet: mojo.query(formId)
			}
		});
		
		/*
		//Cancel Button
		this.addObserver(this.getValue("cancelButtonId"), "onclick", "ClearErrors", function(context, caller) { 
			return { 
				className: ".mojoValidationError", 
				targetId: this.getController().getValue("formId")
			}
		});
		*/
		this.addObserver(this.getValue("cancelButtonId"), "onclick", "ClearForm", function(context, caller) {
			return {
				formSet: mojo.queryFirst(this.getController().getValue("formId"),context)
			}
		});
		/*
		//Show DisableBox if we pass Validation.
		this.addObserver(this.getCommand("ValidateRules"), "onResponse", "DisableBox", function(context, caller) {
			return { 
				target: context, 
				show: true 
			}
		});*/
	},
	addCommands: function() {	
		//Add pre-made commands to automatically handle the following:
			//Messaging
			//EnterKey
			//UpdateControllerParam
			//DisableBox
			//ClearForm
			//ClearErrors
			//ClearModel
			//Refresh
			//ToolTip
			//Validate
			//DATA COMMANd
		this.addCommand("Messaging",				"stdlib.behavior.MessagingBehavior");	
		this.addCommand("EnterKey",					"stdlib.behavior.EnterKeyBehavior");
		this.addCommand("UpdateControllerParam",	"stdlib.command.UpdateControllerParamCommand");
		this.addCommand("DisableBox",				"stdlib.behavior.DisableBoxBehavior");
		this.addCommand("ClearForm",				"stdlib.behavior.ClearFormBehavior");
/*		this.addCommand("ClearErrors",				"stdlib.command.RemoveObjectsCommand"); */
		this.addCommand("ClearModel",				"stdlib.command.ClearModelCommand");
		this.addCommand("Redirect", 					"stdlib.behavior.RedirectBehavior");
/*		this.addCommand("ToolTip", 					"stdlib.behavior.ToolTipBehavior"); */
		this.addCommand("ValidateRules",			"stdlib.command.ValidateRulesCommand");
	},
	addIntercepts: function() {
		this.addIntercept("around", this.getValue("formSubmitCommand"),	"ValidateRules", { rules: this.getValue("formRules"), formSet: mojo.query(this.getValue("formId")) });
	}
});
dojo.provide("stdlib.controller.FormValidationController");
dojo.require("mojo.controller.Controller");
dojo.declare("stdlib.controller.FormValidationController", mojo.controller.Controller, 
{
	params: {
		isSubmitted: {
			required: false,
			defaultValue: false,
			type: Boolean
		},
		formRules: {
			required: true,
			defaultValue: "stdlib.rules.Rules",
			type: String
		},
		submitButtonId: {
			required: true,
			defaultValue: "#submit-form",
			type: String
		},
		cancelButtonId: {
			required: false,
			defaultValue: "#cancel-form",
			type: String
		},
		errorsContainerId: {
			required: false,
			defaultValue: "",
			type: String
		},
		showDisableBox: {
			required: false,
			defaultValue: true
		}
	},
	addObservers: function() {
		var formRules = this.getValue("formRules");
		var targetElement = (this.getValue("errorsContainerId") != "") ? mojo.queryFirst(this.getValue("errorsContainerId")) : null;
		
	
		//Handles all "Enter" key submits.
		this.addObserver("input", "onkeydown", "EnterKey");
		this.addObserver(this.getCommand("EnterKey"), "onResponse", "UpdateControllerParam", function(context, caller) {
			return {
				control: this.getController().declaredClass,
				params: "isSubmitted", 
				value: true, 
				element: context
			}
		});
		this.addObserver(this.getCommand("EnterKey"), "onResponse", "SubmitForm", function(context, caller) {
			return {
				form: this.getContextElement()
			}
		});
		
		//Handles onblur validation only if the user has clicked "submit", but has errors in it.
		this.addObserver(["input", "textarea"], "onblur", "ValidateRules", function(context, caller) {
			if(!this.getController().getValue("isSubmitted")) return { rules: {}, formSet: this.getContextElement()};
			return {
				rules: formRules,
				formSet: this.getContextElement(),
				targetElement: targetElement
			}
		});
		this.addObserver("select", "onchange", "ValidateRules", function(context, caller) {
			if(!this.getController().getValue("isSubmitted")) return { rules: {}, formSet: this.getContextElement()};
			return {
				rules: formRules,
				formSet: this.getContextElement(),
				targetElement: targetElement
			}
		});

		//Add an observer to the onclick of Submit to update the Controller's parameters for isSubmitted = true.
		this.addObserver(this.getValue("submitButtonId"), "onclick", "UpdateControllerParam", function(context, caller) {
			return {
				control: this.getController().declaredClass,
				params: "isSubmitted", 
				value: true, 
				element: context
			}
		});
		this.addObserver(this.getValue("submitButtonId"), "onclick", "SubmitForm", function(context, caller) {
			return {
				form: this.getContextElement()
			}
		});
		
		this.addObserver(this.getCommand("SubmitForm"), "execute", "DisableBox", function(context, caller) {
			if(!this.getController().getValue("showDisableBox")) return; //No disable box if the dev specifies it in the controller paarams.
			return {
				show: true,
				target: context
			}
		});
		
		//Re-run ValidateRules when isSubmitted changes values. 
		this.addObserver(this.getConfig("params").isSubmitted, "onChange", "ValidateRules", function(context, caller) {
			if(!this.getController().getValue("isSubmitted")) return { rules: {}, formSet: this.getContextElement()};
			return {
				rules: formRules,
				formSet: this.getContextElement(),
				targetElement: targetElement
			}
		});
		
		this.addObserver(this.getValue("cancelButtonId"), "onclick", "ClearErrors", function(context, caller) { 
			return { 
				className: ".mojoValidationError", 
				target: this.getContextElement()
			}
		});
	},
	addCommands: function() {
		this.addCommand("EnterKey",			"stdlib.behavior.EnterKeyBehavior");
		this.addCommand("UpdateControllerParam",	"stdlib.command.UpdateControllerParamCommand");
		this.addCommand("ClearErrors",			"stdlib.behavior.RemoveElementsBehavior");
		this.addCommand("ValidateRules",		"stdlib.command.ValidateRulesCommand");
		this.addCommand("SubmitForm",			"stdlib.behavior.SubmitFormBehavior");
		this.addCommand("DisableBox", 			"stdlib.behavior.DisableBoxBehavior");
	},
	addIntercepts: function() {
		this.addIntercept("around", "SubmitForm", "ValidateRules", { 
			rules: this.getValue("formRules"),
			formSet: this.getContextElement(),
			targetElement: (this.getValue("errorsContainerId") != "") ? mojo.queryFirst(this.getValue("errorsContainerId")) : null
		});
	}
});

/* 
	Class: SliderController
	
	An abstract Slider component that a
*/
dojo.provide("stdlib.controller.SliderController");
dojo.require("mojo.controller.Controller");
dojo.declare("stdlib.controller.SliderController", mojo.controller.Controller, 
{
	params: {
		//The number of pixels between ticks.
		tickSize: {
			required: false,
			defaultValue: 10,
			type: Number
		},
		tickValue: {
			required: false,
			defaultValue: 1,
			type: Number
		},
		tickMaxValue: {
			required: false,
			defaultValue: 10,
			type: Number
		},
		value: {
			required: false,
			defaultValue: 0,
			type: Number
		},
		valueInput: {
			required: false,
			defaultValue: "slider-value-input",
			type: String
		},
		thumb: {
			required: false,
			defaultValue: ".slider-thumb",
			type: String
		},
		draggable: {
			required: false,
			defaultValue: false,
			type: Boolean
		},
		selectedIndex: {
			required: false,
			defaultValue: 0,
			type: Number
		},
		//"horizontal" or "vertical"
		orientation: {
			required: false,
			defaultValue: "horizontal",
			type: String
		}
	},	
	addObservers: function() {	
		this.addObserver(this.getContextElement(), "onmousedown", "UpdateControllerParam", function(context, caller) {
			return {
				control: "stdlib.controller.SliderController",
				params: "draggable",
				value: true
			}
		});
		
		this.addObserver(this.getContextElement(), "onmousedown", "Drag", function(context, caller) {
			return {
				element: mojo.queryFirst(".slider-thumb", context),
				container: mojo.queryFirst(".slider-bg", context),
				orientation: this.getController().getValue("orientation"),
				tickSize: this.getController().getValue("tickSize")
			};
		});
		
		this.addObserver(document.body, "onmouseup", "UpdateControllerParam", function(context, caller) {
			return {
				control: "stdlib.controller.SliderController",
				params: "draggable",
				value: false
			}
		});
		
		this.addObserver(this.getContextElement(), "onmousemove", "Drag", function(context, caller) {
			if(!this.getController().getValue("draggable")) return;
			return {
				element: mojo.queryFirst(".slider-thumb", context),
				container: mojo.queryFirst(".slider-bg", context),
				orientation: this.getController().getValue("orientation"),
				tickSize: this.getController().getValue("tickSize")
			};
		});
		
		this.addObserver(this.getCommand("Drag"), "execute", "UpdateControllerParam", function(context, caller) {
			if(!this.getController().getValue("draggable")) return;
			return {
				control: "stdlib.controller.SliderController",
				params: "selectedIndex",
				value: this.getController().getCommand("Drag").selectedIndex
			};
		});
		
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateControllerParam", function(context, caller) {
			if(!this.getController().getValue("draggable")) return;
			return {
				control: "stdlib.controller.SliderController",
				params: "value",
				value: caller.getValue() * this.getController().getValue("tickValue")
			};
		});

		this.addObserver(this.getConfig("params").draggable, "onChange", "UpdateFormField", function(context, caller) {
			if(this.getController().getValue("draggable")) return;
			return {
				formObj: context,
				fields: [{
					name: this.getController().getValue("valueInput"),
					value: this.getController().getValue("value")
				}]
			};
		});
		this.addObserver(mojo.queryFirst("#"+this.getValue("valueInput")), "onchange", "UpdateControllerParam", function(context, caller) {
			if(this.getController().getValue("draggable")) return;
			return {
				control: "stdlib.controller.SliderController",
				params: "value",
				value: parseInt(caller.value)
			};
		});
		
		this.addObserver(this.getConfig("params").value, "onChange", "UpdateControllerParam", function(context, caller) {
			if(this.getController().getValue("draggable")) return;
			return {
				control: "stdlib.controller.SliderController",
				params: "selectedIndex",
				value: Math.round(caller.getValue() / this.getController().getValue("tickValue"))
			};
		});
		
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "Drag", function(context, caller) {
			if(this.getController().getValue("draggable")) return;
			return {
				element: mojo.queryFirst(".slider-thumb", context),
				container: mojo.queryFirst(".slider-bg", context),
				orientation: this.getController().getValue("orientation"),
				tickSize: this.getController().getValue("tickSize"),
				position: caller.getValue() * this.getController().getValue("tickSize")
			};
		});
		
	},
	addCommands: function() {	
		this.addCommand("Drag",				"stdlib.behavior.DragBehavior");
		this.addCommand("Tween",			"stdlib.behavior.TweenBehavior");
		this.addCommand("UpdateControllerParam",	"stdlib.command.UpdateControllerParamCommand");
		this.addCommand("UpdateFormField", 		"stdlib.behavior.UpdateFormFieldBehavior");
	},
	addIntercepts: function() {}
});
dojo.provide("stdlib.controller.TabController");
dojo.require("mojo.controller.Controller");

dojo.declare("stdlib.controller.TabController", mojo.controller.Controller, 
{
	params: {
		selectedIndex: {
			required: false,
			defaultValue: 0,
			type: Number
		},
		activeOn: {
			required: false,
			defaultValue: "onclick"
		}
	},
	addObservers: function() {		
		this.addObserver("> .tabs-nav > .tab", this.getValue("activeOn"), "UpdateClass", function(context, caller) { 
			var tabs = mojo.query("> .tabs-nav > .tab", context);
			var index = 0;
			for (var i = 0; i < tabs.length; i++) {
				if (tabs[i] == caller) {
					index = i;
					break;
				}
			}
			this.getController().setValue("selectedIndex", index);
		});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
			element: mojo.query("> .tabs-nav > .selected", context),
			action: "remove",
			cssClass: "selected"
		}});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
			element: mojo.query("> .tabs-content > .selected", context),
			action: "remove",
			cssClass: "selected"
		}});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
			element: mojo.query("> .tabs-nav > .tab", context)[caller.getValue()],
			action: "add",
			cssClass: "selected"
		}});
		this.addObserver(this.getConfig("params").selectedIndex, "onChange", "UpdateClass", function(context, caller) { return {
			element: mojo.query("> .tabs-content > .tab-content", context)[caller.getValue()],
			action: "add",
			cssClass: "selected"
		}});
		this.addObserver("> .add", "onclick", "UpdateClass", function(context, caller) {
			mojo.Model.add("testData", {name: "new", description: (new Date()).getTime()});
			this.getController().setValue("selectedIndex", 0);
			this.getController().getConfig("params").selectedIndex.onChange();
		});
	},
	addCommands: function() {
		this.addCommand("UpdateClass", "stdlib.behavior.UpdateCssClassBehavior");
	},
	addIntercepts: function() {

	}
});
/*
	Class: stdlib.controller.metrics.MetricsController
	Author: Steven Luscher, Jaime Bueza, Loyal Chow
			
	Manages generic Omniture access via Transaction Command and InitializeMetricsMap Command.
	
	Notes:
		- You cannot add trackableLinks (customLink events) to onInit of any controller due
		to the way this Metrics engine is designed. The Metrics Engine initializes when
		all other controllers have been mapped, thusly, you can't observe onInit. If
		you wanted to observe a custom event when the app starts up, you can either
			a) put the events into the MetricsMap.pages property
				or
			b) attach the track to a command that is fired at the beginning of your application
			
			
	Exmample Metrics Map (MetricsMap.js):
		(start code)
		dojo.provide("clubn.MetricsMap");
		clubn.MetricsMap = {
			pages: [
				{
					pattern: /clubnintendo/,
					properties: function() {
						return {
							pageName: "nintendo:club nintendo"
						}
					}
				},
				{
					pattern: /registration/,
					properties: {
						//Optionally, you can specify an object, instead of a function returning an object.
						pageName: "Homepage"
					}
				}	
			],
			links: [
				{

					pattern: ".promo-hot-spot .promo",
					event: "onclick",
					properties: function(caller) {
						return {
							prop1: caller.className,
							eVar2: "evar 2 set"
						}
					}
				}
			]
		};
		(end)		
*/
dojo.provide("stdlib.controller.metrics.MetricsController");
dojo.require("mojo.controller.Controller");
dojo.declare("stdlib.controller.metrics.MetricsController", mojo.controller.Controller, 
{
	params: {
		metricsMap: {
			defaultValue: "app.MetricsMap",
			required: true
		},
		pageIsLoaded: {
			defaultValue: false 
		},
		analyticsSuite: {
			defaultValue: "omniture",
			required: false
		}
	},
	getMetricsMap: function() {
		dojo.require(this.getValue("metricsMap"));
		var obj = (eval(this.getValue("metricsMap")));
		return obj;
	},
	addObservers: function() {
		this.addObserver(this, "onInit", "Init", { map: this.getValue("metricsMap") });		
		this.addObserver(mojo.controller.Map.getInstance(), "onComplete", "TrackPage", function(context, caller) {
			if(this.getController().getValue("pageIsLoaded")) return false;
			this.getController().setValue("pageIsLoaded", true);
		});
		
		var links = this.getMetricsMap().links;
		
		
		for (var i = 0, len = links.length; i < len; i++) {
			var trackableLink = links[i];	
		

			//Generic variables for the addObservers, we're going to fill this in based on the logic below.
			var whatToTrack = null, whenToTrack = null; 
			
			//BIG TODO: Refactor both the "this.addObserver" calls within this block into
			//a controlller-based call to nullify code duplication.
			
			if(!trackableLink.command && !trackableLink.controller) {
				//We're a DOM element
				whatToTrack = trackableLink.pattern;
				whenToTrack = trackableLink.event;


				this.addObserver(whatToTrack, whenToTrack, "TrackLink", function(tl) {
					return function(context, caller) {
						var tmpProperties = null;
						if(typeof(tl.properties) == "function") {
							tmpProperties = tl.properties(caller);
						} else {
							tmpProperties = tl.properties;
						}
						if (!tmpProperties) return false;
						return {
							transactionType: "customLink",
							properties: tmpProperties
						}
					}
				}(trackableLink));
			} else {
				//We're a Mojo Object
				var mojoObj = mojo.query(trackableLink.pattern); //Grabs a X number of context elements
				if(!mojoObj) {
					//if we can't find the context of the controller on the page, we must continue the loop
					//and not add an observer
					continue;
				} else {
					if(!dojo.isArray(mojoObj)) {
						mojoObj = [mojoObj];
					}
					for(var x = 0, newLen = mojoObj.length; x < newLen; x++) {
						var obj = mojoObj[x].mojoControllers[trackableLink.controller];

						whenToTrack = trackableLink.event;
						if(!trackableLink.command || trackableLink.command == 'undefined') {
							//If you don't pass a command param, the observer == controller.
							whatToTrack = obj;
			
						} else {
							//We observe the command within the controller.
							whatToTrack = obj.getCommand(trackableLink.command);
						}
				
					
						//console.log("Controller: ", whatToTrack.declaredClass, " --> ", whenToTrack);	

						//Fixes TrackableLink reference problem because function(context, caller){}
						//is invoked upon the user interaction, so the returning object will always
						//be the last link object within the MetricsMap. The following patches this 
						//by passing in a
						//function that takes the trackableLink, and returns the context, caller
						//into the TrackLink callback function.
						this.addObserver(whatToTrack, whenToTrack, "TrackLink", function(tl) {
							return function(context, caller) {
								var tmpProperties = null;
								if(typeof(tl.properties) == "function") {
									tmpProperties = tl.properties(caller);
								} else {
									tmpProperties = tl.properties;
								}
								if (!tmpProperties) return false;
								return {
									transactionType: "customLink",
									properties: tmpProperties
								}
							}
						}(trackableLink));
						
					}
				}
			}
		}
	},
	addCommands: function() {
	  	this.addCommand("TrackPage", 		"stdlib.command.metrics." + this.getValue("analyticsSuite") + ".TransactionCommand");
	 	this.addCommand("TrackLink", 		"stdlib.command.metrics." + this.getValue("analyticsSuite") + ".TransactionCommand");
		this.addCommand("Init", 			"stdlib.command.metrics.InitializeMetricsMapCommand");
	},
	addIntercepts: function() {}
});

/*
    Class: stdlib.behavior.FilterDropdownBehavior
    Author: Loyal Chow

    Filters the options of an HTML Select list by class name
*/
dojo.provide("stdlib.behavior.FilterDropdownBehavior");
dojo.require("mojo.command.Behavior");

dojo.declare("stdlib.behavior.FilterDropdownBehavior", mojo.command.Behavior,
{
    _optionsStorage: {},
    execute: function(requestObj) {
        // Params:
        var params = requestObj.getParams();
        var dropdown = params.selectObj;
        var filterClass = params.filterClass;
        var minoption = params.minoption;

	if(params.minoption =="undefined"){
		minoption =0;
	}
	else minoption =-1;
	
        // Get Name/ID
	if (!dropdown) { return; }
        var dropdownName = (dropdown.name || dropdown.id);

        // Store Options
        if (typeof(this._optionsStorage[dropdownName]) == "undefined") {
            this._optionsStorage[dropdownName] = [];
            for (var i = 0; i < dropdown.options.length; i++) {
                this._optionsStorage[dropdownName][i] = dropdown.options[i];
            }
        }
        
       
        // Blow Away Existing Options
        for (var i = dropdown.options.length - 1; i > minoption ; i--) {
            dropdown.removeChild(dropdown.options[i]);
        }
        
       
        // Add Filtered Options from Storage
        for (var i = 0; i < this._optionsStorage[dropdownName].length; i++) {
            var option = this._optionsStorage[dropdownName][i];

            if (option.className.indexOf(filterClass) >= 0) {
  
                dropdown.appendChild(option);
            }
        }
        // Reset Selected Index
        if (dropdown.options.length > 0 && filterClass.length > 0) {
            dropdown.selectedIndex = 0;
        }
    
    
    
    
    }
});
dojo.provide("stdlib.controller.TemplateController");
dojo.require("mojo.controller.Controller");

dojo.declare("stdlib.controller.TemplateController", mojo.controller.Controller, 
{
	modelSource: "",
	_modelSourceHandle: null,
	templateObj: null,
	escapeQuotes: false,
	escapeHtml: false,
	onInit: function() {
		var context = this.getContextElement();
		var templateHTML = this._normalize(context.innerHTML);
		this.templateObj = TrimPath.parseTemplate(templateHTML);
		dojo.style(this.getContextElement(), 'display', 'none');
		this.setModelSource(context.getAttribute("modelsource"));
	},
	getModelSource: function() {
		if(!this.modelSource) {
			return "";
		}
		return this.modelSource;
	},
	setModelSource: function(modelSource) {
		if (this._modelSourceHandle) {
			mojo.Model.removeObserver(this._modelSourceHandle);
		}
		this.modelSource = modelSource;
		this._modelSourceHandle = mojo.Model.addObserver(this.modelSource, this, "onModelUpdate");
		this.onModelUpdate();
	},
	onModelUpdate: function() {
		this._bindToModel();
	},
	_bindToModel: function() {
		var modifiers = {
			escapeQuotes: function(str) {
				str = str.toString();
				str = str.replace(/\"/g, "&#34;");
				str = str.replace(/\'/g, "&#39;");
				return str;
			}
		};
		var sModel = this.getModelSource();
		if (sModel.length > 0 && mojo.Model.contains(sModel) && this.getContextElement()) {
			var modelData = mojo.Model.get(sModel);
			var result = new Array();
			if (!dojo.isArray(modelData)) {
				modelData = [modelData];
			}
			var modelDataLength = modelData.length;

			for (var i = 0, len = modelDataLength; i < len; i++) {
				if (modelData[i]) {
					if (typeof(modelData[i]) != "object") {
						var tmpModelData = modelData[i].toString();
						modelData[i] = new Object();
						modelData[i].data = tmpModelData;
					}
					modelData[i].currentIndex = i;
					modelData[i].totalLength = len;
					if(this.escapeQuotes) {
						modelData[i]._MODIFIERS = modifiers;
						modelData[i].content = modifiers.escapeQuotes(modelData[i].content);
					}
					result.push(this.templateObj.process(modelData[i]));
				}
			}
			var templateNode = this.getContextElement();
			var content = result.join("");

			templateNode.innerHTML = "";
			templateNode.innerHTML = content;
			dojo.style(this.getContextElement(), 'display', 'block');
		} else {
			dojo.style(this.getContextElement(), 'display', 'none');
		}
	},
	_normalize: function(templateStr) {
		var pattern = /[\!|\$]\{[^\}]*\}/g;
		var matchResult = templateStr.match(pattern);
		var splitResult = templateStr.split(pattern);
		var result = new Array();
		var resultLength = 0;
		if (matchResult) {
			resultLength = matchResult.length;
		}
		for (var i = 0; i < resultLength; i++) {
			result.push(splitResult[i]);
			var npattern = "$" + matchResult[i].substring(1);
			var modifiers = "";
			if (this.escapeHtml) {
				modifiers += "|escape";
			}
			if (this.escapeQuotes) {
				modifiers += "|escapeQuotes";
			}

			npattern = npattern.substring(0, npattern.length-1) + modifiers + "}";
			result.push(npattern);
		}

		result.push(splitResult[resultLength]);
		return result.join("");
	},
	addObservers: function() {		
	},
	addCommands: function() {
	},
	addIntercepts: function() {

	}
});