
Array.implement({
	setBlock: function() {
		this.each(function(item) { item.setBlock(); });
		return this;
	},
	setNone: function() {
		this.each(function(item) { item.setNone(); });
		return this;
	},
	setHref: function(h) {
		this.each(function(item) { item.setHref(h); });
		return this;
	}
});

var Dialog = new Class({
	Implements: [Events, Options],
	options: {
		transition: Fx.Transitions.Bounce.easeOut,
		overflow: { left: 0, top: 0 },
		duration: 300,
		distance: 20
	},
	initialize: function(container, options) {
		this.run = false;
		this.container = container;
		this.arrow = container.getElement('.arrow');
		this.setOptions(options);
		this.current = null;
		this.fx = new Fx.Morph(this.container, {
			duration: this.options.duration,
			link: 'ignore'
		});
		
		// For use with removeEvent() method
		this._detect = this.detect.bindWithEvent(this);
	},
	detect: function(event) {
		var t = $(new Event(event).target);
		if (this.container == t || 
			this.container.hasChild(t) || 
			(t.hasClass('bulle') && t != this.current))
				return;

		this.hide();
	},
	chain: function(event, target) {
		this.fireEvent('onShow', event);
		this.current = target;
		this.run = false;
	},
	hide: function() {
		if (this.run || !this.top)
			return;

		this.run = true;
		this.fx.start({
			opacity: (Browser.Engine.trident) ? 1 : 0,
			top: this.top - ((Browser.Engine.trident) ? 0 : this.options.distance)
		}).chain((function() {
			this.run = false;
			this.current = null;			
			document.removeEvent('click', this._detect);
			this.fireEvent('onHide');
			this.container.setStyles({
				visibility: 'hidden',
				display: 'none'
			});
		}).bind(this));
	},
	show: function(event) {
		//console.log($type(event));
		this.event = event;
		var scrolltop, eoo, moo, target = event;
		//var scrolltop, eoo, moo, target = $(new Event(event).target);
//		if (this.current == target || this.run)
//			return;
		
		this.run = true;
		this.container.setBlock();

		eoo = target.getCoordinates();
		moo = this.container.getCoordinates();

		this.top = eoo.top - moo.height + this.options.overflow.top;		
		this.left = eoo.left - moo.width + this.options.overflow.left; 

		if (this.left < 0) this.left = 0;
					
		if (this.top < 0) {
			this.arrow.addClass('top');		
			this.top += moo.height + eoo.height + (this.options.overflow.top * -2);
		} else this.arrow.removeClass('top');
		
		this.arrow.setStyles({
			left:  eoo.left - this.left - this.arrow.getStyle('margin-right').toInt(),
			top: eoo.top - this.top 
		});
		
		if (this.current) {
			this.fx.start({left: this.left, top: this.top}).chain((function() {
				this.chain(event, target);
			}).bind(this));
		} else {
			this.container.setStyles({
				left: this.left,		
				top: this.top + ((Browser.Engine.trident) ? 0 : this.options.distance),
				visibility: 'visible',
				opacity: (Browser.Engine.trident) ? 1 : 0
			});

			this.fx.start({opacity: 1, top: this.top}).chain((function() {
				document.addEvent('click', this._detect);
				this.chain(event, target);
			}).bind(this));
		}
		return this;
	}
});

var Discreet = new Class({
	Implements: [Events, Options],
	options: {
		duration: 300,
		hide: 0.2
	},
	initialize: function(container, element, options) {
		this.setOptions(options);
		this.container = container;
		this.element = element;
		
		this.container.addEvents({
			mouseenter: this.enter.bind(this),
			mouseleave: this.leave.bind(this)
		});
	
		this.element.setOpacity(this.options.hide);
		this.fx = new Fx.Tween(this.element, {
			duration: this.options.duration, 
			link: 'ignore'
		});
	},
	enter: function() {
		this.fx.start('opacity', 1);
	},
	leave: function() {
		this.fx.start('opacity', this.options.hide);
	}
})

