var DoNothing = function(){void(0);};

	/*
		--> $R
		Retorna un 
		__________________________________________________________________________________________________
	*/
var $R = function(ini, fini){
	if(!(fini)){
		var fini = ini;
		ini = 0;
	}
	this.ini = ini;
	this.fini = fini;
	var tr = [];
	for(var i = ini; i<fini; i++) tr.push(i);
	return toRange(tr);
}
var Range = $R;
var toRange = function(arr){
	var tr = arr;
	tr.expand = function(n){
		return (function(n){
			this.fini = this.fini + n;
			this.array = $R(this.ini, this.fini);
			return this.array;
		}).call(tr, n);
	};
	tr.concatRange = function(range){
		return toRange((function(range){
			return tr.concat(range.filter(function(val){
				return !(this.test(val));
			}, tr));
		}).call(tr, range));
	};
	tr.unConcatRange = function(range){
		return toRange((function(range){
			t = this;
			range.each(function(val){
				t.remove(val);
			});
			return t;
		}).call(tr, range));
	};
	return tr;
};

var UUID = function(prefix, sep){
  var sep = (sep || sep==='') ? sep : '-';
  return ((prefix || prefix==='') ? prefix : '') + [4, 2, 2, 2, 6].map(function(length) {
    return $R(length).map(function() {
      return sep + Math.round((Math.random() * 256)).toString(16);
    }).join('');
  }).join(sep);
}

var miniUUID = function(prefix, sep){
  var sep = (sep || sep==='') ? sep : '-';
  return ((prefix || prefix==='') ? prefix : '') + [2, 1, 1, 3].map(function(length) {
    return $R(length).map(function() {
      return sep + Math.round((Math.random() * 256)).toString(16);
    }).join('');
  }).join(sep);
}
	/*
		--> Iframe
		Conjunt de mètodes per a treballar amb els iframes
		__________________________________________________________________________________________________
	*/
var Iframe = function(iframe){
	iframe = $(iframe);
	if(iframe.name == ''){
		iframe.name = miniUUID('if',''); //UUID('iframe_','');
	}
	if(iframe.id == ''){
		iframe.id = iframe.name;
	}else{
		iframe.name = iframe.id;
	}

	iframe.extend({
		/*
			--> Iframe.getWindow
			En retorna l'element window
			__________________________________________________________________________________________________
		*/
		getWindow: function(){
			return this.contentWindow || document.frames(this.name) || document.frames[this.name];
		},
		/*
			--> Iframe.getDocument
			En retorna l'element document
			__________________________________________________________________________________________________
		*/
		getDocument: function(){
			return this.contentDocument || this.getWindow().document;
		},
		/*
			--> Iframe.getHTML
			En retorna el contingut HTML
			__________________________________________________________________________________________________
		*/
		getHTML: function(){
			return this.getDocument().body.innerHTML;
		},
		/*
			--> Iframe.getVar
			En retorna una variable global
			__________________________________________________________________________________________________
		*/
		getVar: function(varname){
			return this.getWindow()[varname];
		},
		/*
			--> Iframe.setVar
			N'estableix una variable global i el seu valor
			__________________________________________________________________________________________________
		*/
		setVar: function(varname, value){
			this.getWindow()[varname] = value;
			return this;
		},
		/*
			--> Iframe.$
			En retorna un element amb el mateix id (o el mateix element
			__________________________________________________________________________________________________
		*/
		$: function(el){
			if (!el) return false;
			if ($type(el) == 'string') return this.getDocument().getElementById(el);
			return el;
		},
		/*
			--> Iframe.navigate
			En canvia l'adreça
			__________________________________________________________________________________________________
		*/
		navigate: function(url){
			this.src = url;
			return this;
		},
		/*
			--> Iframe.setEvent
			Estableix un esdeveniment a l'iframe
			__________________________________________________________________________________________________
		*/
		setEvent: function(e,f){
			this.removeEvents(e);
			this.addEvent(e,f);
			return this;
		}
	});
	return iframe;
}

