var Util = (function() {
	var instance = {
		customLog: true,
		log: function() {
			var logMe = [];
			for (var i = 0; i < arguments.length; i++) {
				if (typeof(arguments[i]) == "null" || typeof(arguments[i]) == "undefined") {
					logMe.push(typeof(arguments[i]));
				} else if (arguments[i] instanceof Object) {
					logMe.push(Util.serialize(arguments[i]));
				} else {
					logMe.push(arguments[i].toString());
				}
			}
			
			var logString = logMe.join(" ");
			
			if (window['console'] && console.log) {
				console.log(logString);
			}		
		},
		translateASCII: function(text){
		
			var translateArray = 
				new Array({"asciiValue":"&lt;","textValue":"<"}
						,{"asciiValue":"&gt;","textValue":">"}
						,{"asciiValue":"&quot;","textValue":"\""}
						,{"asciiValue":"&amp;","textValue":"&"}
						,{"asciiValue":"&#47;","textValue":"/"}
						,{"asciiValue":"\\\\\"","textValue":"\""}
						,{"asciiValue":"&#92;","textValue":"\\"}
						,{"asciiValue":"<br>","textValue":"\n"}
						,{"asciiValue":"&#039;","textValue":"\'"});
			
			var i=0;
			var len = translateArray.length;
			for(;i<len;i++){
				text = text.replace(new RegExp( translateArray[i].asciiValue , "g" ),translateArray[i].textValue);
			}
			
			return text;
		},
		// Serialize something
		// functionContext: if we are trying to serialize a function, call it in this context
		//     if functionContext is null, just return the function source
		serialize: function(item, functionContext) {
			var itemString = "";		
			if (item == null) {
				itemString = "null";
			} else if (item.constructor == String) {	
				itemString = '"' + item.replace(/"/g, "\\\"") + '"';
			} else if (item.serialize) {
				itemString = item.serialize();
			} else if (item.constructor == Array) {
				itemString = "[";
				for (var i = 0; i < item.length; i++) {
					itemString += arguments.callee(item[i]) + ",";
				}
				// remove trailing comma and add close bracket
				itemString = (itemString != "[") ? itemString.substr(0, itemString.length - 1) + "]" : "[]";
			} else if (item.constructor == Function) {
				itemString = functionContext ? item.apply(functionContext) : item.toString();
			} else if (typeof(item) == "number") {
				itemString += item;
			} else if (typeof(item) == "object" && item.toSource) {
				itemString += item.toSource();
				// Remove parentheses
				var match = /^\((.*)\)$/.exec(itemString);
				if (match)
					itemString = match[1];
			} else if (typeof(item) == "object") {
				itemString = "{";
				for (var prop in item) {
					itemString += prop + ":" + arguments.callee(item[prop]) + ",";
				}
				itemString = (itemString != "{") ? itemString.substr(0, itemString.length - 1) + "}" : "{}";
			} else {
				itemString += item;
			}

			return itemString;
		},
		
		
		clone: function(source, additives) {
			var obj = {};
			
			for (var key in source) {
				obj[key] = source[key];
			}
			
			if (additives) {
				for (var key in additives) {
					obj[key] = additives[key];
				}
			}
			
			return obj;
		},
		// Copies simple objects recursively.
		copyObj: function(object) {
			var newObj = {}; 
			$.each(object, function(name, value) {
				if (typeof(value) === 'object') {
					newObj[name] = Util.copyObj(value);
				}
				else {
					newObj[name] = value;
				}
			});
			
			return newObj;
		},		
		// get an array of all the item names in the object
		keys: function(obj) {
			var items = [];
			for (var item in obj) {
				items.push(item);
			}
			return items;
		},
		
		contents: function(obj) {
			var items = [];
			for (var item in obj) {
				items.push(item + ": " + obj[item]);
			}
			return items;
		},
		
		// Generate a naive, 18 character identifier
		simpleId: function() {
			var randNum = "";
			
			do {
				var randomSeed = Math.floor(Math.random()*93015432)%233280;
				randNum =( (randomSeed/233280.0)*100000000).toString();
				if(randNum.indexOf(".")>-1 ){
					randNum =randNum.replace(".","");
				}
			} while (randNum.length < 6 );
			
			randNum = randNum.substring(0,5);
			return ( randNum + "" + new Date().getTime() );	
			//return ((new Date()).getTime() + "" + Math.floor(Math.random() * 1000000)).substr(0, 18);
		},
		
		encodeURIContent:function(serializedNoteStr){
			serializedNoteStr = serializedNoteStr.replace(/\u000D/g,"<br/>");// carriage return
			serializedNoteStr = serializedNoteStr.replace(/\u000A/g,"<br/>");
			serializedNoteStr = serializedNoteStr.replace(/%/gi,"%25");		
			serializedNoteStr = serializedNoteStr.replace(/&/gi,"%26");		
			serializedNoteStr = serializedNoteStr.replace(/\+/gi,"%2B");			
					
			serializedNoteStr = serializedNoteStr.replace(/\\xA0/g," ");
			serializedNoteStr = serializedNoteStr.replace(/%0A/g," ");
			serializedNoteStr = serializedNoteStr.replace(/<br>/gi,"<br/>");			
				
			return serializedNoteStr;
		},
		
		myantiescape: function(labelText) {
			var tempText = labelText;
			tempText = tempText.replace(/&gt;/g,">");
			tempText =tempText.replace(/&lt;/g,"<");
			tempText = tempText.replace(/&amp;/g,"&");
			//labelText = labelText.replace(/&dbq/g,"\"")
			return tempText;
		},
		getDimensioAtBorder: function(value, obj){
			if(parseInt(value)<0)
				value = 0;
			else if( (parseInt(value)+ obj.getSize().width) > obj.parent.getSize().width )
				value = obj.parent.getSize().width - obj.getSize().width;
				
			return value;
		},
		
		getDOMElementText:function(textInput){
			var element =$("<div id='tempText'>"+textInput+"</div>");			
			return element.text();
		},
		
		// checks for intersection between two rectangles
		// first and second are objects like {left: 0, top: 0, right: 0, bottom: 0} or { left: 0, top: 0, width: 0, height: 0 }
		intersect: function(first, second) {
			first.right = first.right || first.left + first.width;
			first.bottom = first.bottom || first.top + first.height;
			second.right = second.right || second.left + second.width;
			second.bottom = second.bottom || second.top + second.height;
			return !(first.left > second.right
				|| first.right < second.left
				|| first.top > second.bottom
				|| first.bottom < second.top);
		},
		/*
			parseUri 1.2.1
			(c) 2007 Steven Levithan <stevenlevithan.com>
			MIT License
		*/
		 parseUri: function(str) {
			//var	o   = parseUri.options,
				m   =this.parser[this.strictMode ? "strict" : "loose"].exec(str),
				uri = {},
				i   = 14;
		
			while (i--) uri[this.key[i]] = m[i] || "";
		
			uri[this.q.name] = {};
			uri[this.key[12]].replace(this.q.parser, function ($0, $1, $2) {
				if ($1) uri[this.q.name][$1] = $2;
			});
			return uri;
		},	
		strictMode: false,
		key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
		q:   {
			name:   "queryKey",
			parser: /(?:^|&)([^&=]*)=?([^&]*)/g
		},
		parser: {
			strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
			loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
		},
		//**END parseUri**//
		isColor: function(color) {
			if (color == 'transparent') return true;
			else
			return /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(color);
		},
		ensureColor: function(color, defaultColor) {
			if (color == 'transparent' ) return color;
			if (!this.isColor(color)) {
				color = defaultColor;
			} else if (color.indexOf("#") != 0) {
				color = "#" + color;
			}
			return color;			
		},
		removeQuotes: function (val){				
				val = val.replace(/'|"/g,"");
				return val;
		},
		rgbToHex: function(rgbColor) {
			var hex = Util.ensureColor(rgbColor, "#ffffff"); // If it's already a hex color, pass through. Otherwise, make default #ffffff
			matches = rgbColor.match(/rgb\((\d*),.*?(\d*),.*?(\d*)\)/);
			if (matches) {
				hex = "#";
				hex += this.toHex(matches[1]);
				hex += this.toHex(matches[2]);
				hex += this.toHex(matches[3]);
			}
			
			return hex;
		},
		hexToRgb:function (hexColor){
			 
			  var   s   =   hexColor;  
			  if (s == 'transparent') s="#ffffff";
			  var   r   =   /^#([\da-f]{1,2})([\da-f]{1,2})([\da-f]{1,2})$/i;  
			  
			  var rgbObject = new Object();
			  if(r.test(s))   
			  {   
					  
					  rgbObject.r = parseInt(RegExp.$1,   16);					  
					  rgbObject.g = parseInt(RegExp.$2,   16);
					  rgbObject.b = parseInt(RegExp.$3,   16);
					  return rgbObject;
			  }
			  
			  return null;
			
		},
		toHex: function(N){
		 if (N==null) return "00";
		 N=parseInt(N); if (N==0 || isNaN(N)) return "00";
		 N=Math.max(0,N); N=Math.min(N,255); N=Math.round(N);
		 return "0123456789ABCDEF".charAt((N-N%16)/16)
		      + "0123456789ABCDEF".charAt(N%16);
		},
		replaceAll: function(replacements, template) {
			// Copy the string to a new variable
			var ret = template;
			$.each(replacements, function(from, to) {
				Util.log(from, to);
				ret.replace(from, to);
			});
			
			return ret;
		},
		 rg2hs: function(rg){
			var hs=new Object();
			m=rg.r;
			if(rg.g<m){m=rg.g};
			if(rg.b<m){m=rg.b};
			v=rg.r;
			if(rg.g>v){v=rg.g};
			if(rg.b>v){v=rg.b};
			value=100*v/255;
			delta=v-m;
			if(v==0.0){hs.s=0}else{hs.s=100*delta/v};
			if(hs.s==0){hs.h=0}
			else{
				
				if(rg.r==v){hs.h=60.0*(rg.g-rg.b)/delta}
				else if(rg.g==v){hs.h=120.0+60.0*(rg.b-rg.r)/delta}
				else if(rg.b=v){hs.h=240.0+60.0*(rg.r-rg.g)/delta}
			
				if(hs.h<0.0){hs.h=hs.h+360.0}
			
			}
			hs.v=Math.round(value);
			hs.h=Math.round(hs.h);
			hs.s=Math.round(hs.s);
			return hs;
		},		
		h2r: function(hs){
				var rg=new Object();
				if(hs.s==0){rg.r=rg.g=rg.b=Math.round(hs.v*2.55);return rg;}
				hs.s=hs.s/100;
				hs.v=hs.v/100;
				hs.h/=60;
				i=Math.floor(hs.h);
				f=hs.h-i;
				p=hs.v*(1-hs.s);
				q=hs.v*(1-hs.s*f);
				t=hs.v*(1-hs.s*(1-f));
				switch(i){
					case 0:rg.r=hs.v;
							rg.g=t;rg.b=p;
							break;
					case 1:rg.r=q;rg.g=hs.v;
							rg.b=p;
							break;
					case 2:rg.r=p;
							rg.g=hs.v;
							rg.b=t;
							break;
					case 3:rg.r=p;
							rg.g=q;
							rg.b=hs.v;
							break;
					case 4:rg.r=t;
							rg.g=p;
							rg.b=hs.v;
							break;
					default:rg.r=hs.v;
							rg.g=p;rg.b=q;
					}
					
					rg.r=Math.round(rg.r*255);
					rg.g=Math.round(rg.g*255);
					rg.b=Math.round(rg.b*255);
					return rg;
			},
		getColorPlan: function(hs){
			z=new Object();
			y=new Object();
			yx=new Object();
			function rc(x,m){
				if(x>m){return m}
				if(x<0){return 0}else{return x}
			}
						
			
			y.s=hs.s;
			y.h=hs.h;
			if(hs.v>70){y.v=hs.v-30}else{y.v=hs.v+30};
	
			//z=h2r(y);
			//PrintoutRecommendColor("1",z);
			return y;
			 
			if((hs.h>=0)&&(hs.h<30)){
				yx.h=y.h=hs.h+20;yx.s=y.s=hs.s;y.v=hs.v;
				if(hs.v>70){yx.v=hs.v-30}else{yx.v=hs.v+30}
			}
			
			if((hs.h>=30)&&(hs.h<60)){
				yx.h=y.h=hs.h+150;
				y.s=rc(hs.s-30,100);
				y.v=rc(hs.v-20,100);
				yx.s=rc(hs.s-70,100);
				yx.v=rc(hs.v+20,100);
			}
			
			if((hs.h>=60)&&(hs.h<180)){
				yx.h=y.h=hs.h-40;
				y.s=yx.s=hs.s;
				y.v=hs.v;
				if(hs.v>70){yx.v=hs.v-30}else{yx.v=hs.v+30}
			}
			
			if((hs.h>=180)&&(hs.h<220)){
				yx.h=hs.h-170;
				y.h=hs.h-160;
				yx.s=y.s=hs.s;
				y.v=hs.v;
				if(hs.v>70){yx.v=hs.v-30}else{yx.v=hs.v+30}
			}
			
			if((hs.h>=220)&&(hs.h<300)){
				yx.h=y.h=hs.h;
				yx.s=y.s=rc(hs.s-60,100);
				y.v=hs.v;
				if(hs.v>70){yx.v=hs.v-30}else{yx.v=hs.v+30}
			}
			
			if(hs.h>=300){
				if(hs.s>50){y.s=yx.s=hs.s-40}else{y.s=yx.s=hs.s+40}
				yx.h=y.h=(hs.h+20)%360;
				y.v=hs.v;
				if(hs.v>70){yx.v=hs.v-30}else{yx.v=hs.v+30}
			}
			
			//z=h2r(y);
			//PrintoutRecommendColor("2",z);
			
			/*
			z=h2r(yx);
			PrintoutRecommendColor("3",z);
			y.h=0;y.s=0;
			y.v=100-hs.v;
			z=h2r(y);
			PrintoutRecommendColor("4",z);
			y.h=0;y.s=0;
			y.v=hs.v;
			z=h2r(y);
			PrintoutRecommendColor("5",z);
			
			*/
		},
		smoothColor:function (rgb){
			rgb.g = rgb.g-30;
			rgb.r = rgb.r-30;
			rgb.b = rgb.b-30;
			
			if (rgb.g < 0 ) rgb.g = 0;
			if (rgb.r < 0 ) rgb.r = 0;
			if (rgb.b < 0 ) rgb.b = 0;
			return rgb;
		},
		getGrid:function (hexColor){
			var rgb = this.hexToRgb(hexColor);
			
			
			if (rgb.g>127 || rgb.r>127 || rgb.b>127){
				return this.smoothColor(rgb);
			
			}
			var hs = this.rg2hs(rgb);
			var y =  this.getColorPlan(hs);
			var newGrid = this.h2r(y);
			//alert("the new color is " +newGrid.r+","+newGrid.g+","+newGrid.b);
			return newGrid;
			
		},
		getHRBottomBorder:function (rgb){
	
			if (rgb.g>127 || rgb.r>127 || rgb.b>127){
				var colorTemp = this.smoothColor(rgb);
				var colorTempMarkup = "rgb("+colorTemp.r+","+colorTemp.g+","+colorTemp.b+")";
				return this.rgbToHex(colorTempMarkup);
			
			}
			var hs = this.rg2hs(rgb);
			var y =  this.getColorPlan(hs);
			var newGrid = this.h2r(y);
			var colorMarkup = "rgb("+newGrid.r+","+newGrid.g+","+newGrid.b+")";
			return this.rgbToHex(colorMarkup);
			
		},
		getElementPos:function (elementId) {

				var ua = navigator.userAgent.toLowerCase();
				var isOpera = (ua.indexOf('opera') != -1);
				var isIE = (ua.indexOf('msie') != -1 && !isOpera); // not opera spoof
			
				var el = document.getElementById(elementId);
				//check if el is null
				if (el == null){
					return false;	
				}
				if(el.parentNode === null || el.style.display == 'none') 
				{
					return false;
				}
			
				var parent = null;
				var pos = [];
				var box;
			
				if(el.getBoundingClientRect)	//IE
				{
					box = el.getBoundingClientRect();
					var scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
					var scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
			
					return {x:box.left + scrollLeft, y:box.top + scrollTop};
				}
				else if(document.getBoxObjectFor)	// gecko
				{
					box = document.getBoxObjectFor(el);
					   
					var borderLeft = (el.style.borderLeftWidth)?parseInt(el.style.borderLeftWidth):0;
					var borderTop = (el.style.borderTopWidth)?parseInt(el.style.borderTopWidth):0;
			
					pos = [box.x - borderLeft, box.y - borderTop];
				}
				else	// safari & opera
				{
					pos = [el.offsetLeft, el.offsetTop];
					parent = el.offsetParent;
					if (parent != el) {
						while (parent) {
							pos[0] += parent.offsetLeft;
							pos[1] += parent.offsetTop;
							parent = parent.offsetParent;
						}
					}
					if (ua.indexOf('opera') != -1 
						|| ( ua.indexOf('safari') != -1 && el.style.position == 'absolute' )) 
					{
							pos[0] -= document.body.offsetLeft;
							pos[1] -= document.body.offsetTop;
					} 
				}
					
				if (el.parentNode) { parent = el.parentNode; }
				else { parent = null; }
			  
				while (parent && parent.tagName != 'BODY' && parent.tagName != 'HTML') 
				{ // account for any scrolled ancestors
					pos[0] -= parent.scrollLeft;
					pos[1] -= parent.scrollTop;
			  
					if (parent.parentNode) { parent = parent.parentNode; } 
					else { parent = null; }
				}
				return {x:pos[0], y:pos[1]};
			}
	};
	
	
	
	
	// Serializer
	instance.Serializer = function() {
		this.pieces = [];
	}
	
	
	
	
	return instance;
})();

// Add indexOf() to Array… Use $.inArray() in the future?
if (![].indexOf) {
	Array.prototype.indexOf = function(value) {
		for ( var i = 0, length = this.length; i < length; i++ )
			if ( this[i] == value )
				return i;

		return -1;
	};
}
if (![].lastIndexOf) {
	Array.prototype.lastIndexOf = function(value) {
		for ( var i = this.length - 1; i > -1; i-- )
			if ( this[i] == value )
				return i;

		return -1;
	};
}