//therendStudio 2009
//#FIXME: all toggled - with internal flag (store the old value), unify single and multiple properties and attributes,pracache 'em,split  properties outside
//#TODO: change all selector with elements,separate animation to apply chaining

MC.Adapter._version = 0.21;
if(typeof jQuery != 'undefined'){
	MC.Adapter.selectElements = function(selector,ancestorNode,single){
		return single ? jQuery(selector,ancestorNode).get(0) : jQuery(selector,ancestorNode);
	}
	MC.Adapter.getDomNode = function(element){
	}
	MC.Adapter.assertNonEmptySelecton = function(selection,failStr){
		if(! selection.length)
			throw failStr;
	}
	MC.Adapter.destroyElements = function(selector){
		jQuery(selector).remove();
	}
	MC.Adapter.atEvent = function(element,eventName,eventHandler){  //Registers an event callback
		jQuery(element).bind(eventName,eventHandler);
	}
	MC.Adapter.atEvents = function(element,eventNameList,eventHandler){  //Registers an event callback
		jQuery(element).bind(eventNameList.join(' '),eventHandler);
	}
	MC.Adapter.fireEvent = function(element,eventName){
		jQuery(element).trigger(eventName);
	}
	MC.Adapter.eventStop = function(event){
		event.preventDefault();
		event.stopPropagation();
		return false;
	};
	MC.Adapter.manipulateElementClassName = function(selector,action,name){
		var elements = jQuery(selector);
		if(elements.length == 0)
			return;
		MC.Utils.validateDefined(name,"Undefined class name");
		switch(action){
			case 'set':
				elements.attr('className',name);
				break;
			case 'add':
				elements.addClass(name);
				break;
			case 'remove':
				elements.removeClass(name);
				break;
			case 'toggle':	
				elements.toggleClass(name);
				break;
			default:
				throw "Invalid manipulateElementClassName() action ["+action+"]";
		}
		return true;
	}
	MC.Adapter.changeElementAttribute = function(selector,action,name,value){
		var elements = jQuery(selector);
		if(elements.length == 0)
			return false;
		switch(action){
			case 'set':
				elements.attr(name,value);
				break;
			case 'clear':
				elements.removeAttr(name);
				break;
			case 'toggle':	
				elements.each(function(){
					var element = jQuery(this);
					if(element.attr(name) == value)
						element.removeAttr(name);
					else
						element.attr(name,value);
				});
				break;
			default:
				throw "Invalid changeElementAttribute() action ["+action+"]";
		}
		return true;
	}
	MC.Adapter.changeElementCssProperty = function(selector,action,name,value,duration,easing){
	//Combine with changeElementCssProperties
		var elements = jQuery(selector);
		if(elements.length == 0)
			return false;
		if(!isNaN(Number(value)))	//FF bug for string value of numeric properties without units ('30' vs. '30px')
			value = Number(value);
		switch(action){
			case 'set':
				elements.css(name,value);
				break;
			case 'clear':
				elements.css(name,'');
				break;
			case 'animate':
				var props = {};
				easing = typeof easing != 'undefined' ? easing : 'linear';
				props[name] = value;
				elements.animate(props,1 * duration,easing);
				break;
			case 'toggle':	
				elements.each(function(){
					var element = jQuery(this);
					if(element.attr(name) == value)
						element.css(name);
					else
						element.css(name,value);
				});
				break;
			default:
				throw "Invalid changeElementCssProperty() action ["+action+"]";
		}
		return true;
	},
	MC.Adapter.changeElementCssProperties = function(selector,action,properties,duration,easing){
		var elements = jQuery(selector);
		if(elements.length == 0)
			return false;
		var props = {};
		MC.Utils.withEach(properties.split(';'),function(){	//#TODO:precache
			if(!this.length)
				return;
			var paramPair = this.split(':');
			if(paramPair.length != 2)
				throw "Invalid css property pair `" + this + "` (must be `property:value`)";
			if(action == 'clear')
				props[paramPair[0]] = '';
			else
				props[paramPair[0]] = 		!isNaN(Number(paramPair[1])) ? Number(paramPair[1]) : paramPair[1];	//FF bug for string value of numeric properties without units ('30' vs. '30px')
		});
		switch(action){
			case 'clear':
			case 'set':
				elements.css(props);
				break;
			case 'animate':
				easing = typeof easing != 'undefined' ? easing : 'linear';
				elements.animate(props,1 * duration,easing);
				break;
			case 'toggle':	
				elements.each(function(){
					var element = jQuery(this);
					jQuery.each(props,function(prop,value){
						if(element.css(prop) == value)
							element.css(prop,'');
						else
							element.css(prop,value);
					});
				});
				break;
			default:
				throw "Invalid changeElementCssProperties() action ["+action+"]";
		}
		return true;
	}
	MC.Adapter.effectHightlight = function(selector,color,duration,count){
		jQuery(selector).each(function(){
			var element = jQuery(this);
			element.stop(true,true);
			if(element.css('backgroundColor') == 'transparent' || MC.Adapter.isBrowserSafari && element.css('backgroundColor') == 'rgba(0, 0, 0, 0)'){
			//highlight the text
				var oldColor = element.css('color');
				for(var i = count;i;i--){
					element.animate({color:color},(count > 1 ? 0.2 : 0.05)*duration,'linear');
					element.animate({color:oldColor},(count > 1 ? 0.8 : 0.95)*duration,'swing');
				};
			}else{
				var oldColor = element.css('backgroundColor');
				for(var i = count;i;i--){
					element.animate({backgroundColor:color},(count > 1 ? 0.2 : 0.05)*duration,'linear');
					element.animate({backgroundColor:oldColor},(count > 1 ? 0.8 : 0.95)*duration,'swing');
				};
			}
		});
	}
	MC.Adapter.strTrim = function(str){
		return jQuery.trim(str);
	}
	MC.Adapter.isBrowserIE = jQuery.browser.msie;
	MC.Adapter.isBrowserOpera = jQuery.browser.opera;
	MC.Adapter.isBrowserSafari = jQuery.browser.safari;
	MC.Adapter.isBrowserMozilla = jQuery.browser.mozilla;
}else if(typeof MooTools != 'undefined'){
	MC.Adapter.selectElements = function(selector,ancestorNode,single){
		return single ? $(ancestorNode || document).getElement(selector) : $(ancestorNode || document).getElements(selector);
	}
	MC.Adapter.assertNonEmptySelecton = function(selection,failStr){
		if(! selection.length)
			throw failStr;
	}
	MC.Adapter.destroyElements = function(selector){
		$$(selector).destroy();
	}
	MC.Adapter.atEvent = function(element,eventName,eventHandler){  //Registers an event callback
		$(element).addEvent(eventName,eventHandler);
	}
	MC.Adapter.atEvents = function(element,eventNameList,eventHandler){  //Registers an event callback
		eventNameList.each(function(eventName){
			$(element).addEvent(eventName,eventHandler);
		});
	}
	MC.Adapter.fireEvent = function(element,eventName){
		$(element).fireEvent(eventName);
	}
	MC.Adapter.eventStop = function(event){
		event.stop();
		return false;
	};
	MC.Adapter.eventCharCode = function(event){
		return  event.code;
	}
	MC.Adapter.isSpecialPressKey = function(event){
		if(MC.Adapter.isBrowserIE)
			return false;	//It doesn't get special keys
		if(event.key.length != 1)
			return true;
		if(MC.Adapter.isBrowserMozilla)
			return  event.event.charCode == 0;
		if(MC.Adapter.isBrowserOpera)
			return  event.event.which < 32 || [35,36,45,46].indexOf(event.event.which) != -1;
		return event.event.keyCode < 32;
	}
	MC.Adapter.manipulateElementClassName = function(selector,action,name){
		var elements = $$(selector);
		if(elements.length == 0)
			return;
		MC.Utils.validateDefined(name,"Undefined class name");
		switch(action){
			case 'set':
				elements.each(function(element){
					element.className = name;
				});
				break;
			case 'add':
				elements.addClass(name);
				break;
			case 'remove':
				elements.removeClass(name);
				break;
			case 'toggle':	
				elements.toggleClass(name);
				break;
			default:
				throw "Invalid manipulateElementClassName() action ["+action+"]";
		}
		return true;
	}
	MC.Adapter.changeElementAttribute = function(selector,action,name,value){
		var elements = $$(selector);
		if(elements.length == 0)
			return false;
		switch(action){
			case 'set':
				elements.set(name,value);
				break;
			case 'clear':
				elements.erase(name,'');
				break;
			case 'toggle':	
				elements.each(function(element){
					if(element.get(name) == value)
						element.erase(name);
					else
						element.set(name,value);
				});
				break;
			default:
				throw "Invalid changeElementAttribute() action ["+action+"]";
		}
		return true;
	}
	MC.Adapter.changeElementCssProperty = function(selector,action,name,value,duration,easing){
		var elements = $$(selector);
		if(elements.length == 0)
			return false;
		switch(action){
			case 'set':
				elements.setStyle(name,value);
				break;
			case 'clear':
				elements.setStyle(name,'');
				break;
			case 'animate':
				easing = typeof easing != 'undefined' ? easing : 'linear';
				elements.each(function(el){
					el.get('tween',{property:'opacity',duration:1 * duration,easing:easing}).start(value);
				});
				break;
			case 'toggle':	
				elements.each(function(){
					element = $(this);
					if(element.getStyle(name) == value)
						element.setStyle(name,'');
					else
						element.setStyle(name,value);
				});
				break;
			default:
				throw "Invalid changeElementCssProperty() action ["+action+"]";
		}
		return true;
	},
	MC.Adapter.changeElementCssProperties = function(selector,action,properties,duration,easing){
		var elements = $$(selector);
		if(elements.length == 0)
			return false;
		var props = new Hash();
		MC.Utils.withEach(properties.split(';'),function(){
			if(!this.length)
				return;
			var paramPair = this.split(':');
			if(paramPair.length != 2)
				throw "Invalid css property pair `" + this + "` (must be `property:value`)";
			if(action == 'clear')
				props[paramPair[0]] = '';
			else
				props[paramPair[0]] = 	!isNaN(Number(paramPair[1])) ? Number(paramPair[1]) : paramPair[1];	//FF bug for string value of numeric properties without units ('30' vs. '30px')
		});
		switch(action){
			case 'clear':
			case 'set':
				elements.setStyles(props);
				break;
			case 'animate':
				easing = typeof easing != 'undefined' ? easing : 'linear';
				elements.animate(props,1 * duration,easing);
				break;
			case 'toggle':
				//#FIXME:	 make it work with multi styles (padding)
				elements.each(function(element){
					props.each(function(value,prop){
						if(element.getStyle(prop) == value)
							element.setStyle(prop,'');
						else
							element.setStyle(prop,value);
					});
				});
				break;
			default:
				throw "Invalid changeElementCssProperties() action ["+action+"]";
		}
		return true;
	}
	MC.Adapter.effectHightlight = function(selector,color,duration,count){
		$(selector).highlight(color);return;
		var element = $(this);
		element.stop(true,true);
		if(element.css('backgroundColor') == 'transparent' || MC.Adapter.isBrowserSafari && element.css('backgroundColor') == 'rgba(0, 0, 0, 0)'){
		//highlight the text
			var oldColor = element.css('color');
			for(var i = count;i;i--){
				element.animate({color:color},(count > 1 ? 0.2 : 0.05)*duration,'linear');
				element.animate({color:oldColor},(count > 1 ? 0.8 : 0.95)*duration,'swing');
			};
		}else{
			var oldColor = element.css('backgroundColor');
			for(var i = count;i;i--){
				element.animate({backgroundColor:color},(count > 1 ? 0.2 : 0.05)*duration,'linear');
				element.animate({backgroundColor:oldColor},(count > 1 ? 0.8 : 0.95)*duration,'swing');
			};
		}
	};
	MC.Adapter.strTrim = function(str){
		return str.trim();
	}
	MC.Adapter.isBrowserIE = Browser.Engine.trident;
	MC.Adapter.isBrowserOpera = Browser.Engine.presto;
	MC.Adapter.isBrowserSafari = Browser.Engine.webkit;
	MC.Adapter.isBrowserMozilla = Browser.Engine.gecko;
}else if(typeof Prototype != 'undefined'){
	MC.Adapter.selectElements = function(selector,ancestorNode){
		return Element.select(ancestorNode || document,selector);
	}
	MC.Adapter.selectElement = function(selector,ancestorNode){
		return Element.down(ancestorNode || document,selector);
	}
	MC.Adapter.destroyElements = function(selector){
		if(typeof selector == 'string')
			var elements = $$(selector);
		else
			var elements = $([selector]);
		elements.each(function(element){
			element.remove();
		});
	}
	MC.Adapter.atEvent = function(element,eventName,eventHandler){  //Registers an event callback
		Element.observe(element,eventName,eventHandler);
	}
	MC.Adapter.atEvents = function(element,eventNameList,eventHandler){  //Registers an event callback
		eventNameList.each(function(eventName){
			Element.observe(element,eventName,eventHandler);
		});
	}
	MC.Adapter.fireEvent = function(element,eventName){
		//#FIXME: update when Prototype supports native fire
		if (document.createEventObject){
	        // dispatch for IE
	        var evt = document.createEventObject();
	        return element.fireEvent('on'+eventName,evt)
	    }
	    else{
	        // dispatch for firefox + others
	        var evt = document.createEvent("HTMLEvents");
	        evt.initEvent(eventName, true, true ); // event type,bubbling,cancelable
	        return !element.dispatchEvent(evt);
	    }
	}
	MC.Adapter.eventStop = function(event){
		Event.stop(event);
		return false;
	};
	MC.Adapter.changeElementAttribute = function(selector,action,name,value){
		if(typeof selector == 'string')
			var elements = $$(selector);
		else
			var elements = $([selector]);
		if(elements.length == 0)
			return false;
		switch(action){
			case 'set':
				elements.each(function(element){
					Element.writeAttribute(element,name,value);
				});
				break;
			case 'clear':
				elements.each(function(element){
					Element.writeAttribute(element,name,null);
				});
				break;
			case 'toggle':	
				elements.each(function(element){
					if(Element.readAttribute(element,name) == value)
						Element.writeAttribute(element,name,'');
					else
						Element.writeAttribute(element,name,value);
				});
				break;
			default:
				throw "Invalid changeElementAttribute() action ["+action+"]";
		}
		return true;
	}
	MC.Adapter.manipulateElementClassName = function(selector,action,name){
		if(typeof selector == 'string')
			var elements = $$(selector);
		else
			var elements = $([selector]);
		if(elements.length == 0)
			return false;
		MC.Utils.validateDefined(name,"Undefined class name");
		switch(action){
			case 'set':
				elements.each(function(element){
					Element.writeAttribute(element,'className',name);
				});
				break;
			case 'add':
				elements.each(function(element){
					Element.addClassName(element,name);
				});
				break;
			case 'remove':
				elements.each(function(element){
					Element.removeClassName(element,name);
				});
				break;
			case 'toggle':
				elements.each(function(element){
					Element.toggleClassName(element,name);
				});
				break;
			default:
				throw "Invalid manipulateElementClassName() action ["+action+"]";
		}
		return true;
	}
	MC.Adapter.changeElementCssProperty = function(selector,action,name,value,duration,easing){
		if(typeof selector == 'string')
			var elements = $$(selector);
		else
			var elements = $([selector]);
		if(elements.length == 0)
			return false;
		var props = {};
		props[name] = value;
		switch(action){
			case 'animate':
			case 'set':
				elements.each(function(element){
					element.setStyle(props);
				});
				break;
			case 'clear':
				elements.each(function(element){
					Element.setStyle(element,props);
				});
				break;
			case 'toggle':	
				elements.each(function(){
					element = $(this);
					if(element.getStyle(name) == value)
						props[name] = null;
					element.setStyle(props);
				});
				break;
			default:
				throw "Invalid changeElementCssProperty() action ["+action+"]";
		}
		return true;
	},
	MC.Adapter.changeElementCssProperties = function(selector,action,properties,duration,easing){
		if(typeof selector == 'string')
			var elements = $$(selector);
		else
			var elements = $([selector]);
		if(elements.length == 0)
			return false;
		var props = {};
		MC.Utils.withEach(properties.split(';'),function(){
			if(!this.length)
				return;
			var paramPair = this.split(':');
			if(paramPair.length != 2)
				throw "Invalid css property pair `" + this + "` (must be `property:value`)";
			if(paramPair[0] != 'opacity' && paramPair[0] != 'z-index' && paramPair[1] != "0" && !isNaN(paramPair[1]))
				throw "COMPABITILITY ERROR(FF)=>A numeric css property value without units:"+this;
			if(action == 'clear')
				props[paramPair[0]] = '';
			else
				props[paramPair[0]] = !isNaN(Number(paramPair[1])) ? Number(paramPair[1]) : paramPair[1];	//FF bug for string value of numeric properties without units ('30' vs. '30px')
		});
		switch(action){
			case 'clear':
			case 'set':
			case 'animate':
				elements.each(function(element){
					Element.setStyle(element,props);
				});
				break;
			case 'toggle':
				elements.each(function(element){
					new Hash(props).each(function(pair){
						var prop = {};
						prop[pair.key] = pair.value;
						if(element.getStyle(pair.key) == pair.value)
							prop[pair.key] = '';
						element.setStyle(prop);
					});
				});
				break;
			default:
				throw "Invalid changeElementCssProperties() action ["+action+"]";
		}
		return true;
	}
	MC.Adapter.strTrim = function(str){
		return str.strip();
	}
	MC.Adapter.isBrowserIE = Prototype.Browser.IE;
	MC.Adapter.isBrowserOpera = Prototype.Browser.Opera;
	MC.Adapter.isBrowserSafari = Prototype.Browser.WebKit;
	MC.Adapter.isBrowserMozilla = Prototype.Browser.Gecko;
}
if(typeof jQuery != 'undefined' || typeof Prototype != 'undefined'){
	MC.Adapter.eventCharCode = function(event){
		if(MC.Adapter.isBrowserMozilla)
			return  event.charCode;
		return event.keyCode;
	}
	MC.Adapter.isSpecialPressKey = function(event){
		if(MC.Adapter.isBrowserIE)
			return false;	//It doesn't get special keys
		if(MC.Adapter.isBrowserMozilla)
			return  event.charCode == 0;
		if(MC.Adapter.isBrowserOpera)
			return  event.which < 32 || [35,36,45,46].indexOf(event.which) != -1;
		return event.keyCode < 32;
	}
}