/*
	Dialog
	Mostra diàlegs simples
	__________________________________________________________________________________________________
*/
var Dialog = Class({
	initialize: function(el, dials){
		if ((dials && dials!==false) || $type(el)=='string'){
			this.id = (!dials) ? $(el).id : dials;
			Dialogs[this.id] = this;
		}else{
			this.id = false;
		}
		this.element = $(el).setStyle('display','none').setStyle('margin-left','auto').setStyle('margin-right','auto').setStyle('position','absolute');
		this.element.dialog = this;
		return this;
	},
	show: function(onHide){
		if(onHide){
			this.onHide = ($type(onHide)=='string') ? function(){Dialogs[onHide].show();} : onHide;
		}else{
			this.onHide = DoNothing;
		}
		var This = this;
		for(var i in Dialogs){ Dialogs[i].element.setStyle('z-index','0'); }
		Dialog.enfosquidor.setStyle('position','fixed').setStyle('display','block').setStyle('z-index','1');
		this.element.setStyle('display','block').setStyle('z-index','2');
		this.element.center(true);
		return this;
	},
	hide: function(){
		Dialog.enfosquidor.setStyle('display','none');
		this.element.setStyle('display','none');
		this.onHide(this);
		return this;
	},
	isActive: function(){
		return !(this.element.getStyle('display')=='none');
	},
	getInput: function(name){
		var els = this.element.getElements('*[name="'+name+'"]');
		if(els[0].getProperty('type')=='checkbox' || els[0].getProperty('type')=='radio'){
			var checked = [];
			els.each(function(el){
				if(el.checked===true) checked.push(el.value);
			});
			return (els.length > 1) ? checked : els[0].checked
		}else{
			return els[0].value;
		}
	},
	setInput: function(name,value){
		var inp = this.element.getElements('*[name="'+name+'"]')
		if(inp[0].getProperty('type')=='checkbox' || inp[0].getProperty('type')=='radio'){
			inp.each(function(el){
				if($type(value)=='boolean'){
					el.checked===value;
				}else if(el.value===value){
					el.checked = true;
				}else if(inp[0].getProperty('type')=='radio'){
					el.checked = false;
				}
			});
			return inp;
		}else{
			inp[0].value = value;
			return inp[0];
		}
	},
	isSet: function(name){
		return (this.getInput(name)!='');
	},
	areSet: function(names){
		return names.every(this.isSet, this);
	},
	onHide: DoNothing,
	kill: function(){
		this.hide().element.remove();
		if(this.id !== false) delete Dialogs[this.id];
	}
});
Dialogs = {};
window.addEvent('load', function(){
		Dialog.enfosquidor = new Element('div').setProperty('style','position:fixed;top:0px;left:0px;height:100%;width:100%;background:black;display:none;').setOpacity(0.8).injectInside(document.body);
});

