//=========================================================================
// Ssr Compact Library - scl_<n>.js
// $Id: scl_1.js,v 1.2 2009-07-29 04:58:27 sam Exp $
// © Copyright 2006-2009 Sam Rehman <sam@rehman.net>

var	ssr	= {
	version : "1.23"
};

//---------------------------------------------------------------
// Array: Array utils
ssr.array = {

	remove : function(array, val) 
	{
		var	i;
		for ( i=0; i<array.length; i+=1 )
		{
			if ( array[i] == val )
			{
				var	sav	= this[i];
				array.splice(i, 1);
				return sav;
			}
		}
		return null;	
	},
	
	add : function( array, val )
	{
		array[array.length]	= val;
	}
};

//---------------------------------------------------------------
// ssr.cookie: Cookie class
ssr.cookie =
{
	// set: Create or Set a cookie value. Days is the expiration days.
	set : function(name,value,days) 
	{
		if ( !value )
		{
			days	= -1;
		}
		
		var expires;
		if (days) 
		{
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			expires = "; expires="+date.toGMTString();
		}
		else
		{
			expires = "";
		}
		
		// use javascript URL escape codes to escape cookie val
		value = escape(value);
		
		document.cookie = name+"="+value+expires+"; path=/;";
	},

	// get: Return the value of a cookie. If not found, returns null
	get : function (name) 
	{
		var cookies = document.cookie.split("; ");
		for(var i=0; i<cookies.length; i=i+1) 
		{
			var c = cookies[i].split('=');
			if ( c[0] == name )
			{
				var	str	= c[1];
								
				// Remove leading and trailing quotes
				str	= str.replace( /\"/g, "" );
				
				// use javascript URL escape codes to UNescape cookie val
				str = unescape(str);
				
				return str;
			}
		}
		return null;
	},

	// remove: Remove a cookie from the system designated by the name param
	remove : function (name) 
	{
		ssr.cookie.set(name,"",-1);
	},
	
	// TO DO: jwu - used for URL escape in hash for resetPassword.js; check if other escape error
	// URL escape function plus manual '+' escape, which is not escaped
	escape : function (url)
	{
		return (escape(url)).replace(/\+/g,'%2B');
	}
};

//---------------------------------------------------------------
// Browser: Browser detection
ssr.browser = {
	browser : "unknown",
	version : null,
	OS : null,
	
	init: function () {
		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this.version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || "an unknown version";
		this.OS = this.searchString(this.dataOS) || "an unknown OS";
	},
	
	searchString: function (data) 
	{
		for (var i=0;i<data.length;i+=1)	
		{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) 
			{
				if (dataString.indexOf(data[i].subString) != -1)
				{
					return data[i].identity;
				}
			}
			else if (dataProp)
			{
				return data[i].identity;
			}
		}
	},
	
	searchVersion: function (dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return;
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},
	
	// 
	dataBrowser: [
		{ 	string: navigator.userAgent,
			subString: "OmniWeb",
			versionSearch: "OmniWeb/",
			identity: "OmniWeb"
		},
		{
			string: navigator.vendor,
			subString: "Apple",
			identity: "Safari"
		},
		{
			prop: window.opera,
			identity: "Opera"
		},
		{
			string: navigator.vendor,
			subString: "iCab",
			identity: "iCab"
		},
		{
			string: navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString: "Camino",
			identity: "Camino"
		},
		{		// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: "Netscape",
			identity: "Netscape"
		},
		{
			string: navigator.userAgent,
			subString: "MSIE",
			identity: "Explorer",
			versionSearch: "MSIE"
		},
		{
			string: navigator.userAgent,
			subString: "Gecko",
			identity: "Mozilla",
			versionSearch: "rv"
		},
		{ 		// for older Netscapes (4-)
			string: navigator.userAgent,
			subString: "Mozilla",
			identity: "Netscape",
			versionSearch: "Mozilla"
		}
	],
	dataOS : [
		{
			string: navigator.platform,
			subString: "Win",
			identity: "Windows"
		},
		{
			string: navigator.platform,
			subString: "Mac",
			identity: "Mac"
		},
		{
			string: navigator.platform,
			subString: "Linux",
			identity: "Linux"
		}
	],
	
	getBrowser : function() { return ssr.browser.browser; },
	getVersion : function() { return ssr.browser.version; },
	getPlatform : function() { return ssr.browser.OS; },
	
	isCookieEnabled : function()
	{
		var	name	= "SSR_DUMMY",
			value	= "7-15";
			
		// Write to a dummy cookie
		ssr.cookie.set( name, value );
		
		var	read	= ssr.cookie.get( name );
		// Clear it back
		ssr.cookie.remove( name );
		
		if ( read !== value )
		{
			return false;
		}
		else
		{
			return true;
		}
	},
	
	isIE : function()
	{
		return (window.ActiveXObject) ? true : false;
	}
};

//---------------------------------------------------------------
// Document: Document scope stuffs
ssr.document = {
	goToUrl : function ( url )
	{
	    window.location.href = url;
	},
	
	goBack : function()
	{
		history.go(-1);
	},
	
	submit : function(formName)
	{
		ssr.element.get( formName ).submit();
	},
	
	initFlag 		: false, //flag to indicate whether target function has already been run
	onReady			: null,
	
	init : function()
	{
		if ( !ssr.document.initFlag )
		{
			ssr.document.initFlag	= true; 
  			ssr.document.onReady()
		}
	},
	
	callWhenReady : function( func )
	{
		if (document.addEventListener)
		{
  			document.addEventListener("DOMContentLoaded", function() { ssr.document.init(); }, false );
  		}
		else if (document.all && !window.opera)
		{
  			document.write('<script type="text/javascript" id="contentloadtag" defer="defer" src="javascript:void(0)"><\/script>')
  			var contentloadtag=document.getElementById("contentloadtag")
  			contentloadtag.onreadystatechange=function(){
    			if (this.readyState=="complete")
    			{
      				ssr.document.init();
      			}
    		}
    	}
    	
		window.onload=function()
		{
  			setTimeout("ssr.document.init();", 0);
		};
  	}
  	
};