Element.implement({
	getCharacterSize: function() {
		var element = this.clone(), size, style;
		style = new Hash(this.getStyles('font-size', 'font-weight')).extend({
			position: 'absolute',
			visibility: 'hidden',
			display: 'block',
			top: 0
		});

		element.setStyles(style).inject(document.body);
		size = element.getSize();
		element.destroy();
		return size;
	},
	getElementsWithAssociate: function(filter) {
		var reg = new RegExp("[.]|#", "g"), a = filter.split(',').map(function(item) {
    		return item.trim().replace(reg, '');
		});
		return this.getElements(filter).associate(a);
	},
	diselected: function() {
		with (this) {
			onselectstart = function() { return false; };
			['MozUser', 'KhtmlUser', 'User'].each(function(p) {
				setStyle(p + 'Select', 'none');
			});
		}		
		return this;
	},
	/*
	 * BUG: if not is dom tree, with IE before 
	 *		center element use injectInside, example:
	 *		img.injectInside(container).center(container);
	 */
	center: function(container) {
		var eoo = this.getCoordinates(), coo = container.getCoordinates(), h, w;

		// For image
		h = (eoo && eoo.height) ? eoo.height : this.height;
		w = (eoo && eoo.width) ? eoo.width : this.width;

		this.setStyles({
			'top': -(h / 2) + (coo.height / 2),
			'left': -(w / 2) + (coo.width / 2),
			'height': h,
			'width': w
		});
		return this;
	},	
	setHref: function(h) {
		h = h || 'javascript:void(0);';
		if (this.get('tag') != 'a')
			return this;
		
		return this.set('href', h);
	},
	setBlock: function() {
		return this.setStyle('display', 'block');
	},
	setNone: function() {
		return this.setStyle('display', 'none');
	}
});
// This Class extends the input fields to powered the search. 
// It shows a list of the selected informations that are beginning
// by the first letter hitten.

var Inputs = new Class({
    options: {
		container: false
	},
	initialize: function(container, options) {
		this.options.container = $(window);
//		this.parent(container.setBlock().fade('hide'), options);
//		this.title = this.element.getElement('.title').diselected();
		this.search = $('searchUsr');
		this.search.removeEvents();
		this.search.addEvent('keyup', this.keyup.bindWithEvent(this));
		this.sb = new Scrollbar($('usrResult'), $$('#usrResult .wrapper')[0].diselected(), {
			orientation: 'vertical', 
			discreet: true, 
			wheel: true
		});
		
		this.list();
	},
	toggle: function() {
		this.element.fade('toggle');
		return this;		
	},
	keyup: function(event) {
		event = new Event(event);
		var filter = /^up|down|left|right|enter$/;

		if (this.search.value.length == 0)
			return;

		if (!filter.test(event.key))
			this.list();
	},
	list: function() {
		this.row = [];
		this.sb.wrapper.empty();

		new Request.JSON({
			url: "ajax.administration.php",
			onComplete: (function(response) {
				response.each(function(player, index) {
					var row = new Element('span', {
						'class': (index % 2) ? 'lite' : 'dark'
					}).adopt([
						new Element('div', {'class': (player.member == 1) ? 'member' : 'nomember'}),
						new Element('div', {							
							'class': 'label',
							'text': player.name + ' ' + player.surname
						})
					]);

					row.addEvent('click', this.select.bind(this, row));
					row.store('id', player.id);
					row.inject(this.sb.wrapper);
					this.row.push(row);
				}, this);
								
				this.sb.setCursor();				
			}).bind(this)
		}).send(JSON.encode({'userGetList': {filter: this.search.value}}));
	},
	select: function(row) {
		console.log( row );
	},
	start: function(event) {
		var target = $(new Event(event).target);
		if (target.hasClass('title'))
			this.parent(event);
	}
});
/*
 * Add onChange event for all step function
 */

Fx.Custom = new Class({
    Extends: Fx.Tween,
	step: function() {
		this.fireEvent('onChange');
		this.parent();
	}
});

/*
 * Extend Discreet class to add move condition 
 */

var DiscreetSlider = new Class({
	Extends: Discreet,
	initialize: function(container, element, slider, options) {
		this.slider = slider;
		this.parent(container, element, options);
	},	
	leave: function() {
		//if (this.slider.ondrag) return;
		this.parent();
	}	
});

/*
 * BUG: Avec la valeur min negative
 * Future demo:
 *
 * negative value
 * grid
 * array
 * proportional value
 */
 
