/*
 * Some rights reserved (cc) 2008, Gonow Tecnologia Ltda
 * @autor: Flavio Crispim dos Santos / Gonow 2008
 * http://creativecommons.org/licenses/by-sa/2.5/
 */

var Slider = function Slider(name,target){

	var _stepSize = 25;

	/*
	 * Public methods
	 */
	this.toString = function(){
		return "Slider@instance:(" + this.getName() + ")";
	};
	this.getName = function getName(){ return name; };
	this.getStepSize = function() { return _stepSize; };
	this.getTarget = function getTarget(){ return target || false; }; 
	this.getDraw = function getDraw(){ return _draw; };
	this.getHandler = function getHandler(){ return _handler; };
	this.draw = function draw(){ return _draw.render(); };
	this.start = function start(){ return _handler.handle(); };
	this.destroy = function destroy(){
		_handler.stopHandle();
		_draw.drop();
	};

	this.setStepSize = function setStepSize(size) {
		_stepSize = size;
	};
	
	this.stepForward = function stepForward(){
		return _handler.step(1);
	};

	this.stepBackward = function backForward(){
		return _handler.step(-1);
	};
	
	this.getSelectedIndex = function getSelectedIndex(){
		return _handler.getSelectedIndex();
	};
	
	this.clearHandle = function clearHandle(){
		_handler.clearHandle();
	};
	
	this.markElm = function markElm(pos){
		_handler.markElm(pos);
	};

	/*
	 * Private members
	 */
	var _draw = new Slider.DrawSlider(this);
	var _handler = new Slider.SlideHandler(this);
	
	_handler.handle();	
	_draw.render();
};

/**
 * Global scroll registry.
 * Holdīs references to every Scroll object.
 */
Slider.registry = {};

Slider.getInstance = function getInstance(id, target){
	if(!Slider.registry[id]){
		Slider.registry[id] = new Slider(id, target);
	}
	return Slider.registry[id];
};

Slider.destroy = function destroy(id){
	if(Slider.registry[id]){
		Slider.registry[id].destroy();
		delete Slider.registry[id];
	}
};

Slider.destroyAll = function destroyAll(){
	for(var x in Slider.registry){
		Slider.destroy(x);
	}
};

Slider.newInstance = function newInstance(id,target){
	if(Slider.registry[id]){ Slider.destroy(id); }
	return Slider.getInstance(id,target);
};

Slider.stepForward = function stepForward(id){
	var slider = Slider.getInstance(id);
	if(slider){
		return slider.stepForward();
	}
};

Slider.stepBackward = function stepBackward(id){
	var slider = Slider.getInstance(id);
	if(slider){
		return slider.stepBackward();
	}
};

Slider.getSelectedIndex = function getSelectedIndex(id){
	var slider = Slider.getInstance(id);
	if(slider){
		return slider.getSelectedIndex();
	}
};

Slider.clearHandle = function clearHandle(id){
	var slider = Slider.getInstance(id);
	if(slider){
		slider.clearHandle();
	}
};

Slider.markElm = function markElm(id, pos){
	var slider = Slider.getInstance(id);
	if(slider){
		slider.markElm(pos);
	}
};

/**
 * 
 * @param {Object} slider
 */