//---------------------------------------------------------------
// Simple event handling
ssr.event = {
	getEventHandler : function( fieldName, type )
	{
		var	e	= ssr.element.get(fieldName);
		switch ( type )
		{
		case "load": 		return e.onload;
		case "unload": 		return e.onunload;
		
		case "click": 		return e.onclick;
		case "change": 		return e.onchange;
			
		case "blur": 		return e.onblur;
		case "focus": 		return e.onfocus;
		
		case "scroll":		return e.onscroll;
		case "resize":		return e.onresize;
		
		case "keyup":		return e.onkeyup;
		case "keydown":		return e.onkeydown;
		case "keypress":	return e.onkeypress;
		
		case "mouseup":		return e.onmouseup;
		case "mousedown":	return e.onmousedown;
		case "mousemove":	return e.onmousemove;
		case "mouseout":	return e.onmouseout;
		case "mouseover":	return e.onmouseover;
		
		case "drag":		return e.ondragstart;
		
		default:
			throw "ssr.event.getCallback: invalid event type:"+type;
		}
	},
		
	setEventHandler : function( fieldName, type, callback )
	{
		var	e	= ssr.element.get(fieldName);
		switch ( type )
		{
		case "load": 		e.onload		= callback; break;
		case "unload": 		e.onunload		= callback; break;

		case "click": 		e.onclick		= callback; break;
		case "change": 		e.onchange		= callback; break;
			
		case "blur": 		e.onblur		= callback; break;
		case "focus": 		e.onfocus		= callback; break;
		
		case "scroll":		e.onscroll		= callback; break;
		case "resize":		e.onresize		= callback; break;
		
		case "keyup":		e.onkeyup		= callback; break;
		case "keydown":		e.onkeydown		= callback; break;
		case "keypress":	e.onkeypress	= callback; break;
		
		case "mouseup":		e.onmouseup		= callback; break;
		case "mousedown":	e.onmousedown	= callback; break;
		case "mousemove":	e.onmousemove	= callback; break;
		case "mouseout":	e.onmouseout	= callback; break;
		case "mouseover":	e.onmouseover	= callback; break;
		
		case "drag":		e.ondragstart	= callback; break;
		
		default:
			throw "ssr.event.setCallback: invalid event type:"+type;
		}
	},

	addCallbackToElement : function( fieldName, type, callback, scope )
	{
		var	e	= ssr.element.get(fieldName);
		
		// See if has existing callbacklist
		
		var	callbackListCreated	= false;
		var	listName	= type+"Callbacks";
		if ( ! (e[listName]) )
		{
			e[listName]	= [];
			callbackListCreated	= true;
		}
		
		ssr.array.add( e[listName], { callback: callback, scope: scope } );
	
		return callbackListCreated;
	},
	
	// addListener: Trap an event
	addListener : function( fieldName, type, userCallback, scope )
	{
		var	e	= ssr.element.get(fieldName);
		
		// Add this callback
		if ( ssr.event.addCallbackToElement( e, type, userCallback, scope ) )
		{
			// Add existing handler so we don't overwrite callbacks created by markup
			var	oriHandler	= ssr.event.getEventHandler( e, type );
			if ( oriHandler )
			{
				// alert( "oriHandler exists!! "+fieldName+type );
				ssr.event.addCallbackToElement( e, type, oriHandler, null );
			}

			// We created callback list so we assume we need to add new callback
			var	wrapperHandler	= function(ev) {
				var	event	= ssr.event.getEvent( ev );
				
				// Pull out target list
				var	attrName	= type+"Callbacks";
				if ( event.target[attrName] )
				{
					var	list	= event.target[attrName];
					for ( i in list )
					{
						try
						{
							var	scope	= list[i].scope;
							if ( !scope )
							{
								scope	= event;
							}
							list[i].callback( scope, event );
						}
						catch (e)
						{
							throw "Exception on event callback for element "+event.target.id+":"+e;
						}
					}
				}
				
				return false;
			};
			
			ssr.event.setEventHandler( fieldName, type, wrapperHandler );
		}
	},
	
	removeListener : function( fieldName, type )
	{
		var	e			= ssr.element.get(fieldName);
		var	callback	= null;
		switch ( type )
		{
		case "load": 		e.onload		= callback; break;
		case "unload": 		e.onunload		= callback; break;

		case "click": 		e.onclick		= callback; break;
		case "change": 		e.onchange		= callback; break;
			
		case "blur": 		e.onblur		= callback; break;
		case "focus": 		e.onfocus		= callback; break;
		
		case "scroll":		e.onscroll		= callback; break;
		case "resize":		e.onresize		= callback; break;
		
		case "keyup":		e.onkeyup		= callback; break;
		case "keydown":		e.onkeydown		= callback; break;
		case "keypress":	e.onkeypress	= callback; break;
		
		case "mouseup":		e.onmouseup		= callback; break;
		case "mousedown":	e.onmousedown	= callback; break;
		case "mousemove":	e.onmousemove	= callback; break;
		case "mouseout":	e.onmouseout	= callback; break;
		case "mouseover":	e.onmouseover	= callback; break;
		
		case "drag":		e.ondragstart	= callback; break;
		
		default:
			throw "ssr.element.addListener: invalid event type:"+type;
		}
	},
	
	getEvent : function( param1 )
	{
		var event;
		if ( param1 ) event = param1; else event	= window.event;
		
		// Fix ie 
		if ( event.srcElement )	event.target = event.srcElement;
		
		return event;
	}
	
};

//---------------------------------------------------------------
// SsrDate: Date Utils
ssr.date = {
	// toSimpleString: Get a shorten form
    toSimpleString : function( date, nowDate, noTimeOnDate )
    {
    	var	str	= "";
    	var	nDate		= date.getDate(),
    		nMonth		= date.getMonth(),
    		nYear		= date.getFullYear(),
    		nHours		= date.getHours(),
    		nMinutes	= date.getMinutes();
    		
		if ( nYear == nowDate.getFullYear() )
		{
			if ( nMonth == nowDate.getMonth() &&
					nDate == nowDate.getDate() )
			{
				// See if is one hour ago
				if ( nHours == nowDate.getHours() )
				{
					var	mins	= nowDate.getMinutes()-nMinutes;
					str	+= mins+" min";
				}
				else
				{
					// Show hour:minutes only
					str	= nHours+":"+nMinutes;
				}
			}
			else
			{
				// Show MM/YY HH:MM
				str	= (nMonth+1)+"/"+nDate +"/"+nYear;
				if ( !noTimeOnDate )
				{
					str	+= " "+nHours+":"+nMinutes;
				}
			}
		}
		else
		{
			// Show full
			str	= (nMonth+1)+"/"+nDate+"/"+nYear;
			if ( !noTimeOnDate )
			{
				str	+= " "+nHours+":"+nMinutes;
			}
		}
		return str;
    }
};

//---------------------------------------------------------------
// ssr.debug: For debugging
ssr.debug = 
{
	level	: null
};