var Slider = new Class({
    Extends: Drag.Move,
 	options: {
		// exemple: function() { this.element.set('html', this.options.value); }
		setHTML: $empty,
		orientation: 'horizontal',
		duration: 300,
		value: null,
		snap: 0,
		max: 10,
		min: 0,
		snap: 0,
		magnet: false
	},
	initialize: function(container, options) {
	
		//this.options.snap = 0;
		//this.options.invert = true;
	
		this.ondrag = false;
		this.options.container = container.diselected();
		this.parent(container.getElement('div.cursor'), options);

		/*
		this.addEvent('drop', (function() {	
			this.ondrag = false;
			//console.log('drop');
		}).bind(this));
		*/

		/*
		this.addEvent('start', (function() {
			this.ondrag = true;	
			//console.log('start');
		}).bind(this));
		*/

		switch(this.options.orientation) {
			case 'horizontal': 	this.mode = {axe: 'x', offset: 'width', direction: 'left'}; break;
			case 'vertical': 	this.mode = {axe: 'y', offset: 'height', direction: 'top'}; break;
		}
		
		this.container.addEvent('mousedown', this.mousedown.bindWithEvent(this));
 		this.container.addEvent('mousewheel', this.mousewheel.bindWithEvent(this));
 
		this.fx = new Fx.Custom(this.element, {
			duration: this.options.duration,
			link: 'cancel'
		}).addEvent('onChange', (function() {
			this.proportion();
			this.fireEvent('onChange');
		}).bind(this));
		
		// Tmp
		this.w = 0;
	},	
	getCoor: function() {
		var element = {c: this.container, e: this.element}; 
		for (p in element) {
			var coor = element[p].getCoordinates();
			element[p] = {
				direction: coor[this.mode.direction],
				offset: coor[this.mode.offset]
			}
		}
		return element;
	},
	getValue: function() {
		return this.options.value;
	},
	setValue: function(value) {
		if (value < this.options.min)
			value = this.options.min;

		// Exepte with value = 0
		if (value != 0 && value > this.options.max)
			value = this.options.max;

		var coo = this.getCoor(), p, x;
		p = (coo.c.offset - coo.e.offset) / (this.options.max - this.options.min);
		x = p * (value - this.options.min);

		//console.log(p);
		//console.log(x);

		this.options.value = value;
		this.to(x);
		return this;
		
		/*
		this.fx.start(this.mode.direction, x).chain((function() {
			this.options.setHTML.bind(this)();
			this.fireEvent('onComplete');
		}).bind(this));
		*/
	},
	proportion: function() {
		var coo = this.getCoor(), p, x;
		p = (coo.e.direction - coo.c.direction) / (coo.c.offset - coo.e.offset);
		x = (this.options.max - this.options.min) * p;
		
		this.options.value = (this.options.min + x).round();
		this.options.setHTML.bind(this)();
	},
	to: function(x) {
		var coo = this.getCoor();
		if (x < 0)
			x = 0;

		if (x > coo.c.offset - coo.e.offset)
			x = coo.c.offset - coo.e.offset;

		this.fx.start(this.mode.direction, x).chain((function() {
			this.proportion();		
			this.fireEvent('onComplete');
		}).bind(this));	
	},
	start: function(event) {
		if (this.options.magnet) {
			var coo = this.getCoor(), p;
			p = (coo.c.offset - coo.e.offset) / (this.options.max - this.options.min);
			this.options.magnet = p.round();
		}
	
	   	this.ondrag = true;
		this.parent(event);
	},
	stop: function(event) {
	   	this.ondrag = false;
	   	this.parent(event);
	},
	drag: function(event) {
		if (this.options.magnet) {
			var now = event.page[this.mode.axe] - this.mouse.pos[this.mode.axe],
				m = this.options.magnet, value = this.options.value - this.options.min,	
				condition;
			
			condition = (this.now < now) ? (now > m * (value + 1)) : (now < m * (value - 1));
			if (condition)
				this.parent(event);
			
			this.now = now;
		} else {
 			this.parent(event);
		}

		this.proportion();
		this.fireEvent('onChange');		
	},
	mousewheel: function(event) {
		event = new Event(event);
		event.stop();

		/*
		var coo = this.getCoor(), condition, x;
		condition = (this.options.orientation == 'horizontal') ? 
						(event.wheel < 0) : (event.wheel > 0);

		x = (coo.e.direction - coo.c.direction);
		if (!condition)
			x += (this.options.duration / 10) + this.w;
		else
			x -= (this.options.duration / 10) + this.w;

		this.element.setStyle(this.mode.direction, x);
		*/
		
		/*
		this.w += 10;
		(function() {
			if (this.w == 0)
				return;
			
			var coo = this.getCoor(), condition, x;
			condition = (this.options.orientation == 'horizontal') ? 
				(event.wheel < 0) : (event.wheel > 0);
	
			x = (coo.e.direction - coo.c.direction);
			if (!condition)
				x += (this.options.duration / 10) + this.w;
			else
				x -= (this.options.duration / 10) + this.w;
	
			this.to(x);
			
			console.log(this.w);
			this.w = 0;
			
		}).bind(this).delay(300);		
		*/
		
		
		var coo = this.getCoor(), condition, x;
		condition = (this.options.orientation == 'horizontal') ? 
			(event.wheel < 0) : (event.wheel > 0);

		x = (coo.e.direction - coo.c.direction);
		if (!condition)
			x += (this.options.duration / 10);
		else
			x -= (this.options.duration / 10);

		this.to(x);
	},
	mousedown: function(event) {
		/*
		if (this.ondrag) return;
		
		var coo = this.getCoor(), x, n;
		
		x = event.page[this.mode.axe] - coo.c.direction;

		n = coo.e.direction - coo.c.direction;

		console.log(n);
		*/

		/*
		n = (x / this.options.magnet).round();

		console.log(n);

		var m = n * this.options.magnet;

		var s = new Element('div', {
			'styles': {
				'position': 'absolute',
				'height': 2,
				'left': m,
				'width': this.options.magnet,
				'background': 'gray'
			}
		});
		
		s.inject(this.container);

		//console.log('x: %s', x);
		//console.log('m: %s', m);
		//console.log('m + offset: %s', m + coo.e.offset);

		if (x >= m && x < (m + coo.e.offset)) {
			
			console.log('in');
			
			//console.log(n + this.options.min);
			//this.setValue(n + this.options.min);
			
			//this.element.setStyle('left', m);
			//this.to(m);
		}
		*/

		/*
		if (x > m && x < (m + coo.c.direction)) {
			
			console.log(n);
			
			this.setValue(n + this.options.min);			
		}*/
		
		/*
		var coo = this.getCoor(), x;
		//x = event.client[this.mode.axe] - coo.c.direction - (coo.e.offset / 2);
		x = event.client[this.mode.axe] - coo.c.direction;
		x = (x / this.options.magnet);
		
		//x = x.round() * this.options.magnet
		
		x = x.round() + this.options.min;
		console.log(x);
		this.setValue(x);
		*/
		
		if (this.ondrag) return;
		var coo = this.getCoor(), x;
		x = event.client[this.mode.axe] - coo.c.direction - (coo.e.offset / 2);
		this.to(x);
	}
});

