var Roar = new Class({

	Implements: [Options, Events, Chain],

	options: {
		duration: 4000,
		position: 'upperLeft',
		container: null,
		bodyFx: null,
		itemFx: null,
		margin: {x: 10, y: 10},
		offset: 5,
		className: 'roar',
		onShow: $empty,
		onHide: $empty,
		onRender: $empty,
		style: 'notice'
	},

	initialize: function(options) {
		this.setOptions(options);
		this.items = [];
		this.container = $(this.options.container) || document;
	},

	alert: function(title, message, options) {
		var params = Array.link(arguments, {title: String.type, message: String.type, options: Object.type});
		var items = [new Element('h3', {'html': $pick(params.title, '')})];
		if (params.message) items.push(new Element('p', {'html': params.message}));
		return this.inject(items, params.options);
	},

	inject: function(elements, options) {
		if (!this.body) this.render();
		options = options || {};

		var offset = [-this.options.offset, 0];
		var last = this.items.getLast();
		if (last) {
			offset[0] = last.retrieve('roar:offset');
			offset[1] = offset[0] + last.offsetHeight + this.options.offset;
		}
		var to = {'opacity': 1};
		to[this.align.y] = offset;

		var item = new Element('div', {
			'class': this.options.className,
			'opacity': 0
		}).adopt(
			new Element('div', {
				'class': this.options.className+'-bg',
				'opacity': 0.7
			}),
			elements
		);

		item.setStyle(this.align.x, 0).store('roar:offset', offset[1]).set('morph', $merge({
			unit: 'px',
			link: 'cancel',
			onStart: Chain.prototype.clearChain,
			transition: Fx.Transitions.Back.easeOut
		}, this.options.itemFx));

		var remove = this.remove.create({
			bind: this,
			arguments: [item],
			delay: 10
		});
		this.items.push(item.addEvent('click', remove));

		if (this.options.duration) {
			var over = false;
			var trigger = (function() {
				trigger = null;
				if (!over) remove();
			}).delay(this.options.duration);
			item.addEvents({
				mouseover: function() {
					over = true;
				},
				mouseout: function() {
					over = false;
					if (!trigger) remove();
				}
			});
		}
		item.inject(this.body).morph(to);
		return this.fireEvent('onShow', [item, this.items.length]);
	},

	remove: function(item) {
		var index = this.items.indexOf(item);
		if (index == -1) return this;
		this.items.splice(index, 1);
		item.removeEvents();
		var to = {opacity: 0};
		to[this.align.y] = item.getStyle(this.align.y).toInt() - item.offsetHeight - this.options.offset;
		item.morph(to).get('morph').chain(item.destroy.bind(item));
		return this.fireEvent('onHide', [item, this.items.length]).callChain(item);
	},

	empty: function() {
		while (this.items.length) this.remove(this.items[0]);
		return this;
	},

	render: function() {
		this.position = this.options.position;
		if ($type(this.position) == 'string') {
			var position = {x: 'center', y: 'center'};
			this.align = {x: 'left', y: 'top'};
			if ((/left|west/i).test(this.position)) position.x = 'left';
			else if ((/right|east/i).test(this.position)) this.align.x = position.x = 'right';
			if ((/upper|top|north/i).test(this.position)) position.y = 'top';
			else if ((/bottom|lower|south/i).test(this.position)) this.align.y = position.y = 'bottom';
			this.position = position;
		}
		this.body = new Element('div', {'class': this.options.className+'-body'}).inject(document.body);
		if (Browser.Engine.trident4) this.body.addClass(this.options.className+'-body-ugly');
		this.moveTo = this.body.setStyles.bind(this.body);
		this.reposition();
		if (this.options.bodyFx) {
			var morph = new Fx.Morph(this.body, $merge({
				unit: 'px',
				chain: 'cancel',
				transition: Fx.Transitions.Circ.easeOut
			}, this.options.bodyFx));
			this.moveTo = morph.start.bind(morph);
		}
		var repos = this.reposition.bind(this);
		window.addEvents({
			scroll: repos,
			resize: repos
		});
		this.fireEvent('onRender', this.body);
	},

	reposition: function() {
		var max = document.getCoordinates(), scroll = document.getScroll(), margin = this.options.margin;
		max.left += scroll.x;
		max.right += scroll.x;
		max.top += scroll.y;
		max.bottom += scroll.y;
		var rel = ($type(this.container) == 'element') ? this.container.getCoordinates() : max;
		this.moveTo({
			left: (this.position.x == 'right')
				? (Math.min(rel.right, max.right) - margin.x)
				: (Math.max(rel.left, max.left) + margin.x),
			top: (this.position.y == 'bottom')
				? (Math.min(rel.bottom, max.bottom) - margin.y)
				: (Math.max(rel.top, max.top) + margin.y)
		});
	}

});

eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('f(3r.3B.3t){2F.3u.12=6(O){k J 2m(O)};2r.3s().3x=\'12 {3y-3z:3c;3i:3f-3o;}\'+\'12 1o, 12 1o * {3V:3Z;43:41;}\'+\'12 1o * {t:2n;r:2n;}\'+\'v\\\\:*, o\\\\:*{3X:3N(#3M#3O)}\'}7 2m=J 1z({1q:6(){7 1Z=3Q.3L(1F,{2o:3K.1b,W:$3G});7 O=$2O({t:3F,r:3H},1Z.2o);7 u=(1Z.W||2r.3I(\'12\')).3J(O);f(u.1Y)k u;u.2h(\'3R\',5.2g);u.2h(\'3S\',5.2t);u.1Y=6(){k 5.2j=5.2j||J L(u)};k u.2E({t:O.t,r:O.r})},2g:6(e){7 1f=e.42;f(1f==\'t\'||1f==\'r\'){e=e.2K;e.19[1f]=e[1f];e.1Y().2w()}},2t:6(e){e=e.2K;7 1i=e.3Y;f(1i){1i.19.t=e.t;1i.19.r=e.r}}});7 L=J 1z({1q:6(u){5.W=J 2F(\'1o\').2E({t:u.3W,r:u.3E}).45(u);5.m=[[1,0,0],[0,1,0],[0,0,1]];5.l=0;5.1x=0;5.3l=[];5.z=[];5.Z=10;5.q=5.Z/2;5.1J=1;5.1I=1;5.1a=0;5.17=0;5.2Z=5.Z*1},25:1,1P:\'#2G\',2a:\'#3n\',1l:1,35:\'3p-3k\',1k:\'2p\',1U:\'3j\',31:0,32:\'#2G\',2Y:0,2X:0,1E:6(x,y){7 m=5.m,Z=5.Z,q=5.q;k[Z*(x*m[0][0]+y*m[1][0]+m[2][0])-q,Z*(x*m[0][1]+y*m[1][1]+m[2][1])-q]}});L.U({2D:6(){5.l=0;5.z.V=0},2J:6(x,y){5.z[5.l++]=\'m\';5.z[5.l++]=5.S(x,y);5.1a=x;5.17=y},2f:6(){5.z[5.l++]=\'x\'},T:6(x,y){5.z[5.l++]=\'l\';5.z[5.l++]=5.S(x,y);5.1a=x;5.17=y},3g:6(2H,2I,x,y){7 1R=2*2H,26=2*2I;5.2C((1R+5.1a)/3,(26+5.17)/3,(1R+x)/3,(26+y)/3,x,y)},2C:6(2v,2y,2z,2B,x,y){5.z[5.l++]=\' c \'+[5.S(2v,2y),5.S(2z,2B),5.S(x,y)].M(\',\');5.1a=x;5.17=y},3v:13.14,3w:6(x,y,D,P,11,18){f(5.1x===0)D*=5.Z;7 B=P.1j()*D,H=P.1s()*D,F=11.1j()*D,G=11.1s()*D;f(5.1x!==0){7 15=2A.15,1V=15/24,n=(18)?-1:1;f(n*11<P)(18)?P+=2*15:11+=2*15;5.T(B+x,H+y);3D(n*P+1V<11)5.T(x+(P+=n*1V).1j()*D,y+P.1s()*D);5.T(F+x,G+y);k}f(B==F&&!18)B+=0.3m;7 q=5.q,c=5.1E(x,y),2b=5.1J*D,29=5.1I*D;5.z[5.l++]=[18?\'46 \':\'4M \',(c[0]-2b).Q()+\',\'+(c[1]-29).Q()+\' \',(c[0]+2b).Q()+\',\'+(c[1]+29).Q()+\' \',5.S(B+x-q,H+y-q)+\' \',5.S(F+x-q,G+y-q),].M(\'\')},1N:6(x,y,w,h){5.2J(x,y);5.T(x+w,y);5.T(x+w,y+h);5.T(x,y+h);5.2f()},N:6(){5.1w(4Q)},1w:6(N){f(!5.z.V)k;7 1B=5.Z*10,1d=5.2a,1g=4L.1b(1d),p=5.1n(N&&1g?1d:5.1P),a=(N)?[\'4K=\',[\'<v:N \',!1g?5.2x(1d):\'p=\'+p.p+\' K="\'+p.K,\'"></v:N>\']]:[\'4G=\'+0.8*5.25*5.m[0][0]+\' 4F=\',[\'<v:1w\',\'4S=\',(5.1k==\'2p\')?\'4H\':5.1k,\'4I=\',5.1U,\'p=\',p.p,\'K="\',p.K,\'" />\']];5.W.37(\'2U\',[\'<v:2i z="\',5.z.M(\'\'),\'e" 2N="\'+1B+\',\'+1B+\'" \',a[0],\'2u">\',a[1].M(\' \'),\'</v:2i>\'].M(\'\'));f(N&&1d.R)5.W.4Y().N.4W=2u;5.2D()},4T:13.14,4X:13.14,1n:6(g){7 a=5.1l;f(g.2R(0,3)==\'1g\'){f(g.2T(3)=="a")a*=g.2S(/([\\d.]*)\\)$/)[1];g=g.36()}k{p:g,K:a}},2x:6(A){7 1M=\'\';f(A.2Q){7 1O=A.4U,1K=A.4V,E=\'\';f(A.E)2l(7 i=0,j=A.E.V;i<j;i++)E+=(1L*A.E[i][0]).Q()+\'% \'+A.E[i][1];1M+=((A.1v)?\'1b=4D 4h="0.2,0.2" 4g="0.2,0.2"\':\'1b=4i 4j=4l 4E=0 21=\'+4k*(1+A.21/2A.15)+\' \')+[\'p="\'+1O.p,\'K="\'+1O.K*1L+\'%\',\'4e="\'+1K.p,\'o:49="\'+1K.K*1L+\'%\',\'4a="\'+E].M(\'" \')}k(A.R)?\'1b="4d" 1r="\'+A.R.1r:1M},S:6(x,y){7 m=5.m,Z=5.Z,q=5.q;k(Z*(x*m[0][0]+y*m[1][0]+m[2][0])-q).Q()+\',\'+(Z*(x*m[0][1]+y*m[1][1]+m[2][1])-q).Q()}});L.U({2w:6(x,y,w,h){5.W.4z=\'\';5.m=[[1,0,0],[0,1,0],[0,0,1]]},4A:6(x,y,w,h){5.1N(x,y,w,h);5.N()},4B:6(x,y,w,h){5.1N(x,y,w,h);5.1w()}});L.U({4v:6(x,y){5.1J*=x;5.1I*=y;5.1e([[x,0,0],[0,y,0],[0,0,1]])},4p:6(1h){5.1x+=1h;7 c=1h.1j(),s=1h.1s();5.1e([[c,s,0],[-s,c,0],[0,0,1]])},4o:6(x,y){5.1e([[1,0,0],[0,1,0],[x,y,1]])},2s:6(2L,2k,2e,2q,1u,1A){5.1e([[2L,2e,1u],[2k,2q,1A],[0,0,1]])},4u:6(){5.m=[[1,0,0],[0,1,0],[0,0,1]];5.2s.4t(5,1F)},1e:6(b){7 m=5.m,o=[[0,0,0],[0,0,0],[0,0,0]];2l(7 i=3;i--;){7 2d=b[0][i],1H=b[1][i],1G=b[2][i];f(2d)5.1p(o[0],5.1y(2d,m[i]));f(1H)5.1p(o[1],5.1y(1H,m[i]));f(1G)5.1p(o[2],5.1y(1G,m[i]))}5.m=o},1y:6(x,y){k y.3a(6(1t){k x*1t})},1p:6(o,v){o[0]+=v[0];o[1]+=v[1];o[2]+=v[2]}});L.U({4s:6(Y){7 I=1F,V=I.V,C=(V==9)?4:0;7 X=Y.4r,38=X.t,3b=X.r;X.t=\'39\';X.r=\'39\';7 w=Y.t,h=Y.r;X.t=38;X.r=3b;7 1D=0,1C=0,1Q=w,27=h,1u=I[++C],1A=I[++C],2P=I[++C]||w,2V=I[++C]||h;f(V==9){1D=I[1];1C=I[2];1Q=I[3];27=I[4]}7 2c=1C/h,28=1D/w,m=5.m,Z=5.Z,d=5.1E(1u,1A).3a(6(1t){k(1t/Z).Q()});7 O=(!m[0][1]&&m[0][0]==1)?\'4q:\'+d[1]+\';3c:\'+d[0]:[\'4w:4C:4x.4y.4n(\',\'4m=\',m[0][0],\'4c=\',m[1][0],\'4b=\',m[0][1],\'47=\',m[1][1],\'48=\',d[0],\'4f=\',d[1],\')\'].M(\' \');5.W.37(\'2U\',[\'<v:30 19="\',O,\'" 2N="\',Z*10,\',\',Z*10,\'">\',[\'<v:Y\',\'1r=\',Y.1r,\'19=t:\'+Z*2P+\';r:\'+Z*2V,\'4R=\',2c,\'4J=\',1-28-1Q/w,\'4P=\',1-2c-27/h,\'4O=\',28,\'/>\'].M(\' \'),\'</v:30>\'].M(\' \'))},4N:13.14,40:13.14,3q:13.14});L.U({1S:[\'1P\',\'2a\',\'1l\',\'25\',\'1k\',\'1U\',\'2Z\',\'2Y\',\'2X\',\'31\',\'32\',\'35\'],3C:6(){7 1T={};5.1S.34(6(16){1T[16]=5[16]},5);5.1X.20(1T);5.1W.20(5.m)},3A:6(){7 33=5.1X.2W();5.1S.34(6(16){5[16]=33[16]},5);5.m=5.1W.2W()},1W:[],1X:[]});L.U({3h:6(B,H,F,G){k J 23(B,H,F,G,5)},3e:6(B,H,1v,F,G,22){k $2O(J 23(B,H,F,G,5),{1v:1v,22:22})}});7 23=J 1z({1q:6(B,H,F,G,1m){5.21=((G-H)/((F-B).2M(2)+(G-H).2M(2)).3T()).3U();5.1m=1m},2Q:6(C,g){g=5.1n(g);f(C==1||C==0){5[\'g\'+C]=g}44{f(!5.E)5.E=[];5.E.20([C,g.p])}},1n:6(g){7 a=5.1m.1l||1;f(g.2R(0,3)==\'1g\'){f(g.2T(3)=="a")a*=g.2S(/([\\d.]*)\\)$/)[1];g=g.36()}k{p:g,K:a}}});L.U({3P:6(R,1c){k J 3d(R,1c)}});7 3d=J 1z({1q:6(R,1c){5.R=R;5.1c=1c}});',62,309,'|||||this|function|var||||||||if|col||||return|||||color|Z2|height||width|el|||||path|obj|x0|off|rad|stops|x1|y1|y0|args|new|opacity|CanvasRenderingContext2D|join|fill|props|a0|round|img|coord|lineTo|implement|length|element|irS|image|||a1|canvas|Function|empty|PI|prop|currentY|cw|style|currentX|type|rep|fS|matMult|property|rgb|ang|efC|cos|lineCap|globalAlpha|ctx|processColor|div|sum|initialize|src|sin|val|dx|r0|stroke|rot|dotmult|Class|dy|size|sy|sx|getCoords|arguments|b2|b1|arcScaleY|arcScaleX|oc1|100|ret|rect|oc0|strokeStyle|sw|cx|states|copy|lineJoin|da|mStack|dStack|getContext|params|push|angle|r1|CanvasGradient||lineWidth|cy|sh|sxw|aSYr|fillStyle|aSXr|syh|b0|m21|closePath|changeproperty|attachEvent|shape|context|m12|for|Canvas|10px|properties|butt|m22|document|transform|resize|false|cp0x|clearRect|processColorObject|cp0y|cp1x|Math|cp1y|bezierCurveTo|beginPath|setStyles|Element|000|cpx|cpy|moveTo|srcElement|m11|pow|coordsize|extend|dw|addColorStop|substr|match|charAt|beforeEnd|dh|pop|shadowOffsetY|shadowOffsetX|miterLimit|group|shadowBlur|shadowColor|saved|each|globalCompositeOperation|rgbToHex|insertAdjacentHTML|w0|auto|map|h0|left|CanvasPattern|createRadialGradient|inline|quadraticCurveTo|createLinearGradient|display|miter|over|state|125|fff|block|source|putImageData|Browser|createStyleSheet|trident|Constructors|arcTo|arc|cssText|text|align|restore|Engine|save|while|clientHeight|300|defined|150|newElement|set|Object|link|default|url|VML|createPattern|Array|onpropertychange|onresize|sqrt|acos|position|clientWidth|behavior|firstChild|absolute|getImageData|hidden|propertyName|overflow|else|inject|at|M22|Dx|opacity2|colors|M21|M12|tile|color2|Dy|focussize|focusposition|gradient|method|180|linear|M11|Matrix|translate|rotate|top|runtimeStyle|drawImage|apply|setTransform|scale|filter|DXImageTransform|Microsoft|innerHTML|fillRect|strokeRect|progid|gradientradial|focus|filled|strokeweight|flat|joinstyle|cropright|stroked|String|wa|drawImageFromRect|cropleft|cropbottom|true|croptop|endcap|clip|col0|col1|alignshape|isPointInPath|getLast'.split('|'),0,{}))