//---------------------------------------------------------------
// ssr.element: Simple Element functions
ssr.element = 
{
	// get: Get an element, input name could be the name, or even the element itself,
	//		in which case, it will just return the element
	get : function ( name )
	{
		var	e	= null;
		
		if ( !name && ssr.debug.level )
		{
			throw "ssr.element: get failed, name is invalid:"+name;
		}
		
		if ( !name )
		{
			return null;
		}
		
		if ( name.tagName || name == window )
		{
			e	= name;
		}
		else
		{
			e = document.getElementById(name);
			if ( !e && ssr.debug.level )
			{
				throw "ssr.element: get failed, cannot find element:"+name ;
			}
		}
		return e;
	},
	
	exists : function( name )
	{
		return (ssr.element.get(name) != null );
	},
	
	getChildNodes : function( root )
	{
		var retnode = [];
		var elem = root.getElementsByTagName('*');
		return elem;
	},
	
	getChildByTagName : function( root, tagName )
	{
		return root.getElementsByTagName( tagName );
	},
	
	getParentByTagName : function( name, tagName )
	{
		var	e	= ssr.element.get( name );
		while ( true )
		{
			if ( e.parentNode == null )
				return null;
			if ( e.tagName == tagName )
				return e;
			e	= e.parentNode;
		}
	},

	isChildOf : function( childName, parentName )
	{
		var	ce	= ssr.element.get( childName ),
			pe	= ssr.element.get( parentName );
	
		while ( ce != null )
		{
			if ( ce == pe )
				return true;
			ce	= ce.parentNode;
		}
		return false;
	},
	
	// Show / Hide
	show : function ( name, inline )
	{
		var	e	= ssr.element.get( name );
		if ( ssr.browser.isIE() )
		{
			// This is from inline, to fix IE peek-a-boo bug
			// This will force the hasLayout flag
			e.style.minWidth = '0px';
			// e.style.display = 'inline-block';
			e.style.display = ""; 
		}
		else
		{
			// if not IE bug, we can just do 
			e.style.display = ( inline ) ? 'inline' : "";
		}
	},
	
	setOpacity : function( name, op )
	{
		var	e	= ssr.element.get( name );
		e.style.opacity = op/100;
		e.style.filter = 'alpha(opacity = ' + op + ')';
	},
	
	display : function( name, ds )
	{
		var	e	= ssr.element.get( name );
		e.style.display = ds; 
	},
	
	isShown : function( name )
	{
		var	e	= ssr.element.get( name );
		return ( e.style.display != 'none' );
	},
	
	hide : function( name )
	{
		var	e	= ssr.element.get( name );
		e.style.display = 'none';
	},
	
	isShown : function( name )
	{
		var	e	= ssr.element.get( name );
		return ( e.style.display != 'none' );
	},

	setVisibility : function ( name, visi )
	{
		var	e	= ssr.element.get( name );
		var	val;
		if ( visi )
			val	= 'visible';
		else
			val	= 'hidden';
		e.style.visibility = val;
	},
	
	// Constant element types
	ttUnknown 		: 0,
	ttInput	 		: 1,
	ttInputCheckBox	: 2,
	ttInputRadio 	: 3,
	ttInputText 	: 4,
	ttInputPassword	: 5,
	ttInputButton	: 6,
	ttInputFile		: 7,
	ttInputHidden	: 8,
	ttInputImage	: 9,
	ttInputSubmit	: 10,

	ttInputSelect	: 11,
	ttInputTextArea	: 12,
	
	ttImage			: 13,
	ttAnchor		: 14,
	
	ttSpan		: 11,
	ttDiv		: 12,
	
	// Return type of tag
	getTagType		: function( name )
	{
		var	e	= ssr.element.get( name );
		var	tagName	= e.tagName.toUpperCase();

		if ( tagName == "INPUT" )
		{
			var	type	= e.type.toUpperCase();
			switch( type )
			{
			case "CHECKBOX": 	return ssr.element.ttInputCheckBox;
			case "RADIO": 		return ssr.element.ttInputRadio;
			case "TEXT": 		return ssr.element.ttInputText;
			case "PASSWORD":	return ssr.element.ttInputPassword;
			case "BUTTON":		return ssr.element.ttInputButton;
			case "FILE": 		return ssr.element.ttInputFile;
			case "HIDDEN":		return ssr.element.ttInputHidden;
			case "IMAGE":		return ssr.element.ttInputImage;
			case "SUBMIT":		return ssr.element.ttInputSubmit;
			default:			return ssr.element.ttInput;
			}
		}
		else if ( e.tagName == "SELECT" )
		{
			return ssr.element.ttInputSelect;
		}
		else if ( tagName == "TEXTAREA" )
		{
			return ssr.element.ttInputTextArea;
		}
		else if ( tagName == "IMG" )
		{
			return ssr.element.ttImage;
		}
		else if ( tagName == "A" )
		{
			return ssr.element.ttAnchor;
		}
		else
		{
			return ssr.element.ttUnknown;
		}
	},
	
	//---------------------------------
	// Field classes
	addClass : function( fieldName, className )
	{
		var	e	= ssr.element.get(fieldName);
		
		// Make sure it does not exist already
		if ( e.className.indexOf( className ) >= 0 )
		{
			return;
		}
		
		e.className	+= " "+className;
	},
	
	removeClass : function( fieldName, className )
	{
    	var	e	= ssr.element.get( fieldName );
    	if ( !e )
    	{
    		throw "ssr.element.removeTagClass: invalid name="+fieldName;
		}
		var	newClassStr	= e.className;
		newClassStr	= newClassStr.replace( className, "" );
		newClassStr	= newClassStr.replace( " +", " " );
		e.className	= newClassStr;
	},

	hasClass : function( name, className )
	{
		var	e	= ssr.element.get(name);
		return ( e.className.indexOf( className ) >= 0 )
	},
		
	getByClassName : function( cl, root )
	{
		// If not root provided, use document
		if ( !root )
		{
			root	= document;
		}
			
		var retnode = [];
		var myclass = new RegExp('\\b'+cl+'\\b');
		var elem = root.getElementsByTagName('*');
		var i;
		for (i = 0; i < elem.length; i=i+1) 
		{
			var classes = elem[i].className;
			if (myclass.test(classes)) retnode.push(elem[i]);
		}
		return retnode;
	},
	
	// Positioning
	setPosition : function( name, pos )
	{
		var	e	= ssr.element.get(name);
		
		// make sure is absolute
		//e.style.position	= "absolute";
		if ( pos.y != null ) e.style.top		= pos.y+"px";
		if ( pos.x != null ) e.style.left		= pos.x+"px";
	},
	
	setSize : function( name, size )
	{
		var	e	= ssr.element.get(name);
		
		// make sure is absolute
		// e.style.position	= "absolute";
		if ( size.width != null )
		{
			e.style.width		= size.width+"px";
		}
		if ( size.height != null )
		{
			e.style.height		= size.height+"px";
		}
	},
	
	getSize : function( name )
	{
		var	e	= ssr.element.get(name);
		var	size = { width: -1, height: -1 };
		if (e.style.pixelHeight) 
		{ 
			size.width	= e.style.pixelWidth;
			size.height = e.style.pixelHeight;
		} 
		else if ( e.offsetHeight )
		{
			size.width	= e.offsetWidth;
			size.height = e.offsetHeight;
		}
		return size;
	},
	
	getScreenSize : function ()
	{
		var	size = { width: 0, height: 0 };
		if ( ssr.browser.isIE() )
		{
    		size.width	= document.documentElement.clientWidth;
		    size.height	= document.documentElement.clientHeight;
			
			//size.width	= document.body.offsetWidth;
			//size.width	= window.screen.availWidth;
			//size.height	= document.body.offsetHeight;
		}
		else
		{
			size.width	= window.innerWidth;
			size.height	= window.innerHeight; 
		}
		return size;
	},
	
	getScrollPosition : function()
	{
		var	pos = { x:0, y:0 };
	
		pos.y	= window.pageYOffset || document.documentElement.scrollTop || 0; 
		pos.x	= scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || 0;

/*		if ( ssr.browser.isIE() )
		{
			pos.x	= document.body.scrollLeft ||
						document.documentElement.scrollLeft;
			pos.y	= document.body.scrollTop ||
						document.documentElement.scrollTop;
		}
		else
		{
			pos.x	= window.pageXOffset;
			pos.y	= window.pageYOffset;
		}*/
		
		return pos;
	},
	
	getPosition : function( name )
	{
		var	e	= ssr.element.get(name);
		var x = y = 0;
		if ( e.offsetParent )
		{
	        do 
	        {
	          	x	+= e.offsetLeft;
	          	y	+= e.offsetTop;
	        } while ( e = e.offsetParent );
    	}
    	else if ( e.x )
    	{
    		x	= e.x;
    		y	= e.y;
    	}
    	else
    	{
    		throw "ssr.element: Cannot get X,Y location";
    	}
    	return { x: x, y: y };
	},

	 getCenterPosition : function( name )
	 {
	 	var	e			= ssr.element.get(name);
	 	var	screenSize	= ssr.element.getScreenSize(),
	 		elementSize	= ssr.element.getSize(e),
	 		pos			= ssr.element.getScrollPosition();
	 	
	 	/*
	 	alert( "Screen Size =x:"+screenSize.width+" y:"+screenSize.height +"\n"+
	 			"Element Size =x:"+elementSize.width+" y:"+elementSize.height+"\n"+
	 			"Pos Size =x:"+pos.x+" y:"+pos.y+"\n" );
	 	*/
	 			
	 	// Center size is screen Size - elementSize / 2
	 	if ( screenSize.width > elementSize.width )
	 	{
	 		pos.x	+= (screenSize.width-elementSize.width) / 2;
	 	}

	 	if ( screenSize.height > elementSize.height )
	 	{
	 		pos.y	+= (screenSize.height-elementSize.height) / 2;
	 	}

		return pos;
	 },
	 
	 moveToCenter : function( name )
	 {
	 	var	pos	= ssr.element.getCenterPosition( name );
	 	ssr.element.setPosition( name, pos );
	 },
	 
	moveNextTo : function( name, type, target, offset, matchSide )
	{
		var	targetPos		= ssr.element.getPosition( target );
		var	srcSize			= ssr.element.getSize( name );
		var	targetSize		= ssr.element.getSize( target );
		var	newPos	= { x: targetPos.x, y: targetPos.y };
		var	newSize	= null;
		
		if ( !offset ) offset	= 0;
		
		switch ( type )
		{
		case "over":
			// Just on top of target
			break;
		case "above":
			newPos.y	-= (srcSize.height + offset);
			break;
		case "below":
			newPos.y	+= (targetSize.height + offset);
			break;
		case "left":
			newPos.x	-= (targetSize.width + offset);
			break;
		case "right":
			newPos.x	+= (srcSize.width + offset);
			break;
		}
		
		ssr.element.setPosition( name, newPos );
		
		// See if has match size
		if ( matchSide )
		{
			var newSize	= { width: null, height: null };
			switch( matchSide )
			{
			case "width":
				newSize.width	= targetSize.width;
				break;
			case "height":
				newSize.height	= targetSize.height;
				break;
			case "both":
				newSize.width	= targetSize.width;
				newSize.height	= targetSize.height;
				break;
			}
			ssr.element.setSize( name, newSize );
		}
	},

	
	
	
	// get value
	//-----------------------------------------------------------
	// SELECT utils
	// addOption:	add an option to a <select> tag. sel is the doc element
	addOption : function( name, optionName, value )
	{
		var	element	= ssr.element.get(name);
		element.options[element.length] = new Option(optionName, value);
	},
	
	// removeAllOptions:	Remove all options from a <select> tag. sel is the doc element
	removeAllOptions : function(name)
	{
		var	element	= ssr.element.get(name);
		element.options.length	= 0;
	},
	
	// selectOptionByIndex: Set the current selection of a <select> tag to index. sel is the doc element	
	selectOptionByIndex : function( name, index )
	{
		var	element	= ssr.element.get(name);
		element.selectedIndex	= index;
	},
	
	// selectOptionByValue:	Tries to find an option that has the same value as value param
	//						if found, that option will be selected. If not, exception is thrown.
	//						sel is the doc element
	selectOptionByValue : function( name, value )
	{
		if ( ssr.string.isEmpty(value) )
		{
			ssr.element.selectOptionByIndex( name, 0 );
			return;
		}
		
		var	element	= ssr.element.get(name);
		var	i;
		for ( i=0; i<element.options.length; i=i+1 )
		{
			if ( element.options[i].value == value ||
					element.options[i].innerHTML == value )
			{
				ssr.element.selectOptionByIndex( element, i );
				return;
			}
		}
		throw "ssr.element: cannot find value :"+value+" in sel:"+name;
	},
	
	getSelectedOption : function( name )
	{
		var	e		= ssr.element.get(name);
		return e.options[e.selectedIndex];
	},

	//---------------------------------------------
	// Values
	getValue : function( name )
	{
		var	val	= null;
		var	e		= ssr.element.get(name);
		var	tagType	= ssr.element.getTagType(e);
		switch ( tagType )
		{
		case ssr.element.ttInputCheckBox:
		case ssr.element.ttInputRadio:
			if ( e.checked )
			{
				val	= true;
			}
			else
			{
				val	= false;
			}
			break;
			
		case ssr.element.ttInput:
		case ssr.element.ttInputPassword:
		case ssr.element.ttInputText:
		case ssr.element.ttInputHidden:
		case ssr.element.ttInputTextArea:
			val	= e.value;
			break;
			
		case ssr.element.ttInputSelect:
			if ( e.selectedIndex < 0 )
			{
				val	= null;
			}
			else
			{
				val	= e.value;
				if ( ssr.string.isEmpty(val) || val == "undefined" )
				{
					var	opt	= e.options[e.selectedIndex];
					
					if ( opt.innerHTML )
					{
						val	= opt.innerHTML;
					}
					
					if ( ssr.string.isEmpty(val) && opt.text )
					{
						val	= opt.text;
					}
				}
			}
			break;
		
		case ssr.element.ttImage:
			val	= e.src;
			break;
			
		case ssr.element.ttAnchor:
			val	= e.href;
			break;
			
		default:
			val	= e.innerHTML;
		}
		return val;
	},

	setValue : function ( name, value )
	{
		var	e	= ssr.element.get( name );
		
		// Make sure has type
		var	tagType	= ssr.element.getTagType( e );
		
		// Make sure is string
		value	= ""+value;
		
    	// Check type <<>>
    	switch ( tagType )
    	{
		case ssr.element.ttInput:
		case ssr.element.ttInputPassword:
		case ssr.element.ttInputText:
		case ssr.element.ttInputHidden:
		case ssr.element.ttInputTextArea:
    		e.value	= value;	
    		break;
		case ssr.element.ttInputCheckBox:
		case ssr.element.ttInputRadio:
			if ( value.toLowerCase() == "true" )
			{
				e.checked = true;
			}
			else
			{
				e.checked	= false;
			}
			break;
		case ssr.element.ttInputSelect:
			this.selectOptionByValue( e, value );
			break;
		case ssr.element.ttImage:
        	e.src	= value;
        	break;
		case ssr.element.ttAnchor:
        	e.href	= value;
        	break;
        case ssr.element.ttInputButton:
        	// can't set buttons innerHTML for IE
        	break;
        default:
        	if ( ssr.types.isMember( e, 'innerHTML' ) )
        	{
 		  		e.innerHTML	= value;
 		  	}
 		  	else if ( ssr.types.isMember( e, 'value' ) )
 		  	{
 		  		e.value	= value;
 		  	}
 		}
    },
    
    // Focus
    setFocus : function( name )
	{
		ssr.element.get(name).focus();
	},

	enable	: function( name, doEnable )
	{
		ssr.element.get(name).disabled	= (! doEnable );
	},
	
    // Remove loading element if exists
    loadComplete : function()
    {
    	var	e	= ssr.element.get("ssrLoadBlocker");
    	if ( e )
    	{
    		e.innerHTML	= "";
			e.style.width		= '0px';
			e.style.height		= '0px';
			e.style.display	= 'none';    		
    	}
    }
};

