// SpryAutoSuggest.js - version 0.5 - Spry Pre-Release 1.5
//
// Copyright (c) 2006. Adobe Systems Incorporated.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of Adobe Systems Incorporated nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// 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.

var Spry;
if (!Spry) Spry = {};
if (!Spry.Widget) Spry.Widget = {};

Spry.Widget.BrowserSniff = function()
{
	var b = navigator.appName.toString();
	var up = navigator.platform.toString();
	var ua = navigator.userAgent.toString();

	this.mozilla = this.ie = this.opera = r = false;
	var re_opera = /Opera.([0-9\.]*)/i;
	var re_msie = /MSIE.([0-9\.]*)/i;
	var re_gecko = /gecko/i;
	var re_safari = /safari\/([\d\.]*)/i;

	if (ua.match(re_opera)) {
		r = ua.match(re_opera);
		this.opera = true;
		this.version = parseFloat(r[1]);
	} else if (ua.match(re_msie)) {
		r = ua.match(re_msie);
		this.ie = true;
		this.version = parseFloat(r[1]);
	} else if (ua.match(re_safari)) {
		this.safari = true;
		this.version = 1.4;
	} else if (ua.match(re_gecko)) {
		var re_gecko_version = /rv:\s*([0-9\.]+)/i;
		r = ua.match(re_gecko_version);
		this.mozilla = true;
		this.version = parseFloat(r[1]);
	}
	this.windows = this.mac = this.linux = false;

	this.Platform = ua.match(/windows/i) ? "windows" :
					(ua.match(/linux/i) ? "linux" :
					(ua.match(/mac/i) ? "mac" :
					ua.match(/unix/i)? "unix" : "unknown"));
	this[this.Platform] = true;
	this.v = this.version;

	if (this.safari && this.mac && this.mozilla) {
		this.mozilla = false;
	}
};

Spry.is = new Spry.Widget.BrowserSniff();