/*
	EXTENSIÓ DE TOTS ELS NUMBERS DEL DOM (MOOTOOLS)
	__________________________________________________________________________________________________
*/
Number.extend({
	/*
		--> each
		Equivalent a Array.each, però per a nombres... substitut de for()
		__________________________________________________________________________________________________
	*/
	each: function(fn, bind){
		for(var i = 0; i < this ; i++) fn.call(bind, i, this);
	}
});
String.extend({
	/*
		--> noExtension
		Retorna el nom del fitxer sense l'extensió
		__________________________________________________________________________________________________
	*/
	noExtension: function(){
		var ex = this.split('.');
		ex = ex[ex.length-1];
		return this.substring(0, this.length - ex.length - 1);
	},
	/*
		--> parseQuery
		Converteix una URL query en un objecte
		Exemple:
		q = 'postid=2124&sid=h12h412hh12h41g24h1g24h1g1h4&style=blue'.parseQuery();
		// q es convertirà en
		//	{
		//		postid:'2124',
		//		sid:'h12h412hh12h41g24h1g24h1g1h4',
		//		style:'blue'
		//	}
		__________________________________________________________________________________________________
	*/
	parseQuery: function() {
		var pairs = this.match(/^\??(.*)$/)[1].split('&');
		var params = {};
		pairs.each(function(pair){
			pair = pair.split('=');
			params[pair[0]] = pair[1];
		});
		return params;
	},
	/*
		--> alert
		Mostra una alerta que no molesta tant
		__________________________________________________________________________________________________
	*/
	alert: function(title, onClick){
		return this.confirm({cancelText:false, title:title, onClick:(onClick) ? onClick : false});
	},
	confirm: function(options){
		var html = '';
		if(options && options.title) html += '<h1>'+options.title.htmlEntities()+'</h1>';
		html += '<div class="content">' + this.htmlEntities().replaceAll('{br}', '<br />').replaceAll('{p}', '<p>').replaceAll('{/p}', '</p>') + '<div class="buttons">';
		html += '<input type="button" value="' + ((options && options.okText) ? options.okText.htmlEntities() : 'OK') + '" />';
		if(options && options.cancelText!==false) html += '<input type="button" value="' + ((options && options.cancelText) ? options.cancelText.htmlEntities() : 'Cancel') + '" />';
		html += '</div></div>';

		var el = new Element('div').setProperty('id', UUID('alert')).setProperty('class', 'dialog').setHTML(html).setStyle('display', 'none').injectInside(document.body);

		var tr = new Dialog(el);

		var f = (options && options.onClick) ? options.onClick : DoNothing;
		var onClick = function(clicked){
			var bind = (options && options.bind) ? options.bind : tr;
			if(f.call(bind, clicked) !== false) tr.kill();
		};

		var botons = el.getElements('input[type="button"]');
		botons[0].addEvent('click', function(){onClick(true);});
		if(botons.length == 2) botons[1].addEvent('click', function(){onClick(false);});

		return tr.show();
	},
	prompt: function(options){
		var html = '';
		if(options && options.title) html += '<h1>'+options.title.htmlEntities()+'</h1>';
		html += '<div class="content">' + this.htmlEntities().replaceAll('{br}', '<br />').replaceAll('{p}', '<p>').replaceAll('{/p}', '</p>');
		html += '<p>'+((options && options.type && (options.type == 'large' || options.type == 'long')) ? '<textarea></textarea>' : '<input type="text">') +'</p>';
		html += '<div class="buttons"><input type="button" value="' + ((options && options.okText) ? options.okText.htmlEntities() : 'OK') + '" />';
		if(options && options.cancelText) html += ' <input type="button" value="' + options.cancelText.htmlEntities() + '" />';
		html += '</div></div>';

		var el = new Element('div').setProperty('id', UUID('alert')).setProperty('class', 'dialog').setHTML(html).setStyle('display', 'none').injectInside(document.body);

		var tr = new Dialog(el);

		var f = (options && options.onClick) ? options.onClick : DoNothing;
		var onClick = function(clicked){
			var value = el.getElement((options && options.type && (options.type == 'large' || options.type == 'long')) ? 'textarea' : 'input').value;
			var bind = (options && options.bind) ? options.bind : tr;
			if(f.call(bind, clicked, value) !== false) tr.kill();
		};

		var botons = el.getElements('input[type="button"]');
		botons[0].addEvent('click', function(){onClick(true);});
		if(botons.length == 2) botons[1].addEvent('click', function(){onClick(false);});

		return tr.show();
	},	/*
		--> ksprint
		'em piquen el {%1} i el {%2}, però més el {%1}'.ksprint('nas', 'peu');
		__________________________________________________________________________________________________
	*/
	ksprint: function(){
		var nthis = this;
		var onEach = function(el){return el;};
		var replaces = arguments;
		if($type(arguments[0])=='object'){
			onEach = arguments[1] || onEach;
			replaces = arguments[0];
			for(var v in replaces){
				nthis = nthis.replaceAll('{%'+v+'}', onEach(replaces[v]));
			}
			return nthis;
		}else if($type(arguments[0])=='array'){
			replaces = arguments[0];
			onEach = arguments[1];
		}
		for(var i=0;i<replaces.length;i++){
			nthis = nthis.replaceAll('{%'+(i+1)+'}', onEach(replaces[i]));
		}
		return nthis;
	},
	/*
		--> htmlentities
		Fa que els strings continguin entities en comptes de caràcters no ASCII
		__________________________________________________________________________________________________
	*/
	htmlEntities:function(){
		var chars = new Array ('&','à','á','â','ã','ä','å','æ','ç','è','é','ê','ë','ì','í','î','ï','ð','ñ','ò','ó','ô','õ','ö','ø','ù','ú','û','ü','ý','þ','ÿ','À','Á','Â','Ã','Ä','Å','Æ','Ç','È','É','Ê','Ë','Ì','Í','Î','Ï','Ð','Ñ','Ò','Ó','Ô','Õ','Ö','Ø','Ù','Ú','Û','Ü','Ý','Þ','€','\"','ß','<','>','¢','£','¤','¥','¦','§','¨','©','ª','«','¬','­','®','¯','°','±','²','³','´','µ','¶','·','¸','¹','º','»','¼','½','¾');
		var entities = new Array ('amp','agrave','aacute','acirc','atilde','auml','aring','aelig','ccedil','egrave','eacute','ecirc','euml','igrave','iacute','icirc','iuml','eth','ntilde','ograve','oacute','ocirc','otilde','ouml','oslash','ugrave','uacute','ucirc','uuml','yacute','thorn','yuml','Agrave','Aacute','Acirc','Atilde','Auml','Aring','AElig','Ccedil','Egrave','Eacute','Ecirc','Euml','Igrave','Iacute','Icirc','Iuml','ETH','Ntilde','Ograve','Oacute','Ocirc','Otilde','Ouml','Oslash','Ugrave','Uacute','Ucirc','Uuml','Yacute','THORN','euro','quot','szlig','lt','gt','cent','pound','curren','yen','brvbar','sect','uml','copy','ordf','laquo','not','shy','reg','macr','deg','plusmn','sup2','sup3','acute','micro','para','middot','cedil','sup1','ordm','raquo','frac14','frac12','frac34');
		newString = this;
		for (var i = 0; i < chars.length; i++){
			myRegExp = new RegExp();
			myRegExp.compile(chars[i],'g')
			newString = newString.replace (myRegExp, '&' + entities[i] + ';');
		}
		return newString;
	},
	/*
		--> replaceAll
		Substitueix part d'un string per una altra sempre que aparegui
		__________________________________________________________________________________________________
	*/
	replaceAll: function(searchValue, replaceValue) {
		var replaceRegex = new RegExp(searchValue,"g");
		return this.replace(replaceRegex, replaceValue);
	},
	/*
		--> replaceOnce
		Substitueix part d'un string per una altra una sola vegada
		__________________________________________________________________________________________________
	*/
	replaceOnce: function(searchValue, replaceValue){
		var replaceRegex = new RegExp(searchValue);
		return this.replace(replaceRegex, replaceValue);
	}
});
Element.extend({
	/*
		--> getParentTag
		Retorna la primera etiqueta del paràmetre passat contenidora de l'element
		__________________________________________________________________________________________________
	*/
	getParentTag:function(tag){
		var obj = this;
		while(obj !=null && $(obj).getTag()!=tag.toLowerCase()) obj = obj.parentNode;
		return $(obj);
	},
	/*
		--> verticalAlign
		Fa que el vertical-align serveixi per a elements com els divs, no només cel·les de taules
	*/
	verticalAlign:function(va){
		var el = this;
		var va = (va) ? va : false
		if(va===false){
			['baseline','sub','super','top','text-top','middle','bottom','text-bottom','inherit'].each(function(v){
				if(el.hasClass(v)){va=v;}
			});
		}
		if(va===false){va='inherit';}
		var div1 = new Element('div');
		div1.setStyle('display','table').setStyle('height',el.getStyle('height')).setStyle('width',el.getStyle('width'));//el.getCoordinates().height.toString()+'px'
		var div2 = new Element('div').setStyle('display','table-cell').setStyle('vertical-align',va).setStyle('width',el.getStyle('width')).injectInside(div1);
		div2.setHTML(el.innerHTML);
		div1.injectAfter(el);
		el.setHTML('');
		el.adopt(div1);
		return el;
	},
	/*
		--> center
		Centra l'element en la finestra
		__________________________________________________________________________________________________
	*/
	center:function(permanent){
		var This = this;
		if(permanent && permanent === true){
			var r = function(){This.center();};
			window.addEvent('resize', r).addEvent('scroll', r);
		}
		var elSize = This.getCoordinates();
		var winSize = window.getSize();

		var el_top = winSize.size.y / 2 - elSize.height / 2 + winSize.scroll.y;
		var el_left = winSize.size.x / 2 - elSize.width / 2 + winSize.scroll.x;

		This.setStyle('top', ((el_top >= 0) ? el_top : 0) + 'px').setStyle('left', ((el_left >= 0) ? el_left : 0) + 'px');
		return This;
	}
});
/*
	AUTOCOMPLETE O AUTOSUGGEST
	Fa que un camp de text (INPUT TYPE="TEXT") carregui suggeriments mentre s'hi escriu
	__________________________________________________________________________________________________
*/
var Autocomplete = Class({
	initialize: function(el, source, options){
		var This = this;
		this.element = $(el);
		this.source = source;
		if(this.element.getTag()=='select'){
			//Convertir en txt
			var newSource = [];
			this.element.getElements('option').each(function(option){
				newSource.push([option.value, option.innerHTML]);
			});
			this.source = newSource;
			
			var newElement = new Element('input').setProperty('type', 'text').setPropertiesFrom(this.element, ['class','style','id','name']);
			this.element = this.element.replaceWith(newElement);
		}
		
		if(!This.element.hasClass('autocomplete')) This.element.addClass('autocomplete');
		This.element.autocomplete = true;
		
		This.box = new Element('ul').setStyle('display','none').setStyle('margin','0px').setStyle('padding','0px').setStyle('position','absolute').setProperty('class','autocomplete_box').injectAfter(this.element);

		var el = This.element;
		el.addEvent('keydown',function(event){
			event = new Event(event);
			if(el.autocomplete == true){
				(function(){
					if(!['esc','$','#','left','right'].test(event.key) && el.value!=''){
						$clear(This.lastEvent);
						This.lastEvent = (function(){
							This.show();
						}).delay(10, el);
					}else if(event.key=='esc' || el.value==''){
						This.hide();
					}
				}).delay(1,el);

			}
		});
		
		This.element.addEvent('blur',function(event){
			This.hide.delay(100, This);
		});
		
		return this;
	},
	lastEvent: false,
	hide: function(){
		$clear(this.lastEvent);
		this.box.setStyle('display','none').setHTML('');
		return this;
	},
	show: function(value, force){
		if(value && force===true){
			this.element.value = value;
		}else{
			value = this.element.value
		}
		
		var resultats = [];
		
		switch($type(this.source)){
		case 'string':
			if(this.source.substr(0,5)=='json:') resultats = this.sources.ajax.json.call(this, this.substr(5,this.source.length), value);
			if(this.source.substr(0,4)=='xml:') resultats = this.sources.ajax.xml.call(this, this.substr(4,this.source.length), value);
			return false;
			break;
		case 'element':
			this.sources.xml.call(this, this.source);
			break;
		case 'function':
			//Si la funció retorna true, es mostrarà this.box, si retorna false, no; altrament, se'n processarà el resultat i després es mostrarà this.box
			var resultats = this.source.call(this.element, value, this);
			if(resultats === true){
				this.box.setStyle('display','block');
				return false;
			}else if(resultats===false){
				return false;
			}
			break;
		case 'array':
			resultats = this.source;
			break;
		}
		this.draw(resultats);
	},
	draw: function(resultats, value){
		var This = this;
		resultats = resultats.filter(This.sources.filter, This.element.value);
		if(resultats.length>0){
			//do sorting
			resultats.sort();
			//dibuixa els resultats
			This.hide();
			//This.box.setHTML('<ul style="padding:0px;margin:0px;"></ul>');
			resultats.each(function(res){This.addOpc.call(This,res);});
			var coor = This.element.getCoordinates();
			coor.padding = {
				left: This.box.getStyle('padding-left').substr(0,This.box.getStyle('padding-left').length-2),
				right: This.box.getStyle('padding-right').substr(0,This.box.getStyle('padding-right').length-2)
			}
			var width = coor.width - coor.padding.left - coor.padding.right;
			width = (width > 0) ? width : coor.width;
			This.box.setStyle('position', 'absolute').setStyle('top', (coor.top+coor.height)+'px').setStyle('left', coor.left+'px').setStyle('width', width+'px').setStyle('display', 'block');
		}
	},
	sources: {
		ajax: {
			json: function(url, value){
				new Json.Remote(url, {onComplete:this.draw}).send({'value':value});
			},
			xml: function(url, value){
				var This = this;
				new XHR({onSuccess:function(xml){This.sources.xml.call(This, xml.toXML(), true);}}).send(url, {'value': value});
			}
		},
		xml: function(xml, value){
			var resultats = []
			eachNode(xml.getElementsByTagName('option'), function(opcio){
				resultats.push(opcio.textContent);
			});
			if(value && value===true){
				this.draw(resultats);
			}else{
				return resultats;
			}
			
		},
		filter: function(opt){
			if(opt.substr(0,this.length) == this) return true;
			return false;
		}
	},
	addOpc: function(value){
		var This = this;
		var op = new Element('li').setStyles({
			'display': 'block',
			'list-style-image': 'none',
			'list-style-position': 'outside',
			'list-style-type': 'none'
		}).setHTML(value.htmlEntities()).addEvent('mousedown',function(){
			This.element.value = value;
			This.hide();
		}).injectInside(This.box);
		return This;
	}
});