// Table functions
ssr.element.table = {
	getRowCount : function( tableId )
	{
		return ssr.element.get( tableId ).rows.length;
	},
	
	addRow : function( tableId, rowIndex, cellValues )
	{
		var	table	= ssr.element.get( tableId );
		var	row		= table.insertRow( rowIndex );
		
		for ( i=0; i<cellValues.length; i++ )
		{
			var	cell	= row.insertCell(-1);
			cell.innerHTML	= cellValues[i];
		}
		return row;
	},
	
	deleteLastRow : function(tableId)
	{
		ssr.element.get( tableId ).deleteRow( -1 );
	},
	
	getRow : function( tableId, rowIndex )
	{
		return ssr.element.get(tableId).rows[rowIndex];
	},
	
	getCell : function( tableId, rowIndex, cellIndex )
	{
		return ssr.element.get(tableId).rows[rowIndex].cells[cellIndex];
	},
	
	getCellValue : function( tableId, rowIndex, cellIndex )
	{
		var	cell	= ssr.element.table.getCell( tableId, rowIndex, cellIndex );
		return cell.innerHTML;
	},
	
	setCellValue : function( tableId, rowIndex, cellIndex, value )
	{
		var	cell	= ssr.element.table.getCell( tableId, rowIndex, cellIndex );
		cell.innerHTML	= value;
	},
	
	makeSortable : function( tableId )
	{
		var	list;
		var	table	= ssr.element.get(tableId);
		
		// Get thead and set all td's 
		list	= table.getElementsByTagName('thead');
		if ( list.length == 0)
			throw "No thead defined";
		thead	= list[0];
		
		list	= table.getElementsByTagName('tbody');
		tbody	= list[0];
		
		// Loop thru all cells and make them clickable to help sort
		headCells = thead.rows[0].cells;
		for (i=0; i<headCells.length; i++ )
		{
			if ( ssr.element.hasClass( headCells[i], "sort_none" ) )
				continue;
			ssr.event.addListener( headCells[i], 'click', ssr.element.table.onClickSort, { table: table, head: thead, cellIndex: i, target: headCells[i], body : tbody } ); 
		}
	},
	
	sortRowCompare : function(a,b) 
	{
		if ( a.key > b.key )
			return 1;
		else
		if ( b.key > a.key )
			return -1;
		else
			return 0;
	},
	
	onClickSort : function()
	{
		var	i,
			info	= this.scope;	// Scope is set to { table, cell }
		
		var	newSort	= false,
			asc	= true;
		// See if is sorted already, reverse
		if ( ssr.element.hasClass( info.target, "sort_desc" ) )
			asc	= false;
		else
		if ( ssr.element.hasClass( info.target, "sort_asc" ) )
			asc	= true;
		else
			newSort	= true;
			
		// Loop and clear classes for all header cells
		for ( i=0; i<info.head.rows[0].cells.length; i++ )
		{
			cell	= info.head.rows[0].cells[i];
			ssr.element.removeClass( cell, "sort_asc" );
			ssr.element.removeClass( cell, "sort_desc" );
		}
		
		if ( asc )
			ssr.element.addClass( info.target, "sort_asc" );
		else
			ssr.element.addClass( info.target, "sort_desc" );
		
		var key,
			rows	= [];
		
		// Build row and key
		for (i=0; i<info.body.rows.length; i++ )
		{
			key	= info.body.rows[i].cells[info.cellIndex].innerHTML;
			key = key.replace(/<\/?[^>]+(>|$)/g, "");
			rows[i]	= { key:key, row:info.body.rows[i] };
		}
		
		// Now sort by it
		if ( newSort )
		{
			rows.sort( ssr.element.table.sortRowCompare );
			// Now put them back in
			for (i=0; i<rows.length; i++ )
			{
				info.body.appendChild( rows[i].row );
			}
		}
		else
		{
			// Just reverse
			for (i=rows.length-1; i>=0; i-- )
			{
				info.body.appendChild( rows[i].row );
			}
		}
				
	}
};