Spry.Widget.AutoSuggest = function(region, suggestRegion, dataset, field, options)
{
	options = options || {};
	this.options = {};

	if (!this.isBrowserSupported())
		return;

	this.region = document.getElementById(region);
	if (!this.region)
		return;

	this.textElement = Spry.Widget.Utils.getFirstChildWithNodeNameAtAnyLevel(this.region, "INPUT");
	this.textElement.setAttribute('AutoComplete', 'off');
	this.suggestRegion = document.getElementById(suggestRegion);
	this.timerID = null;
	if (typeof dataset == "string"){
		this.dataset = window[dataset];
	}else{
		this.dataset = dataset;
	}
	this.field = field;
	if (typeof field == 'string' && field.indexOf(',') != -1)
	{
		field = field.replace(/\s*,\s*/ig, ',');
		this.field = field.split(',');
	}

	this.showSuggestClass = 'showSuggestClass';
	this.hideSuggestClass = 'hideSuggestClass';
	this.hoverSuggestClass = 'hoverSuggestClass';
	this.minCharsType = false;
	this.containsString = false;
	this.loadFromServer = false;
	this.urlParam = '';
	this.suggestionIsVisible = false;
	this.stopFocus = false;
	this.hasFocus = false;

	Spry.Widget.Utils.setOptions(this, options);
	Spry.Widget.Utils.setOptions(this.options, options);

	var self = this;
	// adding listeners to the text input to catch the text changes
	this._notifyKeyUp = function(e){ self.handleKeyUp(e)}
	this._notifyFocus = function(e){ if (self.stopFocus){ self.handleKeyUp(e);} self.hasFocus = true; self.stopFocus = false;}
	this._notifyMDown = function(e){ self.clickInList = true;}
	Spry.Widget.Utils.addEventListener(this.textElement, "keydown", this._notifyKeyUp, false); 
	Spry.Widget.Utils.addEventListener(this.textElement, "focus", this._notifyFocus, false);
	Spry.Widget.Utils.addEventListener(this.textElement, "drop", this._notifyKeyUp, false);
	Spry.Widget.Utils.addEventListener(this.textElement, "dragdrop", this._notifyKeyUp, false);
	
	// on opera the blur is triggered before onclick
	if (Spry.is.opera){
		this._notifyBlur = function(e) { setTimeout(function(){if (!self.clickInList){ self.showSuggestions(false); }else{ self.stopFocus = true; self.textElement.focus();} self.clickInList = false; self.hasFocus = false;}, 100)}
	}else{
		this._notifyBlur = function(e) { if (!self.clickInList){ self.showSuggestions(false); }else{ self.stopFocus = true; self.textElement.focus();} self.clickInList = false; self.hasFocus = false;}
	}
	Spry.Widget.Utils.addEventListener(this.textElement, "blur", this._notifyBlur, false);

	// we listen on the suggest region too
	Spry.Widget.Utils.addEventListener(this.suggestRegion, "mousedown", this._notifyMDown, false);
	
	// when data is changing we will decide if we will have to show the suggestions
	this.dataset.addObserver(
	{
		onDataChanged: function(el)
		{
				var data = el.getData();
				var val = self.getValue();
				if (data && (!self.minCharsType || val.length >= self.minCharsType) && (data.length > 1 || (data.length == 1 && self.childs[0] && self.childs[0].attributes.getNamedItem("spry:suggest").value != self.getValue())))
				{
					self.showSuggestions(true);
					return;
				}
				self.showSuggestions(false);
		}
	});
	
	// define some notification functions used later for each row in the list
	this._notifyNodeMOver = function(e, node)
	{ 
		var l = self.childs.length;
		for (var i=0; i<l; i++)
			if (self.childs[i] != node && Spry.Widget.Utils.hasClassName(self.childs[i], self.hoverSuggestClass))
			{
				Spry.Widget.Utils.removeClassName(self.childs[i], self.hoverSuggestClass);
				break;
			}
	};
	this._notifyNodeClick = function(e, value) {if (value){self.setValue(value);}};

	// prepare the suggest region
	Spry.Widget.Utils.makePositioned(this.suggestRegion);
	Spry.Widget.Utils.addClassName(this.suggestRegion, this.hideSuggestClass);

	// Set up an observer so we can attach our click behaviors whenever
	// the region is regenerated.
	var regionID = Spry.Widget.Utils.getElementID(suggestRegion);
	this._notifyDataset = { onPostUpdate: function() {
			self.attachClickBehaviors();
	}, onPreUpdate: function(){
			self.removeClickBehaviours();
	}};
	Spry.Data.Region.addObserver(regionID,this._notifyDataset);

	// clean up the widget when on page unload
	// Spry.Widget.Utils.addEventListener(window, 'beforeunload', function(){self.destroy()}, false);

	// make the first computation in case the textfield is not empty
	this.attachClickBehaviors();
	this.handleKeyUp(null);
	this.showSuggestions(false);
};

Spry.Widget.AutoSuggest.prototype.isBrowserSupported = function()
{
	return Spry.is.ie && Spry.is.v >= 5 && Spry.is.windows
		||
	Spry.is.mozilla && Spry.is.v >= 1.4
		||
	Spry.is.safari
		||
	Spry.is.opera && Spry.is.v >= 9;
};

Spry.Widget.AutoSuggest.prototype.getValue = function()
{
	if (!this.textElement)
		return '';
	return this.textElement.value;
};

Spry.Widget.AutoSuggest.prototype.setValue = function(str)
{
	if (!this.textElement)
		return;
	this.textElement.value = str;
	this.showSuggestions(false);
};

Spry.Widget.AutoSuggest.prototype.focus = function()
{
	if (!this.textElement)
		return;
	this.textElement.focus();
};

Spry.Widget.AutoSuggest.prototype.showSuggestions = function(doShow)
{
	if (this.region && this.isVisibleSuggestion() != doShow)
	{
		if (doShow && this.hasFocus)
				Spry.Widget.Utils.addClassName(this.region, this.showSuggestClass);
		else
				Spry.Widget.Utils.removeClassName(this.region, this.showSuggestClass);
	}
	this.suggestionIsVisible = Spry.Widget.Utils.hasClassName(this.region, this.showSuggestClass);
};

Spry.Widget.AutoSuggest.prototype.isVisibleSuggestion = function()
{
	return this.suggestionIsVisible;
};

