/*
Class: RangeSlider
        Creates a slider with two elements: a knob and a container. Returns the values.
Note:
        The Slider requires an XHTML doctype.
Arguments:
        element - the knob container
        knob - the handle
        options - see Options below
        maxknob - an optional maximum slider handle
Options:
	start - the minimum value for your slider.
	end - the maximum value for your slider.
        mode - either 'horizontal' or 'vertical'. defaults to horizontal.
        offset - relative offset for knob position. default to 0.
        knobheight - positions the max slider knob
Events:
        onChange - a function to fire when the value changes.
        onComplete - a function to fire when you're done dragging.
        onTick - optionally, you can alter the onTick behavior, for example displaying an effect of the knob moving to the desired position.
                Passes as parameter the new position.
*/
var RangeSlider = new Class({

	options: {
		onChange: Class.empty,
		onComplete: Class.empty,
		onTick: function(pos){
			this.moveKnob.setStyle(this.p, pos);			
		},
		start: 0,
		end: 100,
		offset: 0,
		steps: 10,
		snap: true,
		knobheight: 20,
		mode: 'horizontal'
	},

    initialize: function(el, knob, options, maxknob) {
		this.element = $(el);
		this.knob = $(knob);
		this.setOptions(options);
		this.previousChange = -1;
		this.previousEnd = -1;
		this.step = -1;
		this.options.knobheight = this.knob.offsetHeight; // no need for this parameter, can calculate it.
		
		if(maxknob!=null)
			this.maxknob = $(maxknob);
		else
			this.element.addEvent('mousedown', this.clickedElement.bindWithEvent(this));
		var mod, offset;
		switch(this.options.mode){
			case 'horizontal':
				this.z = 'x';
				this.p = 'left';
				mod = {'x': 'left', 'y': false};
				offset = 'offsetWidth';
				break;
			case 'vertical':
				this.z = 'y';
				this.p = 'top';
				mod = {'x': false, 'y': 'top'};
				offset = 'offsetHeight';
		}
		this.max = this.element[offset] - this.knob[offset] + (this.options.offset * 2);
		this.half = this.knob[offset]/2;
		this.getPos = this.element['get' + this.p.capitalize()].bind(this.element);
		this.knob.setStyle('position', 'relative').setStyle(this.p, - this.options.offset);
		if(maxknob != null) {
			this.maxPreviousChange = -1;
			this.maxPreviousEnd = -1;
			this.maxstep = this.options.end;
			this.maxknob.setStyle('position', 'relative').setStyle(this.p, + this.max - this.options.offset).setStyle('bottom', this.options.knobheight);
		}
		var lim = {};
		lim[this.z] = [- this.options.offset, this.max - this.options.offset];
		this.drag = new Drag.Base(this.knob, {
			limit: lim,
			modifiers: mod,
			snap: 0,
			onStart: function(){
					this.draggedKnob();
			}.bind(this),
			onDrag: function(){
					this.draggedKnob();
			}.bind(this),
			onComplete: function(){
					this.draggedKnob();
					this.end();
			}.bind(this)
		});
		if(maxknob != null) {  
			this.maxdrag = new Drag.Base(this.maxknob, {
				limit: lim,
				modifiers: mod,
				snap: 0, 
				onStart: function(){
					this.draggedKnob(1);
				}.bind(this),
				onDrag: function(){
					this.draggedKnob(1);
				}.bind(this),
				onComplete: function(){
					this.draggedKnob(1);
					this.end();
				}.bind(this)
			});
		}
		
		if (this.options.initialize) this.options.initialize.call(this);
    },

	setMin: function(stepMin){
		this.step = stepMin.limit(this.options.start, this.options.end);
		this.checkStep();
		this.end();
		this.moveKnob = this.knob;
		this.fireEvent('onTick', this.toPosition(this.step));
		return this;
	},

	setMax: function(stepMax){
		this.maxstep = stepMax.limit(this.options.start, this.options.end);
		this.checkStep(1);
		this.end();
		this.moveKnob = this.maxknob;
		this.fireEvent('onTick', this.toPosition(this.maxstep));
		return this;
	},

	clickedElement: function(event){
		var position = event.page[this.z] - this.getPos() - this.half;
		position = position.limit(-this.options.offset, this.max -this.options.offset);
		this.step = this.toStep(position);
		this.checkStep();
		this.end();
		this.fireEvent('onTick', position);
	},

	draggedKnob: function(mx){
		if(mx==null) {
			this.step = this.toStep(this.drag.value.now[this.z]);
			this.checkStep();
		}
		else {  
			this.maxstep = this.toStep(this.maxdrag.value.now[this.z]);
			this.checkStep(1);
		}
	},

	checkStep: function(mx){
		if(mx==null) {
			if (this.previousChange != this.step){
				this.previousChange = this.step;
			}
		}
		else {  
			if (this.maxPreviousChange != this.maxstep){
				this.maxPreviousChange = this.maxstep;
			}
		}
		
		if(this.maxknob!=null) {
			if(this.step < this.maxstep)
				this.fireEvent('onChange', { minpos: this.step, maxpos: this.maxstep });
			else    
				this.fireEvent('onChange', { minpos: this.maxstep, maxpos: this.step });
		}
		else {  
			this.fireEvent('onChange', this.step);
		}
	},

	end: function(){
		if (this.bypassOnComplete)
			return;
			
		if (this.previousEnd !== this.step || (this.maxknob != null && this.maxPreviousEnd != this.maxstep)) {
			
			this.previousEnd = this.step;

			if(this.maxknob != null) {
				this.maxPreviousEnd = this.maxstep;

				if(this.step < this.maxstep)
					this.fireEvent('onComplete', { minpos: this.step , maxpos: this.maxstep  });
				else    
					this.fireEvent('onComplete', { minpos: this.maxstep , maxpos: this.step  });
			}
			else {  
				this.fireEvent('onComplete', this.step);
			}
		}
		if( this.options.snap ) {
			this.bypassOnComplete = true;
			if(this.maxknob != null) {
				var saveMin = 0;
				var saveMax = 0;
				if(this.step < this.maxstep) {
					saveMin = this.step;
					saveMax = this.maxstep;
				}
				else {
					saveMin = this.maxstep;				
					saveMax = this.step;					
				}
				this.setMin(saveMin);				
				this.setMax(saveMax);									
			}
			else {
				this.setMin(this.step);
			}
			this.bypassOnComplete = false;
		}
	},
	
	toStep: function(position){
		return Math.round((position + this.options.offset) / this.max * this.options.steps) + this.options.start;
	},

	toPosition: function(step){
		return (this.max * step / this.options.steps) - (this.max * this.options.start / this.options.steps) - this.options.offset;
	}

});