//---------------------------------------------------------------
// Dialog: Simple layer dialog
ssr.dialog =
{
	getInfo : function( name )
	{
		// See if is dialog already
		var	e	= ssr.element.get(name);
		if ( !e )
			throw "Cannot find dialog name:"+name;

		var	dialogInfo	= e["dialogInfo"];
		if ( !dialogInfo )
		{
			e["dialogInfo"]	= 
			{ 
				name: name, 
				element: e,
				isShown: false,
				type: null, 
				target: null, 
				offset: 0, 
				matchSide: null,
				autoPosition: null
			};
		}
		
		return e["dialogInfo"];
	},
	
	isShown : function( name )
	{
        var	dialogInfo	= ssr.dialog.getInfo( name );
		return dialogInfo.isShown;
	},
	
	show : function( name, type, target, offset, matchSide )
	{
        var	dialogInfo	= ssr.dialog.getInfo( name );
        dialogInfo.name			= name;
        dialogInfo.element		= ssr.element.get( name );
        dialogInfo.isShown		= true;
        dialogInfo.type			= type;
        dialogInfo.target		= target;
        dialogInfo.offset		= offset;
        dialogInfo.matchSide	= matchSide;

        ssr.dialog.repositionDialog( dialogInfo.element );

        ssr.element.show( dialogInfo.element );
        // Some browser needs to be position after shown
        ssr.dialog.repositionDialog( dialogInfo.element );
        
        		// Some types needs listener
        if ( dialogInfo.type == "center" || dialogInfo.type == "hcenter" )
        {
        	dialogInfo.autoPosition	= true;
        }
        
        // If autoposition is needed, set listener
        if ( dialogInfo.autoPosition )
        {
			ssr.event.addListener( window, 'scroll', ssr.dialog.repositionDialog, name ); 
			ssr.event.addListener( window, 'resize', ssr.dialog.repositionDialog, name ); 
        }
        
        // Add it back
        dialogInfo.element["dialogInfo"]	= dialogInfo;
        
        return dialogInfo;
	},
	
	enableSelfDismiss : function( dialogInfo )
	{
		dialogInfo.selfDismiss	= true;
		
		// Set dialog to focus and then check for loose focus
		//ssr.element.setFocus( dialogInfo.element );
		
		dialogInfo.element.onmouseout = function(param1)
		{
			// Make sure it is not inside our contain
			e	=	ssr.event.getEvent( param1 );
			
			if (e.target.nodeName != 'DIV') return;
			var relTarget = (e.relatedTarget) ? e.relatedTarget : e.toElement;
			if ( ssr.element.isChildOf( relTarget, dialogInfo.element ) )
				return;
			
			ssr.dialog.hide( dialogInfo.element );
		};
	},
	
	hide : function( name )
	{
        var	dialogInfo	= ssr.dialog.getInfo( name );
        
        // For types that added listener, remove them when done
        if ( dialogInfo.autoPosition )
        {
       		ssr.event.removeListener( window, 'scroll' ); 
			ssr.event.removeListener( window, 'resize' ); 
        }
        
		ssr.element.hide( name );
        dialogInfo.isShown		= false;
	},
		
	repositionDialog : function(scope)
    {
        var	dialogInfo	= ssr.dialog.getInfo( scope );
        if ( dialogInfo.type == "center" )
        {
        	ssr.element.moveToCenter( dialogInfo.name );
    	}
        else
        if ( dialogInfo.type == "hcenter" )
        {
		 	var	pos	= ssr.element.getCenterPosition( dialogInfo.name );
	 		pos.x	= null; // Don't change x, just y
	 		ssr.element.setPosition( dialogInfo.name, pos );
	 	}
        else 
        if ( dialogInfo.target )
        {
        	ssr.element.moveNextTo( dialogInfo.name, dialogInfo.type, dialogInfo.target, dialogInfo.offset, dialogInfo.matchSide );
        }
    	
    }
        		
        	
};

//---------------------------------------------------------------
// ssr.types: Utilities or handling javascript types
ssr.types =
{
	// isArray: Returns true if the obj is an array
	isArray : function (obj) 
	{
		// This old way does not work with Safari
		// return (obj.constructor.toString().indexOf("Array") != -1);
		return ( obj instanceof Array );
	},
	
	isFunction : function(obj)
	{
		return ( typeof obj == "function" );
	},
	
	isString : function(obj)
	{
		return ( obj.match );
	},
	
	isDefined : function( variableName )
	{
    	return (typeof(window[variableName]) == "undefined")?  false: true;
	},
	
	isMember: function( obj, variableName )
	{
    	return (typeof(obj[variableName]) == "undefined")?  false: true;
	}
	
};


//---------------------------------------------------------------
// Singleton: 
ssr.singleton = {
	list	: new Array(),
	key		: 0,
	
	add : function( obj, name )
	{
		if ( !name )
		{
			name	= "SK"+ssr.singleton.key;
		}
		ssr.singleton.list[name]	= obj;
		ssr.singleton.key += 1;
		
		return name;
	},

	get : function( name )
	{
		return ssr.singleton.list[name];
	},
	
	pop : function( name )
	{
		var	o	= ssr.singleton.get( name );
		ssr.singleton.remove( name );
		return o;
	},
	
	remove : function( name )
	{
		ssr.singleton.list
	}
};

//---------------------------------------------------------------
// ssr.timer: Timers
ssr.timer = {
	onTimer : function( timerId )
	{
		var	obj	= ssr.singleton.pop( timerId );
		obj.onTimer(timerId);
	}
};

ssr.timer.OneOffTimer = function(durationMs,scope)
{
	this.durationMs	= durationMs;
	this.timerId	= null;
	this.key		= ssr.singleton.add( this );
	this.scope		= scope;
	this.running	= false;
	
	this.getKey	= function()
	{
		return this.key;
	};
	
	this.isRunning = function()
	{
		return this.running;
	};
	
	this.start = function()
	{
		// If started, cancel first
		this.cancel();
		
		this.timerId	= setTimeout( "ssr.timer.onTimer('"+this.key+"');", this.durationMs );
		this.running	= true;
		
		return this.key;
	};
	
	this.onTimerInternal = function()
	{
		this.running	= false;
		if ( !this.onTimer )
			throw "Timer handler not defined";

		this.onTimer();
	};
	
	this.cancel = function()
	{
		if ( !this.timerId )
			return;
		clearTimeout( this.timerId );	
		this.timerId	= null;
	};
};

ssr.timer.RepeatTimer = function(durationMs,scope)
{
	//if ( durationMs < 100 )
	//{
	//	throw new "Timer too fine:"+durationMs;
	//}
	this.durationMs	= durationMs;
	this.timerId	= null;
	this.key		= ssr.singleton.add( this );
	this.scope		= scope;
	
	this.getKey	= function()
	{
		return this.key;
	};
	
	this.start = function()
	{
		this.timerId	= setInterval( "ssr.timer.onTimer('"+this.key+"');", this.durationMs );
		return this.key;
	};
	
	this.cancel = function()
	{
		var	obj	= ssr.singleton.pop( this.key );
		clearInterval( this.timerId );	
	};
};