Spry.Widget.AutoSuggest.prototype.handleKeyUp = function(e)
{
	if (this.timerID)
	{
		clearTimeout(this.timerID);
		this.timerID = null;
	}

	// If the user hit the escape key, hide the auto suggest menu!
	if (e && Spry.Widget.Utils.isSpecialKey(e))
	{
		this.handleSpecialKeys(e);
		return;
	}
	var self = this;
	if (!this.loadFromServer)
		this.timerID = setTimeout(function() { self.timerID = null; self.filterDataSet()}, 200);
	else
		this.timerID = setTimeout(function() { self.timerID = null; self.loadDataSet()}, 200); 
};

Spry.Widget.AutoSuggest.prototype.scrollVisible = function(el)
{
	if (typeof this.scrolParent == 'undefined')
	{
		var currEl = el;
		this.scrolParent = false;
		while	(!this.scrolParent)
		{
			var overflow = Spry.Widget.Utils.getStyleProp(currEl, 'overflow');
			if (!overflow || overflow.toLowerCase() == 'scroll')
			{
					this.scrolParent = currEl;
					break;
			}
			if (currEl == this.region) 
				break;
			
			currEl = currEl.parentNode;
		}
	}

	if (this.scrolParent != false)
	{
		var h = parseInt(Spry.Widget.Utils.getStyleProp(this.scrolParent, 'height'), 10);
		if (el.offsetTop < this.scrolParent.scrollTop)
			this.scrolParent.scrollTop = el.offsetTop;
		else if (el.offsetTop + el.offsetHeight > this.scrolParent.scrollTop + h)
		{
			// the 5 pixels make the latest option more visible.
			this.scrolParent.scrollTop = el.offsetTop + el.offsetHeight - h + 5;
			if (this.scrolParent.scrollTop < 0)
				this.scrolParent.scrollTop = 0;	
		}

	}
};

Spry.Widget.AutoSuggest.prototype.handleSpecialKeys = function(e){
 	switch (e.keyCode)
	{
		case 40: // Down key  
 		case 38: // Up Key
			if (!(this.childs.length > 0) || !this.getValue())
				return;	

			var prev = this.childs.length-1;
			var next = false;
			var found = false;
			var data = this.dataset.getData();
			if (this.childs.length > 1 || (data && data.length == 1 && this.childs[0] && this.childs[0].attributes.getNamedItem('spry:suggest').value != this.getValue()))
			{
				this.showSuggestions(true);
			}
			else
				return;	
			
			for (var k=0; k < this.childs.length; k++)
			{
				if (next)
				{
					Spry.Widget.Utils.addClassName(this.childs[k], this.hoverSuggestClass);
					this.scrollVisible(this.childs[k]);
					break;
				}
				if (Spry.Widget.Utils.hasClassName(this.childs[k], this.hoverSuggestClass))
				{
					Spry.Widget.Utils.removeClassName(this.childs[k], this.hoverSuggestClass);
					found = true;
					if (e.keyCode == 40)
					{
						next = true;
						continue;
					}
					else
					{
						Spry.Widget.Utils.addClassName(this.childs[prev], this.hoverSuggestClass);
						this.scrollVisible(this.childs[prev]);
						break;
					}
				}
				prev = k;
			}
			if (!found || (next && k == this.childs.length))
			{
				Spry.Widget.Utils.addClassName(this.childs[0], this.hoverSuggestClass);
				this.scrollVisible(this.childs[0]);
			}
			Spry.Widget.Utils.stopEvent(e);
			break;
		case 27: // ESC key
			this.showSuggestions(false);
			break;
		case 13: //Enter Key
			if (!this.isVisibleSuggestion()) 
				return;
			for (var k=0; k < this.childs.length; k++)
				if (Spry.Widget.Utils.hasClassName(this.childs[k], this.hoverSuggestClass))
				{
					var attr = this.childs[k].attributes.getNamedItem('spry:suggest');
					if (attr){
						this.setValue(attr.value);
						this.handleKeyUp(null);
					}
					// stop form submission
					Spry.Widget.Utils.stopEvent(e);
					return false;
				}
			break;
		case 9: //Tab Key
			this.showSuggestions(false);
	}
	return;
};