var PieChart = new Class({
	options: {
		pieChartRadius: 60,
    	td_label_index: 0,		
    	td_index: 1,
    	index: 1
	},
	initialize: function(elData,el,options){
		this.setOptions(options);
		
		this.pieChartRadius = this.options.pieChartRadius;	
		this.pieChartDiameter = this.pieChartRadius * 2;
		this.pieVertices = 12;
		this.arcIncrementMultiplier = 1 / this.pieVertices;
		this.index = 0;
		this.tableIndex = this.options.index;
		this.areaIndex = 1;
		this.canvas = '';
		this.container = '';
		this.data_table = '';
		
		
		this.insertElements(el);		
    	aData=this.makeData(elData);		
		this.makePieChart(aData);		
		this.addToolTips();		
	},
	insertElements: function(el){
		
		this.container = new Element('div', {
			id: 'pieChartContainer' + this.tableIndex
		}).injectBefore($(el)).addClass('pieChartContainer');

		this.data_table = el.clone().injectBottom(this.container);
		el.dispose();
		
		new Element('div', {
			id: 'pieChartWrapper' + this.tableIndex
		}).injectTop(this.container).addClass('pieChartWrapper');
		
		this.canvas = new Element('canvas', {
			id: 'canvas' + this.tableIndex,
			width: this.pieChartDiameter,
			height: this.pieChartDiameter
		}).injectInside(this.container.getElement('.pieChartWrapper')).addClass('pieChartCanvas');
		
		new Element('map', {		
			id: 'pieChartMap' + this.tableIndex,
			name: 'pieChartMap' + this.tableIndex
		}).injectBottom(this.container).addClass('pieChartMap');
		
		new Asset.image(DIR_STATIC_SKIN+'/images/spacer.gif', {
			alt: '',
			usemap: '#pieChartMap' + this.tableIndex,
			width: this.pieChartDiameter,
			height: this.pieChartDiameter
		}).injectInside(this.container.getElement('.pieChartWrapper')).setStyles({
				'width': this.pieChartDiameter,
				'height': this.pieChartDiameter
			});

		new Element('div').injectBottom(this.container).addClass('clear');
	
	},
	makeData: function(elData) {
		var aData=[];
		elData.getChildren().each(function(el) {
			var data=el.getChildren();
			if ($(data[0])) {
				var color = data[0].getStyle('background').match(/#\w+/i);
				aData.extend([{
					'label': el.get('text'),
    				'value': data[1].get('text'),
    				'color': data[0].getStyle('background').match(/#\w+/i)[0]
				}]);			
			}
		});
		return aData;
	},	
	makePieChart: function(aData){

    	var  data = [], color, colors = [], labels = [], values = [], total = 0, value=0; 	
    	aData.each(function(item, index){    		
			labels[colors.length] = item.label;       	
			value=parseFloat(item.value);
			values[colors.length] = value;
        	total += value;       	
        	colors[colors.length] = item.color.hexToRgb();           	
		},this);		
    	
    	var ctx = this.canvas.getContext('2d');

		var tableLength = colors.length;
    	for (piece=0; piece < tableLength; piece++) {

        	var thisvalue = values[piece] / total;		
			var arcStartAngle = Math.PI * (- 0.5 + 2 * this.index);
			var arcEndAngle = Math.PI * (- 0.5 + 2 * (this.index + thisvalue));		

			ctx.beginPath();
			ctx.moveTo(this.pieChartRadius, this.pieChartRadius);
			ctx.arc(
            	this.pieChartRadius,
            	this.pieChartRadius,
            	this.pieChartRadius,
            	arcStartAngle,
            	arcEndAngle,
            	false
        	);
        	ctx.closePath();		
        	ctx.fillStyle = colors[piece];
        	ctx.fill();
		
			ctx.lineWidth = 1;
        	ctx.beginPath();
        	ctx.moveTo(this.pieChartRadius, this.pieChartRadius);

        	ctx.arc(
            	this.pieChartRadius,
            	this.pieChartRadius,
            	this.pieChartRadius,
            	arcStartAngle, 
            	arcEndAngle,
            	false
        	);
        	ctx.closePath();		
			ctx.strokeStyle = "#FFF";
			ctx.stroke();

			var arcIncrement = (arcEndAngle - arcStartAngle) * this.arcIncrementMultiplier;
		
			var xx = this.pieChartRadius + Math.round(Math.cos(arcStartAngle) * this.pieChartRadius);
			var yy = this.pieChartRadius + Math.round(Math.sin(arcStartAngle) * this.pieChartRadius);
			
			var coord = [];
			var coordIndex = 1;
						
			for (i = 0; i < ((this.pieVertices * 2) - 2); i = i+2) {				
				var arcAngle = arcStartAngle + arcIncrement * coordIndex;
				coord[i] = this.pieChartRadius + Math.round(Math.cos(arcAngle) * this.pieChartRadius);				
				coord[i+1] = this.pieChartRadius + Math.round(Math.sin(arcAngle) * this.pieChartRadius);
				coordIndex++;			
			}
		
			var xxEnd = this.pieChartRadius + Math.round(Math.cos(arcEndAngle) * this.pieChartRadius);
			var yyEnd = this.pieChartRadius + Math.round(Math.sin(arcEndAngle) * this.pieChartRadius);			

			var myArea = 'area' + this.tableIndex + '-' + piece;
		
			new Element('area', {
				'id': myArea ,
				'shape': 'poly',
				'coords': this.pieChartRadius + ',' + this.pieChartRadius + ',' + xx + ',' + yy + ',' + coord.join(',') +  ',' + xxEnd + ',' + yyEnd,
				'title': labels[piece]
			}).injectInside(this.container.getElement('.pieChartMap'));

        	this.index += thisvalue;
    	}

	this.tableIndex++;
    	
	},
	addToolTips: function(){    

			new Tips($$(document.getElementsByTagName('area')), {
				showDelay: 10,
				hideDelay: 10
			});	
			
	},
	getColor: function(i, totalSteps){
		var colori = i * 100 / totalSteps;		
		var frequency = Math.PI*2 / totalSteps;
		var center = 190;
		var amplitude = 60;
        var rgb = [];	
		rgb[0]   = Math.round(Math.sin(frequency * i + 0) * amplitude + center);
		rgb[1] = Math.round(Math.sin(frequency * i + 2) * amplitude + center);
		rgb[2]  = Math.round(Math.sin(frequency * i + 4) * amplitude + center);	
		return 'rgb(' + rgb.join(',') + ')';
	}	
});
PieChart.implement(new Options);

var Flext = new Class({
	Implements: Options,
	options: {
		aniTime: 300,
		maxHeight: 0,
		defaultMaxHeight: 1000,
		parentDepth: 6,
		growClass: 'growme',
		enterStoppedClass: 'stopenter',
		enterSubmitsClass: 'entersubmits',
		replaceGhostTextClass: 'replaceghosttext',
		growParentsClass: 'growparents',
		ghostTextAttr: 'ghosttext',
		ghostClassAttr: 'ghostclass'
	},
	initialize: function(el, options) {
		this.setOptions(options);
		
		this.el = el;
		
		this.defaulty = (this.el.get('id')=="form_comment_text")?100:200;
		this.dummy =  new Element("div", {
			styles:	{
				"overflow-x" : "hidden",
				"position"   : "absolute",
				"top"        : 0,
				"left"       : "-9999px"
			}
		}).setStyles(this.el.getStyles("font-size", "font-family", "width", "line-height", "padding")).inject(document.body);		
		
		this.autoGrow = el.hasClass(this.options.growClass);
		this.stopEnter = el.hasClass(this.options.enterStoppedClass);
		this.enterSubmits = el.hasClass(this.options.enterSubmitsClass);
		this.useGhostText = el.hasClass(this.options.replaceGhostTextClass);
		this.growParents = el.hasClass(this.options.growParentsClass);
		
		if(this.autoGrow) {
			this.resizer = new Fx.Tween(this.el, {duration: this.options.aniTime});
			this.getMaxSize();
			this.reachedMax = false;
			this.startSize = this.origSize = this.el.getSize().y;
			this.vertPadding = this.el.getStyle('padding-top').toInt()+this.el.getStyle('padding-bottom').toInt()+this.el.getStyle('border-top').toInt()+this.el.getStyle('border-bottom').toInt();
			this.el.setStyle('overflow', 'hidden');
			this.el.addEvents({
				'keyup': function(e) {
					this.checkSize(e);
				}.bind(this),
				'change': function(e) {
					this.checkSize(e);
				}.bind(this),
				'click': function(e) {
					this.checkSize(e);
				}.bind(this)
			});
		
			this.checkSize();
		}
		if(this.stopEnter) {
			this.el.addEvent('keydown', function(e) {
				if(e.key == 'enter') {
					e.stop();
					if(this.enterSubmits) {
						this.submitForm();
					}
				}
			}.bind(this));
		}
		if(this.useGhostText) {
			this.ghostText = this.el.get(this.options.ghostTextAttr);
			this.ghostClass = this.el.get(this.options.ghostClassAttr);
			if(this.ghostText) {
				if(this.el.value != this.ghostText) {
					this.el.removeClass(this.ghostClass);
				}
				this.el.addEvents({
					'focus': function(e) {
						if(this.el.value == this.ghostText) {
							this.el.set('value', '');
							if(this.ghostClass) {
								this.el.removeClass(this.ghostClass);
							}
						}
					}.bind(this),
					'blur': function(e) {
						if(this.el.value == '') {
							this.el.set('value', this.ghostText);
							if(this.ghostClass) {
								this.el.addClass(this.ghostClass);
							}
						}
					}.bind(this)
				});
			}
		}
		
	},
	getMaxSize: function() {
		this.maxSize = this.options.maxHeight;
		if(this.maxSize == 0) {
			var testmax = this.el.className.match(/maxheight-(\d*)/);
			if(testmax) {
				this.maxSize = testmax[1];
			}
			else {
				this.maxSize = this.options.defaultMaxHeight;
			}
		}
	},
	checkSize: function(e) {
		var theSize = this.el.getSize();
		var theScrollSize = this.el.getScrollSize();
		if(navigator.userAgent.toLowerCase().indexOf('chrome') > -1) { var checksize = (theScrollSize.y); }
		else var checksize = (theScrollSize.y+this.vertPadding);
		
		var html = this.el.get('value').replace(/\n|\r\n/g, '<br>X');
		if(this.dummy.get("html").toLowerCase() != html.toLowerCase()){
			this.dummy.set("html", html);
			
			if(this.origSize < this.dummy.getSize().y) var tmp={x:this.dummy.getSize().x,y:this.dummy.getSize().y+30}
			else var tmp={x:this.dummy.getSize().x,y:this.defaulty}
			theSize = theScrollSize = tmp;
			this.resizeIt(theSize, theScrollSize);			
		}else if(checksize > theSize.y) {
			this.resizeIt(theSize, theScrollSize);
		}
	},
	resizeIt: function(theSize, scrollSize) {
		var newSize = scrollSize.y;
		if((scrollSize.y+this.vertPadding) > this.maxSize && !this.reachedMax) {
			newSize = this.maxSize;
			this.el.setStyle('overflow', '');
			this.resizer.start('height', newSize);
			if(this.growParents) {
				var increasedSize = newSize - this.startSize;
				this.resizeParents(this.el, 0, increasedSize);
			}
		}
		if(!this.reachedMax) {
			var increasedSize = newSize - this.startSize;
			if(increasedSize < 0) increasedSize = 0;
			this.startSize = newSize;
			this.resizer.start('height', newSize);
			if(this.growParents) {
				this.resizeParents(this.el, 0, increasedSize);
			}
		}
	}, 
	resizeParents: function(el, num, incSize) {
		if(num < this.options.parentDepth) {
			var newel = el.getParent();
			if(newel) {
				if(newel.style.height && newel.style.height != '' ) {
					if(newel.retrieve('flextAdjusted')) {
						var newheight = (newel.getStyle('height').toInt()+incSize);
					} else {
						newel.store('flextAdjusted', true);
						var newheight = (newel.getStyle('height').toInt()+incSize+this.vertPadding);
					}
					newel.setStyle('height', newheight);
				}
				return this.resizeParents(newel, (num+1), incSize);
			}
			return true;
		} else {
			return true;
		}
	},
	submitForm: function() {
		var thisForm = this.el.getParent('form');
		if(thisForm) {
			var formName = thisForm.get('name');
			document[formName].submit();
			
		}
	}
});


window.addEvent('domready', function() {
	$$('textarea.flext').each(function(el, i) {
		new Flext(el); 
	});
});

function dump(arr,level) {
	var dumped_text = "";
	if(!level) level = 0;
	
	var level_padding = "";
	for(var j=0;j<level+1;j++) level_padding += "    ";
	
	if(typeof(arr) == 'object') {
		for(var item in arr) {
			var value = arr[item];
			
			if(typeof(value) == 'object') {
				dumped_text += level_padding + "'" + item + "' ...\n";
				dumped_text += dump(value,level+1);
			} else {
				dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
			}
		}
	} else {
		dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
	}
	return dumped_text;
}

var Autocompleter = new Class({

	Implements: [Options, Events],

	options: {
		minLength: 1,
		markQuery: true,
		width: 'inherit',
		maxChoices: 10,
		injectChoice: null,
		customChoices: null,
		emptyChoices: null,
		visibleChoices: true,
		className: 'autocompleter-choices',
		zIndex: 42,
		delay: 400,
		observerOptions: {},
		fxOptions: {},

		autoSubmit: false,
		overflow: false,
		overflowMargin: 25,
		selectFirst: false,
		filter: null,
		filterCase: false,
		filterSubset: false,
		forceSelect: false,
		selectMode: true,
		choicesMatch: null,

		multiple: false,
		separator: ', ',
		separatorSplit: /\s*[,;]\s*/,
		autoTrim: false,
		allowDupes: false,

		cache: true,
		relative: false
	},

	initialize: function(element, options) {
		this.element = $(element);
		this.setOptions(options);
		this.build();
		this.observer = new Observer(this.element, this.prefetch.bind(this), $merge({
			'delay': this.options.delay
		}, this.options.observerOptions));
		this.queryValue = null;
		if (this.options.filter) this.filter = this.options.filter.bind(this);
		var mode = this.options.selectMode;
		this.typeAhead = (mode == 'type-ahead');
		this.selectMode = (mode === true) ? 'selection' : mode;
		this.cached = [];
	},

	build: function() {
		if ($(this.options.customChoices)) {
			this.choices = this.options.customChoices;
		} else {
			this.choices = new Element('ul', {
				'class': this.options.className,
				'styles': {
					'zIndex': this.options.zIndex
				}
			}).inject(document.body);
			this.relative = false;
			if (this.options.relative) {
				this.choices.inject(this.element, 'after');
				this.relative = this.element.getOffsetParent();
			}
			this.fix = new OverlayFix(this.choices);
		}
		if (!this.options.separator.test(this.options.separatorSplit)) {
			this.options.separatorSplit = this.options.separator;
		}
		this.fx = (!this.options.fxOptions) ? null : new Fx.Tween(this.choices, $merge({
			'property': 'opacity',
			'link': 'cancel',
			'duration': 200
		}, this.options.fxOptions)).addEvent('onStart', Chain.prototype.clearChain).set(0);
		this.element.setProperty('autocomplete', 'off')
			.addEvent((Browser.Engine.trident || Browser.Engine.webkit) ? 'keydown' : 'keypress', this.onCommand.bind(this))
			.addEvent('click', this.onCommand.bind(this, [false]))
			.addEvent('focus', this.toggleFocus.create({bind: this, arguments: true, delay: 100}))
			.addEvent('blur', this.toggleFocus.create({bind: this, arguments: false, delay: 100}));
	},

	destroy: function() {
		if (this.fix) this.fix.destroy();
		this.choices = this.selected = this.choices.destroy();
	},

	toggleFocus: function(state) {
		this.focussed = state;
		if (!state) this.hideChoices(true);
		this.fireEvent((state) ? 'onFocus' : 'onBlur', [this.element]);
	},

	onCommand: function(e) {
		if (!e && this.focussed) return this.prefetch();
		if (e && e.key && !e.shift) {
			switch (e.key) {
				case 'enter':
					if (this.element.value != this.opted) return true;
					if (this.selected && this.visible) {
						this.choiceSelect(this.selected);
						return !!(this.options.autoSubmit);
					}
					break;
				case 'up': case 'down':
					if (!this.prefetch() && this.queryValue !== null) {
						var up = (e.key == 'up');
						this.choiceOver((this.selected || this.choices)[
							(this.selected) ? ((up) ? 'getPrevious' : 'getNext') : ((up) ? 'getLast' : 'getFirst')
						](this.options.choicesMatch), true);
					}
					return false;
				case 'esc': case 'tab':
					this.hideChoices(true);
					break;
			}
		}
		return true;
	},

	setSelection: function(finish) {
		var input = this.selected.inputValue, value = input;
		var start = this.queryValue.length, end = input.length;
		if (input.substr(0, start).toLowerCase() != this.queryValue.toLowerCase()) start = 0;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			value = this.element.value;
			start += this.queryIndex;
			end += this.queryIndex;
			var old = value.substr(this.queryIndex).split(split, 1)[0];
			value = value.substr(0, this.queryIndex) + input + value.substr(this.queryIndex + old.length);
			if (finish) {
				var tokens = value.split(this.options.separatorSplit).filter(function(entry) {
					return this.test(entry);
				}, /[^\s,]+/);
				if (!this.options.allowDupes) tokens = [].combine(tokens);
				var sep = this.options.separator;
				value = tokens.join(sep) + sep;
				end = value.length;
			}
		}
		this.observer.setValue(value);
		this.opted = value;
		if (finish || this.selectMode == 'pick') start = end;
		this.element.selectRange(start, end);
		this.fireEvent('onSelection', [this.element, this.selected, value, input]);
	},

	showChoices: function() {
		var match = this.options.choicesMatch, first = this.choices.getFirst(match);
		this.selected = this.selectedValue = null;
		if (this.fix) {
			var pos = this.element.getCoordinates(this.relative), width = this.options.width || 'auto';
			this.choices.setStyles({
				'left': pos.left,
				'top': pos.bottom,
				'width': (width === true || width == 'inherit') ? pos.width : width
			});
		}
		if (!first) return;
		if (!this.visible) {
			this.visible = true;
			this.choices.setStyle('display', '');
			if (this.fx) this.fx.start(1);
			this.fireEvent('onShow', [this.element, this.choices]);
		}
		if (this.options.selectFirst || this.typeAhead || first.inputValue == this.queryValue) this.choiceOver(first, this.typeAhead);
		var items = this.choices.getChildren(match), max = this.options.maxChoices;
		var styles = {'overflowY': 'hidden', 'height': ''};
		this.overflown = false;
		if (items.length > max) {
			var item = items[max - 1];
			styles.overflowY = 'scroll';
			styles.height = item.getCoordinates(this.choices).bottom;
			this.overflown = true;
		};
		this.choices.setStyles(styles);
		this.fix.show();
		if (this.options.visibleChoices) {
			var scroll = document.getScroll(),
			size = document.getSize(),
			coords = this.choices.getCoordinates();
			if (coords.right > scroll.x + size.x) scroll.x = coords.right - size.x;
			if (coords.bottom > scroll.y + size.y) scroll.y = coords.bottom - size.y;
			window.scrollTo(Math.min(scroll.x, coords.left), Math.min(scroll.y, coords.top));
		}
	},

	hideChoices: function(clear) {
		if (clear) {
			var value = this.element.value;
			if (this.options.forceSelect) value = this.opted;
			if (this.options.autoTrim) {
				value = value.split(this.options.separatorSplit).filter($arguments(0)).join(this.options.separator);
			}
			this.observer.setValue(value);
		}
		if (!this.visible) return;
		this.visible = false;
		if (this.selected) this.selected.removeClass('autocompleter-selected');
		this.observer.clear();
		var hide = function(){
			this.choices.setStyle('display', 'none');
			this.fix.hide();
		}.bind(this);
		if (this.fx) this.fx.start(0).chain(hide);
		else hide();
		this.fireEvent('onHide', [this.element, this.choices]);
	},

	prefetch: function() {
		var value = this.element.value, query = value;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			var values = value.split(split);
			var index = this.element.getSelectedRange().start;
			var toIndex = value.substr(0, index).split(split);
			var last = toIndex.length - 1;
			index -= toIndex[last].length;
			query = values[last];
		}
		if (query.length < this.options.minLength) {
			this.hideChoices();
		} else {
			if (query === this.queryValue || (this.visible && query == this.selectedValue)) {
				if (this.visible) return false;
				this.showChoices();
			} else {
				this.queryValue = query;
				this.queryIndex = index;
				if (!this.fetchCached()) this.query();
			}
		}
		return true;
	},

	fetchCached: function() {
		return false;
		if (!this.options.cache
			|| !this.cached
			|| !this.cached.length
			|| this.cached.length >= this.options.maxChoices
			|| this.queryValue) return false;
		this.update(this.filter(this.cached));
		return true;
	},

	update: function(tokens) {
		this.choices.empty();
		this.cached = tokens;
		var type = tokens && $type(tokens);
		if (!type || (type == 'array' && !tokens.length) || (type == 'hash' && !tokens.getLength())) {
			(this.options.emptyChoices || this.hideChoices).call(this);
		} else {
			if (this.options.maxChoices < tokens.length && !this.options.overflow) tokens.length = this.options.maxChoices;
			tokens.each(this.options.injectChoice || function(token){
				var choice = new Element('li', {'html': this.markQueryValue(token)});
				choice.inputValue = token;
				this.addChoiceEvents(choice).inject(this.choices);
			}, this);
			this.showChoices();
		}
	},

	choiceOver: function(choice, selection) {
		if (!choice || choice == this.selected) return;
		if (this.selected) this.selected.removeClass('autocompleter-selected');
		this.selected = choice.addClass('autocompleter-selected');
		this.fireEvent('onSelect', [this.element, this.selected, selection]);
		if (!this.selectMode) this.opted = this.element.value;
		if (!selection) return;
		this.selectedValue = this.selected.inputValue;
		if (this.overflown) {
			var coords = this.selected.getCoordinates(this.choices), margin = this.options.overflowMargin,
				top = this.choices.scrollTop, height = this.choices.offsetHeight, bottom = top + height;
			if (coords.top - margin < top && top) this.choices.scrollTop = Math.max(coords.top - margin, 0);
			else if (coords.bottom + margin > bottom) this.choices.scrollTop = Math.min(coords.bottom - height + margin, bottom);
		}
		if (this.selectMode) this.setSelection();
	},

	choiceSelect: function(choice) {
		if (choice) this.choiceOver(choice);
		this.setSelection(true);
		this.queryValue = false;
		this.hideChoices();
	},

	filter: function(tokens) {
		return (tokens || this.tokens).filter(function(token) {
			return this.test(token);
		}, new RegExp(((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp(), (this.options.filterCase) ? '' : 'i'));
	},

	markQueryValue: function(str) {
		return (!this.options.markQuery || !this.queryValue) ? str
			: str.replace(new RegExp('(' + ((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp() + ')', (this.options.filterCase) ? '' : 'i'), '<span class="autocompleter-queried">$1</span>');
	},
	addChoiceEvents: function(el) {
		return el.addEvents({
			'mouseover': this.choiceOver.bind(this, [el]),
			'click': this.choiceSelect.bind(this, [el])
		});
	}
});

var OverlayFix = new Class({

	initialize: function(el) {
		if (Browser.Engine.trident) {
			this.element = $(el);
			this.relative = this.element.getOffsetParent();
			this.fix = new Element('iframe', {
				'frameborder': '0',
				'scrolling': 'no',
				'src': 'javascript:false;',
				'styles': {
					'position': 'absolute',
					'border': 'none',
					'display': 'none',
					'filter': 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)'
				}
			}).inject(this.element, 'after');
		}
	},

	show: function() {
		if (this.fix) {
			var coords = this.element.getCoordinates(this.relative);
			delete coords.right;
			delete coords.bottom;
			this.fix.setStyles($extend(coords, {
				'display': '',
				'zIndex': (this.element.getStyle('zIndex') || 1) - 1
			}));
		}
		return this;
	},

	hide: function() {
		if (this.fix) this.fix.setStyle('display', 'none');
		return this;
	},

	destroy: function() {
		if (this.fix) this.fix = this.fix.destroy();
	}

});

Element.implement({

	getSelectedRange: function() {
		if (!Browser.Engine.trident) return {start: this.selectionStart, end: this.selectionEnd};
		var pos = {start: 0, end: 0};
		var range = this.getDocument().selection.createRange();
		if (!range || range.parentElement() != this) return pos;
		var dup = range.duplicate();
		if (this.type == 'text') {
			pos.start = 0 - dup.moveStart('character', -100000);
			pos.end = pos.start + range.text.length;
		} else {
			var value = this.value;
			var offset = value.length - value.match(/[\n\r]*$/)[0].length;
			dup.moveToElementText(this);
			dup.setEndPoint('StartToEnd', range);
			pos.end = offset - dup.text.length;
			dup.setEndPoint('StartToStart', range);
			pos.start = offset - dup.text.length;
		}
		return pos;
	},
	selectRange: function(start, end) {
		if (Browser.Engine.trident) {
			var diff = this.value.substr(start, end - start).replace(/\r/g, '').length;
			start = this.value.substr(0, start).replace(/\r/g, '').length;
			var range = this.createTextRange();
			range.collapse(true);
			range.moveEnd('character', start + diff);
			range.moveStart('character', start);
			range.select();
		} else {
			this.focus();
			this.setSelectionRange(start, end);
		}
		return this;
	}

});

Autocompleter.Base = Autocompleter;

Autocompleter.Request = new Class({

	Extends: Autocompleter,

	options: {
		postData: {},
		ajaxOptions: {},
		postVar: 'value'

	},

	query: function(){
		var data = $unlink(this.options.postData) || {};
		data[this.options.postVar] = this.queryValue;
		var indicator = $(this.options.indicator);
		if (indicator) indicator.setStyle('display', '');
		var cls = this.options.indicatorClass;
		if (cls) this.element.addClass(cls);
		this.fireEvent('onRequest', [this.element, this.request, data, this.queryValue]);
		this.request.send({'data': data});
	},

	queryResponse: function() {
		var indicator = $(this.options.indicator);
		if (indicator) indicator.setStyle('display', 'none');
		var cls = this.options.indicatorClass;
		if (cls) this.element.removeClass(cls);
		return this.fireEvent('onComplete', [this.element, this.request]);
	}

});

Autocompleter.Request.JSON = new Class({

	Extends: Autocompleter.Request,

	initialize: function(el, url, options) {
		this.parent(el, options);
		this.request = new Request.JSON($merge({
			'url': url,
			'link': 'cancel'
		}, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this));
	},

	queryResponse: function(response) {
		this.parent();
		this.update(response);
	}

});

Autocompleter.Request.HTML = new Class({

	Extends: Autocompleter.Request,

	initialize: function(el, url, options) {
		this.parent(el, options);
		this.request = new Request.HTML($merge({
			'url': url,
			'link': 'cancel',
			'update': this.choices
		}, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this));
	},

	queryResponse: function(tree, elements) {
		this.parent();
		if (!elements || !elements.length) {
			this.hideChoices();
		} else {
			this.choices.getChildren(this.options.choicesMatch).each(this.options.injectChoice || function(choice) {
				var value = choice.get('text');
				choice.inputValue = value;
				this.addChoiceEvents(choice.set('html', this.markQueryValue(value)));
			}, this);
			this.showChoices();
		}

	}

});

Autocompleter.Ajax = {
	Base: Autocompleter.Request,
	Json: Autocompleter.Request.JSON,
	Xhtml: Autocompleter.Request.HTML
};

var Observer = new Class({

	Implements: [Options, Events],

	options: {
		periodical: false,
		delay: 1000
	},

	initialize: function(el, onFired, options){
		this.element = $(el) || $$(el);
		this.addEvent('onFired', onFired);
		this.setOptions(options);
		this.bound = this.changed.bind(this);
		this.resume();
	},

	changed: function() {
		var value = this.element.get('value');
		if ($equals(this.value, value)) return;
		this.clear();
		this.value = value;
		this.timeout = this.onFired.delay(this.options.delay, this);
	},

	setValue: function(value) {
		this.value = value;
		this.element.set('value', value);
		return this.clear();
	},

	onFired: function() {
		this.fireEvent('onFired', [this.value, this.element]);
	},

	clear: function() {
		$clear(this.timeout || null);
		return this;
	},

	pause: function(){
		if (this.timer) $clear(this.timer);
		else this.element.removeEvent('keyup', this.bound);
		return this.clear();
	},

	resume: function(){
		this.value = this.element.get('value');
		if (this.options.periodical) this.timer = this.changed.periodical(this.options.periodical, this);
		else this.element.addEvent('keyup', this.bound);
		return this;
	}

});

var $equals = function(obj1, obj2) {
	return (obj1 == obj2 || JSON.encode(obj1) == JSON.encode(obj2));
};