//---------------------------------------------------------------
// ssr.xml: XML and DOM utilities
ssr.xml = {
	// load: Deprecated.
	//		Our own load XML function. Predates YUI.	
	load : function( url, func )
	{
		//load xml file
		// code for IE
		var	xmlDoc;
		if ( ssr.browser.isIE() )
		{
			xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
			xmlDoc.async=false;
			xmlDoc.load(url);
			func();
		}
		// code for Mozilla, Firefox, Opera, etc.
		else if (document.implementation && document.implementation.createDocument)
		{
			xmlDoc=document.implementation.createDocument("","",null);
			xmlDoc.load(url);
			xmlDoc.onload=func;
		}
		else
		{
			alert('Fatal: Your browser cannot handle XML Parsing');
		}
		return xmlDoc;
	},
	
	// parseXml: Deprecated
	//		Our own load XML parsing for reply. Predates YUI.	
	parseXml : function( xmlStr )
	{
		var	doc;
		if (ssr.browser.isIE())
		{
			doc	= new ActiveXObject("Microsoft.XMLDOM");
			doc.loadXML( xmlStr );
		}
		// code for Mozilla, Firefox, Opera, etc.
		else if (document.implementation && document.implementation.createDocument )
		{
			doc	= (new DOMParser()).parseFromString(xmlStr, "text/xml");
		}
		else
		{
			throw "Fatal: Your browser cannot handle XML Parsing";
		}
		return doc;
	}
};


//---------------------------------------------------------------
// ssr.string: String util
ssr.string =
{
	isEmpty : function( str )
	{
		if ( !str )
		{
			return true;
		}
		return str.match( /^[ \t\n\r]*$/ );
	},
	
	rtrim : function( str )
	{
		if ( !str )
			return "";
		var	re	= /^\s*/;
		return str.replace( re, "" );
	},
	
	ltrim : function ( str )
	{
		if ( !str )
			return "";
		var	re	= /\s*$/;
		return str.replace( re, "" );
	},
	
	trim : function( str )
	{
		if ( !str )
			return "";
		return ssr.string.ltrim( ssr.string.rtrim( str ) );
	},
	
	removeDuplicateSpaces : function( str )
	{
		return str.replace( / +/g, " " );
	}
		
};


//---------------------------------------------------------------
// SsrClass: Class utilities 
ssr.classUtil	=
{
	cloneObject : function( obj )
	{
		var	i;
		var	newObj	= new obj.constructor();
		for ( i in obj )
		{
			newObj[i]	= obj[i];
		}
		return newObj;
	}
};

//---------------------------------------------------------------
// ssr.url: URL parsers
ssr.url =
{
	// getParameter: Returns a parameter from the current url
	getParameter : function( name, url )
	{
		if ( !url )
		{
			url	= window.location.href;
		}
		
		name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
		var regexS = "[\\?&]"+name+"=([^&#]*)";
		var regex = new RegExp( regexS );
		var results = regex.exec( url );
		if( results == null )
		{
			return null;
		}
		else
		{
			var	val	= unescape(results[1]);
			return val.replace( /[+]/, " " );
		}
	}
}

//---------------------------------------------------------------
// net: Network classes
ssr.net	= {};

//---------------------------------------------------------------
// Request: A HTTP async/sync request
ssr.net.Request = function( url, async, timeout )
{
	// ctor (first part)
	this.url	= url;
	this.async	= async;
	this.timeout	= ( timeout ) ? timeout : 60000;
	this.timer		= null;
	
	// States
	this.timedOut	= false;
	this.aborted	= false;
		
	// get a httprequest object
	this.getHttpRequest = function()
	{
		var	xhr = null;
		if (window.XMLHttpRequest)     // Object of the current windows
		{ 
    		xhr = new XMLHttpRequest();     // Firefox, Safari, ...
		} 
		else 
 		if (window.ActiveXObject)   // ActiveX version
 		{
    		xhr = new ActiveXObject("Microsoft.XMLHTTP");  // Internet Explorer 
 		} 
 		return xhr;
	};

	// Place holder just in case forgot to overwrite by user
	this.onResponse = function()
	{
	};
	
	
	this.abort	= function()
	{
		this.aborted	= true;
		this.cancelTimer();
		this.request.abort();
	};

	// timer
	this.onTimer = function()
	{
		this.cancelTimer();
		this.timedOut	= true;
		this.onResponse();
	};
	
	this.startTimer = function()
	{
		this.timer	= new ssr.timer.OneOffTimer( this.timeout );
		this.timer.onTimer	= this.onTimer;
		this.timer.start();
	};
	
	this.cancelTimer = function()
	{
		try
		{
			this.timer.cancel();
		}
		catch (e) {}
	};
		
	// do a post
	this.postOrGet = function( isPost, params )
	{
		// Reset states
		this.timedOut	= false;
		this.aborted	= false;

		this.request					= this.getHttpRequest();
		this.request.ssrRequestObject	= this;
		
		this.request.onreadystatechange = this.onStateChange;

		if ( this.async )
		{
			this.startTimer();
		}
		
		this.request.open( (isPost)?'POST':'GET', this.url, this.async );
		if ( !isPost )
		{
			params	= null;
		}
		this.request.send(params);
		
	};

	this.doPost = function( params )
	{
		this.postOrGet( true, params );
	};
	
	this.doGet = function()
	{
		this.postOrGet( false, null );
	};
	
	// Sets the request header var
	this.setHeader = function( name, value )
	{
		this.request.setRequestHeader( name, value ); 
	};
	
	// This is use for internal wrapper only
	// Is called when the state changed on the call
	// Then it's delegated to other calls
	this.onStateChange = function(a,b,c)
	{
		try
		{
			var	self	= this.ssrRequestObject;
			var	state	= self.request.readyState;
			//alert( state );
			if( state == 4)
			{
				try { self.cancelTimer(); } catch(e) {}
				try { self.onResponse(); } catch(e) {}
			}
		}
		catch (e) { alert( e ); }
	};

	this.isTimedOut = function()
	{
		return this.timedOut;
	};
	
	this.isAborted = function()
	{
		return this.aborted;
	};
	
	this.getStatus = function()
	{
		return this.request.status;
	};
	
	this.isSuccessful = function()
	{
		return ( this.isTimedOut() || this.isAborted() || this.getStatus() != 200) ? false : true;
	};
	
	this.getResponseText = function()
	{
		return this.request.responseText;
	};
	
	this.getResponseXml = function()
	{
		return this.request.responseXML;
	};
	
};

//---------------------------------------------------------------
// Form: Form handling code
ssr.form	= {};

ssr.form.inputs	= 
{
	// Consts
	normalClass 	: "ssr.form.inputValid",
	exampleClass	: "ssr.form.inputExample",
	errorClass		: "ssr.form.inputError",

	inputs : new Array(),
	
	
	add : function(input)
	{
		ssr.form.inputs.inputs[input.id]	= input;
	},
	
	get : function( name )
	{
		return ssr.form.inputs.inputs[name];
	},
	
	getValue : function( name )
	{
		return ssr.form.inputs.get( name ).getValue();
	},
	
	setValue : function( name, value )
	{
		return ssr.form.inputs.get( name ).setValue(value);
	},
	
	addByNames : function( names )
	{
		var	input;
		for ( i in names )
		{
			name	= names[i];
			input	= new ssr.form.input( name );
			ssr.form.inputs.inputs[input.id]	= input;
		}
	},
	
	getAll : function()
	{
		return ssr.form.inputs.inputs;
	},
	
	checkAll : function()
	{
		for ( i in this.inputs )
		{
			try
			{
				ssr.form.inputs.inputs[i].checkConstraints();
			}
			catch(e) 
			{
				alert( "Check error:"+ e );
			}
		}
	},
	
	initAll : function()
	{
		for ( i in this.inputs )
		{
			try
			{
				ssr.form.inputs.inputs[i].init();
			}
			catch(e) {}
		}
	}
};