/*
	Tabs
	Passant-li una matriu de pestanyes i una altra de contingut de les pestanyes, les implementa com a pestanyes
	__________________________________________________________________________________________________
*/
var Tabs = new Class({
	defaultOptions: {
		classPrefix: 'tab',
		showFirst: 0
	},
	initialize: function(tabs, contents, options){
		this.setOptions(this.defaultOptions, options);
		this.tabs = tabs;
		this.contents = contents;
		var This = this;
		tabs.each(function(tab, i){
			tab.content = contents[i];
			$(contents[i]).setStyle('display','none').tab = tab;
			tab.showTab = function(){This.showTab.call(This, tab);};
			contents[i].showTab = tab.showTab;
			tab.addEvent('click', tab.showTab).addClass(This.options.classPrefix+'-unselected');
		});
		var sf = this.options.showFirst;
		var sft = $type(sf);
		((sft == 'element' || sft == 'string') ? $(sf) : tabs[sf]).showTab();
		return this;
	},
	showTab: function(tab){
		this.hideAll();
		if($(tab).hasClass(this.options.classPrefix+'-unselected')){
			tab.removeClass(this.options.classPrefix+'-unselected').addClass(this.options.classPrefix+'-selected').content.setStyle('display','block');
			tab.fireEvent('show', tab.content, this);
		}
		return tab;
	},
	hideAll: function(){
		this.tabs.filter(function(tab){
			return tab.hasClass(this.options.classPrefix+'-selected');
		}, this).each(function(tab){
			tab.removeClass(this.options.classPrefix+'-selected').addClass(this.options.classPrefix+'-unselected').content.setStyle('display','none');
			tab.fireEvent('hide', tab.content, this);
		}, this);
		return this;
	}
});
Tabs.implement(new Events);
Tabs.implement(new Options);

/*
	Extensió de l'objecte Math
	__________________________________________________________________________________________________
*/
Math.eq2 = function(a,b,c, f){
	if(!f) var f = function(n){return n;};
	var disc=b*b-4*a*c;
	if(disc<0) return false;
	var x1=(-b-Math.sqrt(disc))/(2*a);
	var x2=(-b+Math.sqrt(disc))/(2*a);
	return [f(x1), f(x2)];
};