RangeSlider.implement(new Events);
RangeSlider.implement(new Options);


var RangePicker = new Class({

	options: {
		onChange: Class.empty,
		onComplete: Class.empty,
		start: 0,
		end: 100
	},

    initialize: function(el, minSel, options, maxSel) {
		this.minSel = $(minSel);
		this.maxSel = $(maxSel);
		this.setOptions(options);
		this.previousChange = -1;
		this.previousEnd = -1;
		this.step = -1;
		var picker = this;
		
		this.minSel.options.length=0;
		for(var i=0; i<this.options.end-this.options.start+1; i++) {			
			var val = this.options.start + i;
			var mappedVal = val;
			if(this.options.stepValueMap && this.options.stepValueMap[i]) {
				mappedVal = this.options.stepValueMap[i];	
			}
			var displayVal = mappedVal;
			if(this.options.valueToDisplayFormat) {
				displayVal = this.options.valueToDisplayFormat(mappedVal);	
			}
			
			this.minSel.options[i] = new Option((i==0 ? "No min" : displayVal),val);			
		}		
		this.minSel.selectedIndex = 0;
		this.minSel.addEvent('change', function() {
			picker.fireEvent('onComplete', { minpos: minSel.value , maxpos: maxSel.value  });									
		});
		
		this.maxSel.options.length=0;
		for(var i=0; i<this.options.end-this.options.start+1; i++) {
			var val = this.options.start + i;
			var mappedVal = val;
			if(this.options.stepValueMap && this.options.stepValueMap[i]) {
				mappedVal = this.options.stepValueMap[i];	
			}
			var displayVal = mappedVal;
			if(this.options.valueToDisplayFormat) {
				displayVal = this.options.valueToDisplayFormat(mappedVal);	
			}
			
			this.maxSel.options[i] = new Option((i==this.options.end-this.options.start ? "No max" : displayVal),val);			
		}
		this.minSel.selectedIndex = this.maxSel.options.length-1;
		this.maxSel.addEvent('change', function() {
			picker.fireEvent('onComplete',{ minpos: minSel.value , maxpos: maxSel.value  });									
		});
		
				
		if (this.options.initialize) this.options.initialize.call(this);
    },
	setMin: function(stepMin){
		var val = stepMin.limit(this.options.start, this.options.end);
		for(var i=0;i<this.minSel.options.length;i++)
		{
			if(this.minSel.options[i].value==val) {
				this.minSel.selectedIndex=i;
				return;
			}
		}
	},
	setMax: function(stepMax){
		var val = stepMax.limit(this.options.start, this.options.end);
		for(var i=0;i<this.maxSel.options.length;i++)
		{
			if(this.maxSel.options[i].value==val) {
				this.maxSel.selectedIndex=i;
				return;
			}
		}
	},
	getStepForValue: function(value) {
		if(this.options.stepValueMap) {
			for(var i=0;i<this.options.stepValueMap.length;i++) {
				if(this.options.stepValueMap[i]==value)
					return i;
			}
			return 0;
		}
		else {
			return value;	
		}
	},
	getMaxStep: function() {
		return this.options.end+1;
	},
	clickedElement: function(event){
	},
	hideRange: function(stepMin,stepMax) {
		var start = stepMin.limit(this.options.start, this.options.end);
		var end = stepMax.limit(this.options.start, this.options.end);
		var changed=false;
		for(var i=start;i<=end;i++) {
			this.minSel.options[i].style.display = 'none';
			this.maxSel.options[i].style.display = 'none';
			if(this.minSel.selectedIndex==i) {
				this.minSel.selectedIndex=0;
				changed=true;
			}
			if(this.maxSel.selectedIndex==i) {
				this.maxSel.selectedIndex=this.maxSel.options.length-1;
				changed = true;	
			}
		}
		if(changed)
			this.fireEvent('onComplete',{ minpos: this.minSel.value , maxpos: this.maxSel.value  });
	},
	unhideRange: function(stepMin,stepMax) {
		var start = stepMin.limit(this.options.start, this.options.end);
		var end = stepMax.limit(this.options.start, this.options.end);
		for(var i=start;i<=end;i++) {
			this.minSel.options[i].style.display = '';
			this.maxSel.options[i].style.display = '';
		}
	}
	

});