Spry.Widget.AutoSuggest.prototype.filterDataSet = function()
{
	var contains = this.containsString;
	var columnName = this.field;
	var val = this.getValue();

	if (this.previousString && this.previousString == val)
		return;

	this.previousString = val;

	if (!val || (this.minCharsType && this.minCharsType > val.length))
	{
		this.dataset.filter(function(ds, row, rowNumber) { return null; });
		this.showSuggestions(false);
		return;
	}

	var regExpStr = Spry.Widget.Utils.escapeRegExp(val);

	if (!contains)
	 	regExpStr = "^" + regExpStr;

	var regExp = new RegExp(regExpStr, "ig");
	
	if (this.maxListItems > 0)
		this.dataset.maxItems = this.maxListItems;

	var filterFunc = function(ds, row, rowNumber)
	{
		if (ds.maxItems >0  && ds.maxItems <= ds.data.length)
			return null;

		if (typeof columnName == 'object')
		{
			var l = columnName.length;
			for (var i=0; i < l; i++)
			{
				var str = row[columnName[i]];
				if (str && str.search(regExp) != -1)
					return row;
			}
		}
		else
		{
			var str = row[columnName];
			if (str && str.search(regExp) != -1)
				return row;
		}
		return null; 
	};

	this.dataset.filter(filterFunc);
	var data = this.dataset.getData();
	if (data && (!this.minCharsType || val.length >= this.minCharsType) && (data.length > 1 || (data.length == 1 && this.childs[0] && this.childs[0].attributes.getNamedItem('spry:suggest').value != val ))){
		this.showSuggestions(true);
		return;
	}
	this.showSuggestions(false);
};

Spry.Widget.AutoSuggest.prototype.loadDataSet = function()
{
	this.dataset.cancelLoadData();
	this.dataset.useCache = false;
	
	var val = this.getValue();
	if (!val || (this.minCharsType && this.minCharsType > val.length))
	{
		this.showSuggestions(false);
		return;
	}
	
	if (this.previousString && this.previousString == val)
	{
		var data = this.dataset.getData();
		if (data && (data.length > 1 || (data.length == 1 && this.childs[0].attributes.getNamedItem("spry:suggest").value != val))){
			this.showSuggestions(true);
		}else{
			this.showSuggestions(false);
		}
		return;
	}

	this.previousString = val;

	var url = Spry.Widget.Utils.addReplaceParam(this.dataset.url, this.urlParam, val);
	this.dataset.setURL(url);
	this.dataset.loadData();
};

Spry.Widget.AutoSuggest.prototype.addMouseListener =  function(node, value)
{
	var self = this;
	Spry.Widget.Utils.addEventListener(node, "click", function(e){ return self._notifyNodeClick(e, value); self.handleKeyUp(null);}, false); 
	Spry.Widget.Utils.addEventListener(node, "mouseover", function(e){ Spry.Widget.Utils.addClassName(node, self.hoverSuggestClass); self._notifyNodeMOver(e, node)}, false); 
	Spry.Widget.Utils.addEventListener(node, "mouseout", function(e){ Spry.Widget.Utils.removeClassName(node, self.hoverSuggestClass); self._notifyNodeMOver(e, node)}, false); 
};
Spry.Widget.AutoSuggest.prototype.removeMouseListener =  function(node, value)
{
	var self = this;
	Spry.Widget.Utils.removeEventListener(node, "click", function (e){ self._notifyNodeClick(e, value); self.handleKeyUp(null);}, false); 
	Spry.Widget.Utils.removeEventListener(node, "mouseover", function(e){ Spry.Widget.Utils.addClassName(node, self.hoverSuggestClass); self._notifyNodeMOver(e, node)}, false); 
	Spry.Widget.Utils.removeEventListener(node, "mouseout", function(e){ Spry.Widget.Utils.removeClassName(node, self.hoverSuggestClass); self._notifyNodeMOver(e, node)}, false); 
};
Spry.Widget.AutoSuggest.prototype.attachClickBehaviors =  function()
{
	var self = this;
	var valNodes = Spry.Utils.getNodesByFunc(this.region, function(node)
	{
		if (node.nodeType == 1) /* Node.ELEMENT_NODE */
		{
			var attr = node.attributes.getNamedItem("spry:suggest");
			if (attr){
				self.addMouseListener(node, attr.value);
				return true;
			}
		}
		return false;
	});
	this.childs = valNodes;
};
Spry.Widget.AutoSuggest.prototype.removeClickBehaviours = function()
{
	var self = this;
	var valNodes = Spry.Utils.getNodesByFunc(this.region, function(node)
	{
		if (node.nodeType == 1) /* Node.ELEMENT_NODE */
		{
			var attr = node.attributes.getNamedItem("spry:suggest");
			if (attr){
				self.removeMouseListener(node, attr.value);
				return true;
			}
		}
		return false;
	});
};
Spry.Widget.AutoSuggest.prototype.destroy = function(){
	this.removeClickBehaviours();
	Spry.Data.Region.removeObserver(Spry.Widget.Utils.getElementID(this.suggestRegion),this._notifyDataset);
	Spry.Widget.Utils.removeEventListener(this.textElement, "keydown", this._notifyKeyUp, false); 
	Spry.Widget.Utils.removeEventListener(this.textElement, "focus", this._notifyFocus, false);
	Spry.Widget.Utils.removeEventListener(this.textElement, "drop", this._notifyKeyUp, false);
	Spry.Widget.Utils.removeEventListener(this.textElement, "dragdrop", this._notifyKeyUp, false);
	Spry.Widget.Utils.removeEventListener(this.suggestRegion, "mousedown", this._notifyMDown, false);
	Spry.Widget.Utils.removeEventListener(this.textElement, "blur", this._notifyBlur, false);
	for (var k in this){
		if (typeof this[k] != 'function'){
			try { delete this.textElement; } catch(err) {}
		}
	}
};
//////////////////////////////////////////////////////////////////////
//
// Spry.Widget.Utils
//
//////////////////////////////////////////////////////////////////////
if (!Spry.Widget.Utils)	Spry.Widget.Utils = {};