Slider.DrawSlider = function DrawSlider(slider){

	/*
	 * Imports
	 */
	var containerId = slider.getName();

	if(!slider.getTarget()) {
		var sliderEl = $D.getElementsByClassName ('slider', 'div', containerId)[0];
		this.SLIDER = $D.generateId(sliderEl);
	} else {
		var sliderEl = $D.get(slider.getTarget());
		this.SLIDER = slider.getTarget();
	}

	this.BUTTON_UP = 'up' + Math.random()*10000000;
	this.BUTTON_DOWN = 'down' + Math.random()*10000000;

	sliderEl = null;

	var _topHandler = function _topHandler(){
		$D.replaceClass(this.BUTTON_UP, 'up', 'up-disable');
	};

	var _bottomHandler = function _bottomHandler(){
		$D.replaceClass(this.BUTTON_DOWN, 'down', 'down-disable');
	};

	var _slideHandler = function _slideHandler(){
		$D.replaceClass(this.BUTTON_UP, 'up-disable', 'up');
		$D.replaceClass(this.BUTTON_DOWN, 'down-disable', 'down');
	};
	
	/*
	 * Public Methods.
	 */
	 
	this.getContentEl = function getContentEl(){
		return $D.getElementsByClassName('content', 'ul', slider.getName())[0];
	};

	this.render = function render(){
		var containerEl = $D.get(slider.getName());
		var contentEl = this.getContentEl();
		if(containerEl.offsetHeight+1 < contentEl.offsetHeight){
			// render UP/DOWN
			var htm = [];
			htm.push('<div id="' + this.BUTTON_UP + '" class="up-disable"><!-- --></div><!-- -->');
			htm.push('<div id="' + this.BUTTON_DOWN + '" class="down"><!-- --></div>');
			$D.get(this.SLIDER).innerHTML = htm.join('');
			
			var handler = slider.getHandler();
			handler.onTop(_topHandler, this);
			handler.onBottom(_bottomHandler, this);
			handler.onSlide(_slideHandler, this);

		}
		containerEl = contentEl = null;
		return true;
	};

	this.drop = function drop(){
		if($D.get(this.SLIDER)){ $D.get(this.SLIDER).innerHTML = ''; }
	};
};