RangePicker.implement(new Events);
RangePicker.implement(new Options);

var iFishEye = new Class({
	options: {
			container: document,
			targetImageClass: ".iFishEyeImg",
			targetCaptionClass: ".iFishEyeCaption",
			dimThumb: {width:64, height:64},
			dimFocus: {width:128, height:128},
			eyeRadius: 192,
			pupilRadius: 50,
			useAxis: 'x',
			norm: "L1",
			blankPath: "images/blank.gif",

			onEyeOver: Class.empty,
			onEyeOut: Class.empty,
			onPupilOver: Class.empty,
			onPupilOut: Class.empty,
			
			isEnabledCallback: Class.empty
	},

	initialize: function(options) {
		this.setOptions(options);
		this.imgs = $$(this.options.targetImageClass);
		this.captions = $A($$(this.options.targetCaptionClass));

		this.imgs.each(function(obj, i) {
			obj.setStyles({
				width: this.options.dimThumb.width +"px",
				height: this.options.dimThumb.height +"px"
			});

			var src = obj.getProperty("src");
			var ext = src.substr(src.length - 3);
			if(ext == "png" && window.ie) {
				obj.setStyle("filter", "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+ src +"',sizingMethod='scale')");
				obj.setProperty("src", this.options.blankPath);
			}

			this.captions[i].setOpacity(0);
			this.captions[i].setStyle('display','none');
		}.bind(this));

		this.options.container.addEvents({
			"mousemove": function(event) {
				if(this.options.isEnabledCallback && this.options.isEnabledCallback!=Class.empty && this.options.isEnabledCallback()==false) {
					// disabled
					return;
				}
				event = new Event(event);
				this._nextState(event);
			}.bind(this),

			"mouseleave": function() {
				this._initialState();
			}.bind(this)
		});
	},

	detachEvents: function() {
		this.options.container.removeEvents();	
	},

	_initialState: function() {
		this.imgs.each(function(obj, i) {
			this.captions[i].setOpacity(0);
			this.captions[i].setStyle('display','none');
 			obj.effects({duration: 300, transition: Fx.Transitions.Sine.easeInOut}).start({
				"width": [obj.getStyle("width").toInt(), this.options.dimThumb.width],
				"height": [obj.getStyle("height").toInt(), this.options.dimThumb.height]
			})
		}.bind(this))
	},

	_nextState: function(event) {
		this.imgs.each(function(obj, i) {
			var h = this._getDistance(event, obj);
			var objProperties = this._getDimensions(h);
			obj.setStyles({
				width: objProperties.width +"px",
				height: objProperties.height +"px"
			});

			if(h < this.options.eyeRadius) this.fireEvent("onEyeOver", obj, 20);
			else this.fireEvent("onEyeOut", obj, 20);

			if(h < this.options.pupilRadius) {
				this.captions[i].setOpacity(1);
				this.captions[i].setStyle('display','');
				this.fireEvent("onPupilOver", obj, 20);
			} else {
				this.captions[i].setOpacity(0);
				this.captions[i].setStyle('display','none');
				this.fireEvent("onPupilOut", obj, 20);
			}
		}.bind(this));
	},

	_getDistance: function(event, obj) {
		var objProperties = obj.getCoordinates();
		var curProperties = {
			x: event.page.x,
			y: event.page.y
		};
		objProperties.center = {
			x: (objProperties.left + (objProperties.width / 2)),
			y: (objProperties.top + (objProperties.height / 2))
		};
		if(this.options.useAxis.length > 1) {
			switch(this.options.norm.toUpperCase()) {
				case "L1":
					return Math.abs(curProperties.x - objProperties.center.x) + Math.abs(curProperties.y - objProperties.center.y);
					break;
				case "L2":
					return Math.round(Math.sqrt(Math.pow((curProperties.x - objProperties.center.x), 2) + Math.pow((curProperties.y - objProperties.center.y),2)));
					break;
			};
		} else {
			return Math.abs(curProperties[this.options.useAxis] - objProperties.center[this.options.useAxis]);
		}
	},

	_getDimensions: function(h) {
		if(h < this.options.eyeRadius) {
			var width = (((this.options.dimThumb.width - this.options.dimFocus.width) / this.options.eyeRadius) * h) + this.options.dimFocus.width;
			var height = (((this.options.dimThumb.height - this.options.dimFocus.height) / this.options.eyeRadius) * h) + this.options.dimFocus.height;
		} else {
			var width = this.options.dimThumb.width;
			var height = this.options.dimThumb.height;
		}
		return {width:width, height:height};
	}
});
iFishEye.implement(new Events); // Implements addEvent(type, fn), fireEvent(type, [args], delay) and removeEvent(type, fn)
iFishEye.implement(new Options);// Implements setOptions(defaults, options)

// Sortable Table

var sortableTable = new Class({
							  
	getOptions: function(){
		return {
			overCls: false,
			onClick: false,
			sortOn: 0,
			sortBy: 'ASC',
			filterHide: true,
			filterHideCls: 'hide',
			filterSelectedCls: 'selected'
		};
	},

	initialize: function(table, options){
		this.setOptions(this.getOptions(), options);
		this.table = $(table);
		this.tHead = this.table.getElement('thead');
		this.tBody = this.table.getElement('tbody');
		this.tFoot = this.table.getElement('tfoot');
		this.elements = this.tBody.getElements('tr');
		this.filtered = false;
		
		/*for(i=0;i<10;i++){
			this.elements.clone().injectInside(this.tBody);
		}
		this.elements = this.tBody.getElements('tr');*/
		
		this.elements.each(this.attachRowHandlers,this);
		
		//setup header
		this.tHead.getElements('th').each(function(el,i){
			if(el.axis){
				el.addEvent('click', this.sort.bind(this,i));
				el.addEvent('mouseover', function(){
					el.addClass('tableHeaderOver');
				});
				el.addEvent('mouseout', function(){
					el.removeClass('tableHeaderOver');
				});
				el.getdate = function(str){
					// inner util function to convert 2-digit years to 4
					function fixYear(yr) {
						yr = +yr;
						if (yr<50) { yr += 2000; }
						else if (yr<100) { yr += 1900; }
						return yr;
					};
					var ret;
					//
					if (str.length>12){
						strtime = str.substring(str.lastIndexOf(' ')+1);
						strtime = strtime.substring(0,2)+strtime.substr(-2)
					}else{
						strtime = '0000';
					}
					//
					// YYYY-MM-DD
					if (ret=str.match(/(\d{2,4})-(\d{1,2})-(\d{1,2})/)) {
						return (fixYear(ret[1])*10000) + (ret[2]*100) + (+ret[3]) + strtime;
					}
					// DD/MM/YY[YY] or DD-MM-YY[YY]
					if (ret=str.match(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{2,4})/)) {
						return (fixYear(ret[3])*10000) + (ret[2]*100) + (+ret[1]) + strtime;
					}
					return 999999990000; // So non-parsed dates will be last, not first
				};
				//
				el.findData = function(elem){
					var child = null;
					if(elem.childNodes && elem.childNodes.length>0) {
						for(var i=0;i<elem.childNodes.length;i++) {
							if(elem.childNodes[i].nodeType==1) {
								child = elem.childNodes[i];
								break;
							}
						}
					}
					if(child){
						return el.findData(child);
					}else{
						return elem.innerHTML.trim();
					}
				};
				
				var CleanNumberStr = function(n) {
					return n.replace(/,/g,'').replace(/[ ]*\u00BD/g,".5").replace(/[ ]*\u00BC/g,".25");						
				}
				el.compare = function(a,b){
					var1 = el.findData(a.childNodes[i]);
					var2 = el.findData(b.childNodes[i]);
					//var1 = a.getChildren()[i].firstChild.data;
					//var2 = b.getChildren()[i].firstChild.data;
					
					if(el.axis == 'number'){						
						try {
							var1 = parseFloat(CleanNumberStr(var1));
						} catch(ex) {
							var1=var1;
						}
						try {
							var2 = parseFloat(CleanNumberStr(var2));
						} catch(ex) { }
						
						if(var1==var2){return 0};
						if(el.sortBy == 'ASC'){
							if(var1<var2){return -1};
						}else{
							if(var1>var2){return -1};
						}
						return 1;						
					}else if(el.axis == 'string'){
						var1 = var1.toUpperCase();
						var2 = var2.toUpperCase();
						
						if(var1==var2){return 0};
						if(el.sortBy == 'ASC'){
							if(var1<var2){return -1};
						}else{
							if(var1>var2){return -1};
						}
						return 1;
						
					}else if(el.axis == 'date'){
						var1 = parseFloat(el.getdate(var1));
						var2 = parseFloat(el.getdate(var2));
						
						if(el.sortBy == 'ASC'){
							return var1-var2;
						}else{
							return var2-var1;
						}
						
					}else if(el.axis == 'currency'){
						try {
							var1 = parseFloat(CleanNumberStr(var1.substr(1)));
						} catch(ex) { }
						try {
							var2 = parseFloat(CleanNumberStr(var2.substr(1)));
						} catch(ex) { }
						
						if(var1==var2){return 0};
						if(el.sortBy == 'ASC'){
							if(var1<var2){return -1};
						}else{
							if(var1>var2){return -1};
						}
						return 1;
						
					}
					
				}
				
				if(i == this.options.sortOn){
					el.fireEvent('click');
				}
			}
			else {
				el.setStyle('background-image','none');	
			}
		}, this);
	},
	attachRowHandlers: function(el,i) {
		var options = this.options;
		if(this.options.overCls){
			el.addEvent('mouseover', function(){
				el.addClass(options.overCls);
			}, this);
			el.addEvent('mouseout', function(){
				el.removeClass(options.overCls);
			});
		}
		if(this.options.onClick){
			el.addEvent('click', options.onClick);
		}
	},
	reloadElements: function() {
		this.tBody = this.table.getElement('tbody');
		this.elements = this.tBody.getElements('tr');
		this.elements.each(this.attachRowHandlers,this);
		this.sort(this.options.sortOn || 1);
	},
	sort: function(index){		
		if(this.options.onStart){
			this.fireEvent('onStart');
		}
		//
		this.options.sortOn = index;
		var header = this.tHead.getElements('th');
		var el = header[index];
		
		header.each(function(e,i){
			if(i != index){
				e.removeClass('sortedASC');
				e.removeClass('sortedDESC');
			}
		});
		
		if(el.hasClass('sortedASC')){
			el.removeClass('sortedASC');
			el.addClass('sortedDESC');
			el.sortBy = 'DESC';
		}else if(el.hasClass('sortedDESC')){
			el.removeClass('sortedDESC');
			el.addClass('sortedASC');
			el.sortBy = 'ASC';
		}else{
			if(this.options.sortBy == 'ASC'){
				el.addClass('sortedASC');
				el.sortBy = 'ASC';
			}else if(this.options.sortBy == 'DESC'){
				el.addClass('sortedDESC');
				el.sortBy = 'DESC';
			}
		}
		//
		this.elements.sort(el.compare);
		this.elements.injectInside(this.tBody);
		//
		if(this.filtered){
			this.filteredAltRow();
		}else{
			this.altRow();
		}
		
		//
		if(this.options.onComplete){
			this.fireEvent('onComplete');
		}
	},
	
	altRow: function(){
		this.elements.each(function(el,i){
			if(i % 2){
				el.removeClass('altRow');
			}else{
				el.addClass('altRow');
			}
		});
	},
	
	filteredAltRow: function(){
		this.table.getElements('.'+this.options.filterSelectedCls).each(function(el,i){
			if(i % 2){
				el.removeClass('altRow');
			}else{
				el.addClass('altRow');
			}
		});
	},
	
	filter: function(form){
		var form = $(form);
		var col = 0;
		var key = '';
		
		form.getChildren().each(function(el,i){
			if(el.id == 'column'){
				col = Number(el.value);
			}
			if(el.id == 'keyword'){
				key = el.value.toLowerCase();
			}
			if(el.type == 'reset'){
				el.addEvent('click',this.clearFilter.bind(this));
			}
		}, this);
		
		if(key){
		this.elements.each(function(el,i){
			if(this.options.filterHide){
				el.removeClass('altRow');
			}
			if(el.getChildren()[col].firstChild.data.toLowerCase().indexOf(key) > -1){
				el.addClass(this.options.filterSelectedCls);
				if(this.options.filterHide){
					el.removeClass(this.options.filterHideCls);
				}
			}else{
				el.removeClass(this.options.filterSelectedCls);
				if(this.options.filterHide){
					el.addClass(this.options.filterHideCls);
				}
			}
		}, this);
		if(this.options.filterHide){
			this.filteredAltRow();
			this.filtered = true;
		}
		}
	},
	
	clearFilter: function(){
		this.elements.each(function(el,i){
			el.removeClass(this.options.filterSelectedCls);
			if(this.options.filterHide){
				el.removeClass(this.options.filterHideCls);
			}
		}, this);
		if(this.options.filterHide){
			this.altRow();
			this.filtered = false;
		}
	}

});
sortableTable.implement(new Events);
sortableTable.implement(new Options);

// /Sortable Table