Spry.Widget.Utils.specialSafariNavKeys = ",63232,63233,63234,63235,63272,63273,63275,63276,63277,63289,";
Spry.Widget.Utils.specialCharacters = ",9,13,27,38,40,";
Spry.Widget.Utils.specialCharacters += Spry.Widget.Utils.specialSafariNavKeys;

Spry.Widget.Utils.isSpecialKey = function (ev)
{
	return Spry.Widget.Utils.specialCharacters.indexOf("," + ev.keyCode + ",") != -1;
};
Spry.Widget.Utils.getElementID = function(el)
{
	if (typeof el == 'string' && el)
		return el;
	return el.getAttribute('id');
};
Spry.Widget.Utils.addReplaceParam = function(url, param, paramValue)
{
	var uri ='';
	var qstring = '';
	var i = url.indexOf('?')
	if ( i != -1)
	{
		uri = url.slice(0, i);
		qstring = url.slice(i+1);
	}
	else 
		uri = url;

	// the list of parameters
	qstring = qstring.replace('?', '');
	var arg = qstring.split("&");

	// prevent malicious use
	if (param.lastIndexOf('/') != -1)
		param = param.slice(param.lastIndexOf('/')+1);

	// remove param from the list
	for (i=0; i < arg.length ;i++)
	{
		var k = arg[i].split('=');
		if ( (k[0] && k[0] == decodeURI(param)) || arg[i] == decodeURI(param))
			arg[i] = null;
	}

	arg[arg.length] = encodeURI(param) + '=' + encodeURI(paramValue);
	qstring = '';
	// reconstruct the qstring
	for (i=0; i < arg.length; i++)
		if (arg[i])
			qstring += '&'+arg[i];

	// remove the first &
	qstring = qstring.slice(1);

	url = uri + '?' + qstring;
	return url;
};

Spry.Widget.Utils.addClassName = function(ele, clssName)
{
	if (!ele) return;

	if (!ele.className) ele.className = '';

	if (!ele || ele.className.search(new RegExp("\\b" + clssName + "\\b")) != -1)
	  return;

	ele.className += ' ' + clssName;
};

Spry.Widget.Utils.removeClassName = function(ele, className)
{
	if (!ele) return;	

	if (!ele.className)
	{
		ele.className = '';
		return;
	}
	ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), '');
};

Spry.Widget.Utils.hasClassName = function (ele, className)
{
	if (!ele || !className)
		return false;

	if (!ele.className)
		ele.className = '';

	return ele.className.search(new RegExp("\\s*\\b" + className + "\\b")) != -1;
};