Slider.SlideHandler = function SlideHandler(slider){

	/*
	 * Private members
	 */
	var _draw = slider.getDraw();
	var topEvent = new $G.CustomEvent('top');
	var bottomEvent = new $G.CustomEvent('bottom');
	var slideEvent = new $G.CustomEvent('slide');

	var _selectedIndex = -1;

	/*
	 * Public members.
	 */
	this.onTop = function onTop(callBack, scope){ topEvent.subscribe(callBack, scope, true); };
	this.onBottom = function onBottom(callBack, scope){ bottomEvent.subscribe(callBack, scope, true); };
	this.onSlide = function onSlide(callBack, scope){ slideEvent.subscribe(callBack, scope, true); };
	this.getSelectedIndex = function(){return _selectedIndex};
	
	this.handle = function handle(){
		try{
			var contentEl = _draw.getContentEl();
			var childs = contentEl.parentNode.parentNode.getElementsByTagName('LI');

			var childsOn = 0;
			for (var i=0, cL = childs.length; i < cL ; i++){
				if (!$D.hasClass(childs[i],'childOff')){
					childsOn++;
					$E.removeListener(childs[i], 'mouseover');
					$E.removeListener(childs[i], 'mouseout');
					$E.on(childs[i], 'mouseover', _mouseOver, this);
					$E.on(childs[i], 'mouseout', _mouseOut, this);
				}
			}
			slider.setStepSize(Math.floor(contentEl.scrollHeight / childsOn));

			childs = contentEl = null;

			$E.on(_draw.BUTTON_UP, 'click', _buttomUp, this);
			$E.on(_draw.BUTTON_DOWN, 'click', _buttomDown, this);
			
			//verify inital state
			_slideUpDown(0);
			return true;
		}catch(e){
			throw new Error("HandleError: " + slider.getName() + ". Error while attaching event handlers. Failed with message:" + e.message);
		}
	};

	this.stopHandle = function stopHandle(){
		$E.purgeElement(_draw.SLIDER, true, 'click');
	};
	
	this.clearHandle = function clearHandle(){
		var contentEl = _draw.getContentEl();
		var childs = contentEl.parentNode.parentNode.getElementsByTagName('LI');
		
		
		
		
		var containerEl = $D.get(slider.getName());
		
		$D.removeClass(childs, 'selectedOld');
		containerEl.scrollTop = 0;
		topEvent.fire(containerEl.scrollTop);
		
		_selectedIndex = -1;
	};
	
	this.markElm = function markElm(pos){
		var contentEl = _draw.getContentEl();
		var childs = contentEl.parentNode.parentNode.getElementsByTagName('LI');
		if (_selectedIndex >= 0 && pos == 'last') {
			$D.replaceClass(childs[_selectedIndex], 'selected', 'selectedOld');
		} else if (_selectedIndex >= 0 && pos == 'new') {
			$D.replaceClass(childs[_selectedIndex], 'selectedOld', 'selected');
		}
	};


	/*
	 * Private functions.
	 */
	this.step = function step(direction){
		
		// Defaults to Forward
		// Forces one at a time.
		//  1=forward, -1=backward
		direction = (direction/Math.abs(direction)||1);
		
		_selectedIndex += (1*direction);
		
		var contentEl = _draw.getContentEl();
		var childs = contentEl.parentNode.parentNode.getElementsByTagName('LI');
		var childsOn = 0;

		for (var i=0, cL = childs.length; i < cL ; i++){
			if (!$D.hasClass(childs[i],'childOff')){
				childsOn++;
			}
		}
		contentEl = null;
		
		if(_selectedIndex < 0){
			_selectedIndex = -1;
			$D.removeClass(childs[0], 'selected');
			return;
		}
		
		if(!childs || childs.length === 0 || _selectedIndex >= childsOn){
			_selectedIndex = childs.length-1;
			return;
		}

		var containerEl = $D.get(slider.getName());
		var selectedEl = childs[_selectedIndex]; // selected LI
		
		$D.addClass(selectedEl, 'selected');
		
		var containerY = $D.getY(containerEl);
		var selectedY = $D.getY(selectedEl);
		
		if(direction > 0){
			if(_selectedIndex != 0){
				$D.removeClass(childs[_selectedIndex-1], 'selectedOld');
				$D.removeClass(childs[_selectedIndex-1], 'selected');
			}
			if(selectedY + selectedEl.offsetHeight > containerY + containerEl.offsetHeight){
				var step = (selectedY + selectedEl.offsetHeight) - (containerY + containerEl.offsetHeight);
				_slideUpDown(step);
			}
		}else{
			if(_selectedIndex < childs.length){
				$D.removeClass(childs[_selectedIndex+1], 'selectedOld');
				$D.removeClass(childs[_selectedIndex+1], 'selected');
			}
			if(selectedY < containerY){
				var step = selectedY - containerY;
				_slideUpDown(step);
			}
		}
		var value = selectedEl.textContent || selectedEl.innerText;
		childs = selectedEl = containerEl = null;
		return value;
	};

	var _slideUpDown = function _slideUpDown(amount){
		try{
			var containerEl = $D.get(slider.getName());
			containerEl.scrollTop += amount;
			slideEvent.fire(containerEl.scrollTop);
			if(containerEl.scrollTop == 0){
				topEvent.fire(containerEl.scrollTop);
			}else if((containerEl.scrollTop + containerEl.offsetHeight) == containerEl.scrollHeight){
				bottomEvent.fire(containerEl.scrollTop);
			}
			containerEl = null;
		}catch(e){
			alert("HandleError: " + slider.getName() + ". Error while attaching event handlers. Failed with message:" + e.message);
		}
	};

	var _mouseOver = function _mouseOver(event){
		var containerEl = $D.get(slider.getName());
		var contentEl = _draw.getContentEl();
		
		var childs = contentEl.parentNode.parentNode.getElementsByTagName('LI');
		contentEl = null;
		var el = this;
		for(var i = 0; i < childs.length; i++){
			$D.removeClass(childs[i], 'selected');
			$D.removeClass(childs[i], 'selectedOld');
			if(childs[i] == el){
				_selectedIndex = i;
				$D.addClass(childs[i], 'selected');
			}
		}
		childs = el = null;
	};
	
	var _mouseOut = function _mouseOver(event){
		var containerEl = $D.get(slider.getName());
		var contentEl = _draw.getContentEl();
		
		var childs = contentEl.parentNode.parentNode.getElementsByTagName('LI');
		contentEl = null;
		var el = this;
		for(var i = 0; i < childs.length; i++){
			$D.removeClass(childs[i], 'selected');
			$D.removeClass(childs[i], 'selectedOld');
			if(childs[i] == el){
				_selectedIndex = i;
				$D.addClass(childs[i], 'selectedOld');
			}
		}
		childs = el = null;
	};
	var _buttomUp = function _buttomUp(event){ _slideUpDown(slider.getStepSize() * -1); };
	var _buttomDown = function _buttomDown(event){ _slideUpDown(slider.getStepSize()); };
}

