/*
Class: rubberbandSelect
	Click and drag to select element.  Hold 'ctrl' key to add items to current selection

Author: PK (real name??)
	- upgraded by Chris Esler http://www.chrisesler.com/mootools
	- minor changes by Nathan White http://www.nwhite.net/ (remove browser selection in background, fixed rebuild method)
License:
	MIT-style license.

Arguments:
	elements - a collection of elements to apply the rubberband selection
	options - an object. See options Below.

Options:
	triggers - a collection of elements to accept rubberband clicks
	onSelect - optionally you can alter the default select behaviour with this option
	onDeselect - optionally you can alter the default de-select behaviour with this option


Inspiration:
	http://forum.mootools.net/viewtopic.php?id=6367
	
	script on forum didn't work with Mootools 1.2b2. upgraded script to work with 1.2b2 

*/

var Rubberband = new Class({
	Implements: [Options, Events],
	options: {
		triggers: new Array(),	
		select: function(element){
			element.addClass('selected');
		},
		deselect: function(element){
			element.removeClass('selected');
		},
		itemClick: function(e){

			if(e.shift){
				switch(this.hasClass('selected')){
					case true:
						this.removeClass('selected');
						break;
					default:
						this.addClass('selected');
						break;
				}
			}
		}
	},

	triggers: null,
	selectedItems: [],
	thumbs: [],
	boxCoordinates: {},
	box: null,
	elements: null,

	initialize: function(elements, options){
		this.setOptions(options);

		this.triggers = this.options.triggers;

		this.box = new Element('div', {
			'id' : 'rubberbox',
			'styles': {
				'position': 'absolute',
				'top': 0,
				'left': 0,
				'border': '1px dotted gray',
				'width': 0,
				'height': 0,
				'display' : 'none'
			}
		}).inject(document.body);

		var overlay = new Element('div').setStyles({
			'position': 'absolute',
			'top': 0,
			'left': 0,
			'bottom': 0,
			'right': 0,
			'opacity': '.3',
			'background-color': "#7389ae"
		}).inject(this.box);

		this.boxCoordinates = {
			x : new Array(),
			y : new Array(),
			w : 0,
			h : 0
		};

		var start = this.start.bindWithEvent(this);			
		var move = this.move.bindWithEvent(this);		
		var end = this.end.bindWithEvent(this);		

		this.options.trigger = (!this.options.trigger) ? document.body : $(this.options.trigger);

		this.options.trigger.addEvents({
			'mousedown' : start,
			'mousemove' : move,
			'mouseup' : end
		});

		document.body.onselectstart = function(e){ e = new Event(e).stop(); return false; };

		this.elements = $$(elements);
		// need to rebuild if window resized, since coordinates would have changed 
		window.addEvent('resize',function(){this.build(this.elements,true)}.bind(this));

		this.build(this.elements);		
		if (this.options.initialize) this.options.initialize.call(this);
	},

	rebuild : function(elements, triggers){
		this.elements = $$(elements);
		if(triggers) this.triggers = triggers;
		this.build( this.elements );	
	},

	build : function(el,resize){
		// window resize reset
		if(resize) this.thumbs = [];

		el.each(function(el,index){
			var tmpX = el.getPosition().x;
			var tmpY = el.getPosition().y;	
			var tmpW = el.getScrollSize().x;
			var tmpH = el.getScrollSize().y;				

			this.thumbs[index] = {
				obj : el,
				input : el.getElement('input[type=checkbox]'),
				w : tmpW,
				h : tmpH,
				x : new Array( tmpX,  tmpW + tmpX),
				y : new Array( tmpY,  tmpH + tmpY)
			};
			el.addEvent('click',this.options.itemClick);
		},this);

	},
	start: function(event){ 		
		//console.log("+++++++++++++++ START ++++++++++++++++");
		event = new Event(event);	

		var greenLight = false;

		this.triggers.each(function(el){
			if(event.target == el) greenLight = true;
		}, this);		


		if(greenLight || event.target == document.body) {
			this.bActive = true;			

			this.boxCoordinates.x[0] = event.page.x;
			this.boxCoordinates.y[0] = event.page.y;	
			this.boxCoordinates.w =  0;
			this.boxCoordinates.h =  0;		

			this.box.setStyles({
				display : '',
				top : this.boxCoordinates.y[0],
				left : this.boxCoordinates.x[0]
			});		
		};
	},

	end: function(event){
		//console.log("+++++++++++++++ END ++++++++++++++++");

		if(!this.bActive) return false;

		this.bActive = false;

		if(this.boxCoordinates.w < 5 && this.boxCoordinates.h < 5 )
			this.thumbs.each(this.checkNodes, this);	

		this.box.setStyles({
			display : 'none',
			top : 0,
			left : 0,
			width : 0,
			height : 0
		});	

		this.boxCoordinates.x[1] = 0;
		this.boxCoordinates.y[1] = 0;
		this.boxCoordinates.w =  0;
		this.boxCoordinates.h =  0;			
		this.boxCoordinates.top = 0;
		this.boxCoordinates.left = 0;			
		this.boxCoordinates.x[2] = 0;
		this.boxCoordinates.y[2] = 0;		
	},

	move: function(event){
		//console.log("+++++++++++++++ MOVE ++++++++++++++++");
		if(this.bActive && this.box.style.display == '') {

			this.control = event.control;

			this.boxCoordinates.x[1] = event.page.x;
			this.boxCoordinates.y[1] = event.page.y;
			this.boxCoordinates.w =  Math.abs(this.boxCoordinates.x[0] - this.boxCoordinates.x[1]);
			this.boxCoordinates.h =  Math.abs(this.boxCoordinates.y[0] - this.boxCoordinates.y[1]);			
			this.boxCoordinates.top = this.boxCoordinates.y[0] > this.boxCoordinates.y[1] ? this.boxCoordinates.y[1] : this.boxCoordinates.y[0];
			this.boxCoordinates.left = this.boxCoordinates.x[0] > this.boxCoordinates.x[1] ? this.boxCoordinates.x[1] : this.boxCoordinates.x[0];			
			this.boxCoordinates.x[2] = this.boxCoordinates.left + this.boxCoordinates.w;
			this.boxCoordinates.y[2] = this.boxCoordinates.top + this.boxCoordinates.h;

			this.box.setStyles({
				top : this.boxCoordinates.top + 'px',
				left : this.boxCoordinates.left + 'px',
				width : this.boxCoordinates.w + 'px',
				height : this.boxCoordinates.h + 'px'
			});

			this.selectedItems.length = 0;
			this.thumbs.each(this.checkNodes, this);
			
			var sel;
			if(document.selection && document.selection.empty){
				document.selection.empty() ;
			} else if(window.getSelection) {
				sel=window.getSelection();
				if(sel && sel.removeAllRanges) 
					sel.removeAllRanges() ;
			}
					
		};

	},
	checkNodes : function(el){

		var box = this.boxCoordinates;				

		if (Math.min(box.x[2], el.x[1]) > Math.max(box.left, el.x[0]) && Math.max(box.top, el.y[0]) < Math.min(box.y[2], el.y[1])) {
			this.options.select(el.obj);
		}
		else {
			if(!this.control) this.options.deselect(el.obj); 
		}

	}
});