Spry.Widget.Utils.addEventListener = function(el, eventType, handler, capture)
{
	try
	{
		if (el.addEventListener)
			el.addEventListener(eventType, handler, capture);
		else if (el.attachEvent)
			el.attachEvent("on" + eventType, handler, capture);
	}catch (e) {}
};

Spry.Widget.Utils.removeEventListener = function(el, eventType, handler, capture)
{
	try
	{
		if (el.removeEventListener)
			el.removeEventListener(eventType, handler, capture);
		else if (el.detachEvent)
			el.detachEvent("on" + eventType, handler, capture);
	}catch (e) {}
};

Spry.Widget.Utils.stopEvent = function(ev)
{
	ev.cancelBubble = true;
	ev.returnValue = false;

	try
	{
		this.stopPropagation(ev);
	}catch (e){}
	try{
		this.preventDefault(ev);
	}catch(e){}
};

/**
 * Stops event propagation
 * @param {Event} ev the event
 */
Spry.Widget.Utils.stopPropagation = function(ev)
{
	if (ev.stopPropagation)
		ev.stopPropagation();
	else
		ev.cancelBubble = true;
};

/**
 * Prevents the default behavior of the event
 * @param {Event} ev the event
 */
Spry.Widget.Utils.preventDefault = function(ev)
{
	if (ev.preventDefault)
		ev.preventDefault();
	else
		ev.returnValue = false;
};

Spry.Widget.Utils.setOptions = function(obj, optionsObj, ignoreUndefinedProps)
{
	if (!optionsObj)
		return;
	for (var optionName in optionsObj)
	{
		if (typeof ignoreUndefinedProps != 'undefined' && ignoreUndefinedProps && typeof optionsObj[optionName] == 'undefined')
			continue;
		obj[optionName] = optionsObj[optionName];
	}
};

Spry.Widget.Utils.firstValid = function()
{
	var ret = null;
	for (var i=0; i < Spry.Widget.Utils.firstValid.arguments.length; i++)
		if (typeof Spry.Widget.Utils.firstValid.arguments[i] != 'undefined')
		{
			ret = Spry.Widget.Utils.firstValid.arguments[i];
			break;
		}

	return ret;
};

Spry.Widget.Utils.camelize = function(stringToCamelize)
{
  var oStringList = stringToCamelize.split('-');
	var isFirstEntry = true;
	var camelizedString = '';

	for(var i=0; i < oStringList.length; i++)
	{
		if(oStringList[i].length>0)
		{
			if(isFirstEntry)
			{
				camelizedString = oStringList[i];
				isFirstEntry = false;
			}
			else
			{
				var s = oStringList[i];
				camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
			}
		}
	}

	return camelizedString;
};

Spry.Widget.Utils.getStyleProp = function(element, prop)
{
	var value;
	var camel = Spry.Widget.Utils.camelize(prop);
	try
	{
		value = element.style[camel];
		if (!value)
		{
			if (document.defaultView && document.defaultView.getComputedStyle)
			{
				var css = document.defaultView.getComputedStyle(element, null);
				value = css ? css.getPropertyValue(prop) : null;
			}
			else
				if (element.currentStyle)
					value = element.currentStyle[camel];
		}
	}
	catch (e) {}

	return value == 'auto' ? null : value;
};
Spry.Widget.Utils.makePositioned = function(element)
{
	var pos = Spry.Widget.Utils.getStyleProp(element, 'position');
	if (!pos || pos == 'static')
	{
		element.style.position = 'relative';

		// Opera returns the offset relative to the positioning context, when an
		// element is position relative but top and left have not been defined
		if (window.opera)
		{
			element.style.top = 0;
			element.style.left = 0;
		}
	}
};
Spry.Widget.Utils.escapeRegExp = function(rexp)
{
	return rexp.replace(/([\.\/\]\[\{\}\(\)\\\$\^\?\*\|\!\=\+\-])/g, '\\$1');
};
Spry.Widget.Utils.getFirstChildWithNodeNameAtAnyLevel = function(node, nodeName)
{
	var elements  = node.getElementsByTagName(nodeName);
	if (elements)
		return elements[0];
	
	return null;
};