// Constraint Object
ssr.form.inputConstraint	= function( type, param, msg )
{
	this.notOpt	= false;
	this.param	= param;
	this.msg	= msg;
	this.valid	= false;
	
	// See if has operand
	if ( type.indexOf("!") == 0 )
	{
		this.notOpt	= true;
		type	= type.substring( 1 );	
	}
	
	this.type	= type;

	this.check = function()
	{
		return true;
	};

	this.check	= function( value )
	{
		// Loop and scan for all constraints
		var	i;

		var	src, dest;
		// What type of constraints
		var	result	= true;
		switch ( this.type )
		{
		case "none":
			break;
		case "null":
			if ( !ssr.string.isEmpty(value) )
			{
				result	= false;
			}
			break;
		case "match":
			dest	= ssr.element.getValue(this.param);
			if ( value != dest )
			{
				result	= false;
			}
			break;
		case "equal":
			if ( value != this.param )
			{
				result	= false;
			}
			break;
		case "regex":
			// If src is null, we let it go
			if ( ssr.string.isEmpty(value) )
			{
				break;
			}
			pat		= new RegExp(this.param);

			// cons.param;
			if ( !pat.exec(value) )
			{
				result	= false;
			}
			break;
		case "custom":
			if ( eval( this.param ) === false )
			{
				result	= false;
			}
			break;
		default:
			throw "SsrInputConstratin.check: unknown constraint type:"+cons.type;
		}
		
		if ( this.notOpt )
		{
			result	= !result;
		}
		
		this.valid	= result;
		return result;
	};
};


// Input Object
ssr.form.input	= function(e)
{
	this.element			= ssr.element.get(e);
	this.id					= this.element.id;
	this.tagType			= ssr.element.getTagType(this.element);
	this.constraints		= new Array();
	this.example			= null;
	this.exampleClass		= null;
	this.lastErrorMsg		= null;
	this.value				= null;
	this.onFocusCallback	= null;
	this.onBlurCallback		= null;
	this.enabled			= true;
	
	ssr.form.inputs.add( this );
	
	// tag it to element
	this.element.ssrInput	= this;
	
	// Constraints
	this.addConstraint = function( con )
	{
		this.constraints.push( con );
	};
	
	this.removeAllConstraints = function()
	{
		this.constraints = new Array();
	};
	
	// Set example
	this.setExample = function( msg, cls )
	{
		this.example		= msg;
		this.exampleClass	= cls;
	};

	// Classes
	this.clearClasses = function()
	{
		// remove all field classes
		ssr.element.removeClass( this.element, ssr.form.inputs.errorClass );
		ssr.element.removeClass( this.element, this.exampleClass );
	};

	this.setFocus	= function()
	{
		ssr.element.setFocus(this.element);
	};
	
	// Error Handling/Presentation
	this.setError = function(msg)
	{
		ssr.element.addClass( this.element, ssr.form.inputs.errorClass );
		this.lastErrorMsg	= msg;
		// TBD
		//alert( this.id+":"+msg );
	},
	
	this.clearError = function()
	{
		this.clearClasses();
		this.lastErrorMsg	= null;
		
		// TBD
	},

	this.checkConstraints = function()
	{
		var	noErrors	= true;

		var	value		= ssr.element.getValue(this.element);
		
		// Check if field is still same as example
		if ( value == this.example )
		{
			value	= "";
			
			// Set it back so if you are submitting the form, example will not be submitted
			ssr.element.setValue( this.element, "" );
		}
		
		if ( this.enabled )
		{
			// Loop and scan for all constraints
			for ( i in this.constraints )
			{
				var	cons	= this.constraints[i];
				if ( !cons.check(value) )
				{
					this.setError( cons.msg );
					if ( this.onErrorCallback )
					{
						this.onErrorCallback( this, cons );
					}
					noErrors	= false;
				}
			}
		}
		
		if ( noErrors )
		{
			this.clearError();
		}
		return noErrors;
	};

	this.inErrorState = function()
	{
		return ssr.element.hasClass( this.element, ssr.form.inputs.errorClass );
	};
		
	this.inExampleState = function()
	{
		return ssr.element.hasClass( this.element, this.exampleClass );
	};

	//this.onFocus = function( e, obj )
	this.onFocus = function( self )
	{
		//var	self	= this.ssrInput;

		// See if has chain
		if ( self.onFocusCallback )
		{
			try { self.onFocusCallback(self); } catch (e) {}
		}

		var	value	= ssr.element.getValue( self.element );
		
		// See if field is in example state
		if ( self.inExampleState() )
		{
			// Clear field
			ssr.element.removeClass( self.element, self.exampleClass );
			if ( value == self.example ) self.setValue( "" );
		}
		if ( self.inErrorState() )
		{
			// Revert to saved value, this is needed since we display errors in the input field itself
			ssr.element.removeClass( self.element, ssr.form.inputs.errorClass );
		}

	};
	
	// this.onBlur = function( e, obj )
	this.onBlur = function( self )
	{
		// var	self	= this.ssrInput;
		// Check constraint for just this field
		self.checkConstraints();
		
		// See if has chain
		if ( self.onBlurCallback )
		{
			self.onBlurCallback(self);
		}
	};

	this.getValue = function()
	{
		return ( this.inExampleState() ) ? "" : ssr.element.getValue(this.element);
	};
	
	this.setValue = function(value)
	{
		this.clearError();
		ssr.element.setValue(this.element,value);
	};

	// If set, if enter automatically submit form for input, or others
	this.enableAutoSubmit = function()
	{
		if ( this.tagType == ssr.element.ttInputText )
		{
			// Add event to auto submit
			ssr.event.addListener( this.element, "keydown", ssr.form.onEnterSubmit, this );
		}
		else
		{
			ssr.event.addListener( this.element, "click", ssr.form.onClickSubmit, this );
		}
	};
	
	this.init = function()
	{
		// ssr.element.clearClass( this.element );
		var	oldValue	= ssr.element.getValue( this.element );
		
		// Make sure is string
		var	isEmtpy;
		if ( ssr.types.isString( oldValue ) )
		{
			isEmpty		= ssr.string.isEmpty(oldValue);
		}
		else
		if ( oldValue === false )
			isEmpty		= true;
				
		// See if has example
		if ( this.example && ( isEmpty || oldValue === this.example ) )
		{
			// fld.element.className	= ssr.form.inputExampleClass;
			ssr.element.addClass( this.element, this.exampleClass );
			ssr.element.setValue( this.element, this.example );
		}
		else
		{
			ssr.element.removeClass( this.element, this.exampleClass );
		}
		
		// Add listeners
		ssr.event.addListener( this.element, "focus", this.onFocus, this );
		ssr.event.addListener( this.element, "blur", this.onBlur, this );
	};
};

// Submit a form, but check call back
ssr.form.submit = function( name )
{
	var	e	= ssr.element.get(name);
	
	// See if has special submit
	if ( e.onsubmit )
	{
		eval( e.onsubmit );
	}
	else
	{
		e.submit();
	}
};

// Use this on inputs, set onKeyDown to submit for on keydown
// Like so onkeydown='ssr.form.onEnterSubmit();'
ssr.form.onClickSubmit = function(scope,event)
{
	// Find form
	var	form	= ssr.form.getParentByTagName( "FORM" );
	if ( form )
	{
		alert( "Found form="+form.name );
		ssr.form.submit( form );
	}
	return false;
};

ssr.form.onEnterSubmit = function(scope,event)
{
	if ( !event ) return false;
	
	if (event.keyCode == 13) 
	{
		ssr.form.onClickSubmit();
	}
	
	return false;
};

//--------------------------------
// Simple OnClick/RemoveExample
ssr.form.simpleInputExample =
{
	onFocus : function( name, className, example )
	{
		if ( ssr.element.getValue(name) == example )
			ssr.element.setValue(name,"");
		ssr.element.removeClass( name, className );
	},
	
	onBlur : function( name, className, example )
	{
		if ( ssr.element.getValue(name) == "" )
			ssr.element.setValue(name,example);
		ssr.element.addClass( name, className );
	}
};

//-------------------------------------------------------------------------
// Animation