var Tabpanel = new Class({
	Implements: [Options],
	options: {
		duration: 500,
		selected: 0
	},
	initialize: function(content, options) {
		this.content = content;
		this.setOptions(options);
		this.tab = this.content.getElements('a.tab');
		this.panel = this.content.getElements('div.panel');

		this.tab.each(function(tab, index) {
			tab.setHref().addEvent('click', this.click.bind(this, index));
		}, this);

		if (this.options.selected !== false)
			this.select(this.options.selected, true);
	},
	click: function(index) {
		this.select(index);
	},
	select: function(index, initialize) {
		if (!(index < this.panel.length || index > 0) || this.index == index) return;
		
		if (this.tab.length) {
			this.tab.each(function(panel) { panel.removeClass('selected'); });
			this.tab[index].addClass('selected');
		}
	
		this.index = index;
		this.panel.each(function(panel) { panel.setNone(); });
		
		this.panel[index].setStyles({
			opacity: (initialize) ? 1 : 0,
			display: 'block'
		});

		if (initialize) return;
		var fx = new Fx.Tween(this.panel[index]);
		fx.start('opacity', 1);
		return this;
	}
});

var Template = new Class({
	set: function(property, data) {
		if (!this.element || $type(this.element) != 'array')
			return;
	
		this.element.each(function(element, index) {
			var value = ($type(data[index]) == 'element') ? data[index].get('text') : data[index];
			element.set(property, value);
		});
	}
});

var Tips = {};