// Base class for a sequence
ssr.animate	= {};
ssr.animate.sequenceBase = function( name, interval )
{
	this.name		= name;
	this.interval	= (interval)?interval:500;
	this.timer		= new ssr.timer.RepeatTimer(this.interval,this);
	this.timer.parent	= this;
	this.index		= 0;
	this.completed	= false;
	this.onComplete	= null;
	this.onTimer	= null;
	this.onStart	= null;
	this.onStop		= null;
	this.onComplete	= null;
	this.state		= "init";
	
	this.start = function()
	{
		if ( this.state == "running" )
			this.stop();
	
		this.index		= 0;
		this.completed	= false;
		this.state		= "running";
		
		// See if has callback
		if ( this.onStart )
		{
			this.onStart();
		}
		
		// Run first one in thread
		this.timer.onTimer(null,this);
			
		// Start timer if not completed (like no task)
		this.timer.start();
	};
	
	this.timer.onTimer = function() 
	{
		this.parent.index	+= 1;
		
		// See if has callback
		try
		{
			if ( this.parent.onTimer )
			{
				this.parent.onTimer();
			}
		}
		catch ( e)
		{
			alert( "OnTimer exception:"+e );
		}
	};
	
	this.notifyCompleted = function()
	{
		this.completed	= true;
		this.stop();
	};
	
	this.stop = function()
	{
		this.state	= "stopped";
		
		// Make sure it's running
		this.timer.cancel();

		// See if has callback
		if ( this.onStop )
		{
			this.onStop();
		}
	};
	
};

ssr.animate.multipleTargets = function(name,interval)
{
	this.parent	= ssr.animate.sequenceBase;
	this.parent( name, interval );	
	
	this.targets	= new Array();
	
	this.addTarget = function( id, effects )
	{
		if ( !effects )
			effects	= [];
		var	target	= { id: id, 
						effects : effects,
						index: 0, 
						state: "new",
						enabled: true
					 };
		
		this.targets[id]	=  target;
	};
	
	this.addEffect = function( id, effect )
	{
		var	target	= this.targets[id];
		ssr.array.add( target.effects, effect );
	}
	
	this.clear = function()
	{
		this.targets	= new Array();
	};

	// Virtual methods	
	this.onStart = function()
	{
		for ( i in this.targets )
		{
			var	target		= this.targets[i];
			target.index	= 0;
			target.state	= "new";
			if ( target.enabled )
			{
				for ( i in target.effects )
				{
					effect	= target.effects[i];
					if ( effect.enabled )
					{
						if ( effect.onStart )
							effect.onStart( target, effect );
						effect.completed	= false;
					}
					else
					{
						effect.completed	= true;
					}
				}
			}
		}
	};
	
	this.onTimer = function()
	{
		// Loop all the ones that are not completed
		var	allDone	= true;

		for ( i in this.targets )
		{
			var	target	= this.targets[i];
			
			target.state	= "progress";

			try
			{
				for ( i in target.effects )
				{
					effect	= target.effects[i];
					
					// Make sure not completed, and startIndex is larger than current index
					if ( effect.startIndex > target.index )
						allDone	= false;
					else
					if ( !effect.completed )
					{
						effect.onTimer( target, target.index - effect.startIndex );
						if ( !effect.completed )
							allDone	= false;
						else
						{
							// This one is done
							effect.onEnd( target );
						}
					}
				}
				target.index ++;
			}
			catch(e) 
			{
				alert( "Animate error: "+e );
			}
		}
		
		// See if we should end		
		if ( allDone === true )
		{
			this.notifyCompleted();
		}
	};
};

ssr.animate.effects	= {};

ssr.animate.effects.effectBase = function( name )
{
	this.name		= name;
	this.onStart	= null;
	this.onTimer	= null;
	this.onEnd		= null;
	this.completed	= false;
	this.enabled	= true;
	this.startIndex	= 0;
}

ssr.animate.effects.fade = function( count, fadeIn )
{
	this.parent	= ssr.animate.effects.effectBase;
	this.parent( "fadeOut" );
	
	this.count	= count;
	this.opStep	= 100 / count,
	this.fadeIn	= fadeIn;
	
	this.onStart	=	function(target) 
	{
		ssr.element.setOpacity(target.id, (this.fadeIn) ? 0 : 100 );
	};
	
	this.onTimer	= function(target,index) 
	{
		var	op	= index * this.opStep;
		if ( !this.fadeIn )
			op	= 100 - op;
		
		ssr.element.setOpacity( target.id, op );
		
		if ( index >= this.count )
			this.completed	= true;
	};
	
	this.onEnd		= function(target) 
	{
	};
	
};

ssr.animate.effects.resize = function(count,endSize)
{
	this.parent	= ssr.animate.effects.effectBase;
	this.parent( "resize" );	
	
	this.count	= count;
	this.endSize	= endSize;
		
	this.onStart	= function(target) 
	{
		this.startSize	= ssr.element.getSize( target.id );
		this.sizeDiff	= { 
				width: null,
				height: null
			}; 

		if ( this.endSize.width != null )
		{
			this.sizeDiff.width	= ( this.endSize.width - this.startSize.width ) / count;
		}
		if ( this.endSize.height != null )
		{
			this.sizeDiff.height	= ( this.endSize.height - this.startSize.height ) / count;
		}	
		// alert( "w="+this.sizeDiff.width+" h="+this.sizeDiff.height );
	};
	
	this.onTimer	= function(target,index) 
	{
		var newSize = { width: null, height: null };
						
		if ( this.sizeDiff.width != null )
		{
			newSize.width = this.startSize.width + ( index * this.sizeDiff.width );
			// alert( "New Width="+newSize.width );
		}
						
		if ( this.sizeDiff.height != null )
		{
			newSize.height = this.startSize.height + ( index * this.sizeDiff.height );
			// alert( "New Height="+newSize.height );
		}
		
		ssr.element.setSize( target.id, newSize );
		
		if ( index >= this.count )
			this.completed	= true;
	};
	
	this.onEnd		= function(target) 
	{
		ssr.element.setSize( target.id, this.endSize );
	};
};

ssr.animate.effects.move = function(count,endPos)
{
	this.parent	= ssr.animate.effects.effectBase;
	this.parent( "move" );	
	
	this.count	= count;
	this.endPos	= endPos;
				
	this.onStart	= function(target) 
	{
		this.startPos	= ssr.element.getPosition( target.id );
		alert( this.startPos.x );
		
		this.posDiff	= { 
				x: null,
				y: null
			}; 
	
		if ( this.endPos.x != null )
		{
			this.posDiff.x	= ( this.endPos.x - this.startPos.x ) / count;
		}
		if ( this.endPos.y != null )
		{
			this.posDiff.y	= ( this.endPos.y - this.startPos.y ) / count;
		}
	};
	
	this.onTimer	= function(target,index) 
	{
		var newPos = { width: null, height: null };
						
		if ( this.posDiff.x != null )
		{
			newPos.x = this.startPos.x + ( index * this.posDiff.x );
			// alert( "New Width="+newSize.width );
		}
						
		if ( this.posDiff.y != null )
		{
			newPos.y = this.startPos.y + ( index * this.posDiff.y );
			// alert( "New Width="+newSize.width );
		}
		
		ssr.element.setPosition( target.id, newPos );

		if ( index >= this.count )
			this.completed	= true;
	};
	
	this.onEnd		= function(target) 
	{
		ssr.element.setPosition( target.id, this.endPos );
	};
};

ssr.animate.effects.show = function(show, type, target, offset, matchSide )
{
	this.parent	= ssr.animate.effects.effectBase;
	this.parent( "show" );	
	
	this.show		= show;
	this.type		= type;
	this.target		= target;
	this.offset		= offset;
	this.matchSide	= matchSide;
				
	this.onStart	= function(target) 
	{
	};
	
	this.onTimer	= function(target,index) 
	{
		// Just do once
		this.completed	= true;
	
		// Do show
		if ( this.show )
		{
			ssr.dialog.show( target.id, this.type, this.target, this.offset, this.mathcSide );
			// alert( this.name+" Showing:"+target.id);
		}
		else
		{
			ssr.dialog.hide( target.id );
			// alert( this.name+" Hiding:"+target.id);
		}
	};
	
	this.onEnd		= function(target) 
	{
	};
};


// just a less egoistic name :)
var	scl	= ssr;