Tips.Base = new Class({
	Implements: [Options],
	options: {
		delay: 1500,
		autohide: true,
		className: 'tooltip',
		transition: {
			show: Fx.Transitions.Bounce.easeOut,
			hide: Fx.Transitions.linear
		},
		duration: {
			show: 400,
			hide: 100
		}
	},
	initialize: function(element, options) {
		this.element = element;
		this.setOptions(options);
		this.container = new Element('a', {
			'class': this.options.className,
			opacity: 0,
			events: {
				'click': this.setHide.bind(this, 1)
			}
		});
		
		['left', 'middle', 'right'].each(function(cn, i) {
			new Element('span', {'class': cn}).inject(this);
		}, this.container);
		
		this.run = false;
		this.fx = new Fx.Tween(this.container.inject(document.body), {
			transition: this.options.transition,
			link: 'ignore'
		});
		return this;
	},
	setValue: function(value) {
		this.container.getElement('span.middle').set('html', value);
		return this;
	},	
	setShow: function() {
		if (this.run) return;
		this.run = true;
		var ic = this.element.getCoordinates(), tc = this.container.getCoordinates();
			
		this.container.setStyles({
			top: ic.top - (tc.height / 2) + (ic.height / 2),
			left: ic.left - tc.width - 100,
			opacity: 1
		});
				
		this.fx.options.duration = this.options.duration.show;
		this.fx.options.transition = this.options.transition.show;
		this.fx.start('left', ic.left - tc.width + 5);		
		
		if (this.options.autohide)
			this.setHide();
	},
	setHide: function(delay) {
		(function() {
			if (!this.run) return;

			// BUG: Fix IE opacity with PNG
			if (Browser.Engine.trident) {
				this.container.set('opacity', 0);
				this.run = false;
				return;
			}
			
			this.fx.options.duration = this.options.duration.hide;
			this.fx.options.transition = this.options.transition.hide;
			this.fx.start('opacity', 0).chain((function() {
				this.run = false;
			}).bind(this));
			
		}).bind(this).delay(delay || this.options.delay);
	}
});

Tips.Info = new Class({
	Extends: Tips.Base,
	initialize: function(element, options) {
		this.parent(element, options);
		this.element.addEvents({
			mouseenter: this.mouse.bindWithEvent(this),
			mouseleave: this.mouse.bindWithEvent(this),
			click: this.mouse.bindWithEvent(this)
		});

		this.setValue(this.element.getProperty('tip'));
		this.container.addEvent('mouseleave', (function(event) {
			if (new Event(event).relatedTarget != this.element)
				this.setVisibility(0);
		}).bind(this));		
	},
	mouse: function(event) {
		var event = new Event(event), rt = event.relatedTarget;
		switch(event.type) {
			case 'mouseover': 	if (!this.container.hasChild(rt)) this.setShow(); break;	
			case 'mouseout':	if (!this.container.hasChild(rt)) this.setVisibility(0); break;
			case 'click':		this.setVisibility(0); break;
		}			 
	},
	setVisibility: function(opacity) {
		// BUG: Fix IE opacity with PNG
		if (Browser.Engine.trident) this.container.setOpacity(opacity);
		else this.container.fade(opacity);
	},
	setShow: function() {
		var ic = this.element.getCoordinates(), tc = this.container.getCoordinates();
		this.container.setStyles({
			//opacity: 0,
			top: ic.top - (tc.height / 2) + (ic.height / 2),
			left: ic.left - tc.width + 5
		});
		this.setVisibility(1);
	}
});

var Validator = new Class({
	Extends: Request,	
	initialize: function(options) {
		this.parent(options);
		this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'});
	},
	gather: function(form) {
		this.form = form || this.options.form;
		
		/*
		this.form.addEvents({
			submit: function(event) {
				new Event(event).stop();
			},
			keydown: (function(event) {
				var key = new Event(event).key;
				if (key == 'enter')
					//validate.get().check('userSetLogin');
					this.gather.valide();
					
			}).bind(this)
		});
		*/		
		
		this.elements = this.form.getElements('[name!=""]');
		this.data = {};

		this.elements.each(function(el) {
			switch(el.getProperty('type') || el.type) {
				case 'image':
					this.data[el.name] = el.src;
					break;
	
				case 'radio':
					if (!this.data[el.name]) this.data[el.name] = (el.checked) ? el.value : null;
					break;
	
				default:
					this.data[el.name] = el.value;
					break;
			}
		}, this);
		return this;
	},
	valide: function(method) {
		if (!method) return;
		
		var data = {};
		data[method] = this.data;		
		this.options.url = this.form.action;
		this.send(data);
	},
	success: function(response) {
		response = JSON.decode(response, this.options.secure);
		if (response == true) {
			this.fireEvent('onValidate', response);
			return;
		}

		this.run = false;
		this.elements.each(function(element) {
			if (this.run || element.name != response.type) return;
			this.error(element, response.message);
		}, this);
	},
	send: function(data) {
		this.parent(JSON.encode(data));
	},
	error: function(element, message) {
		// BUG: if possible detect has focus before focus()
		if (element.focus)
			element.focus();
			
		if (!element.tooltip)
			element.tooltip = new Tips.Base(element);
		
		element.tooltip.setValue(message).setShow();
		this.run = true;
	}
});
