/**
  * Simulates Scrollbar behaviour
  * root_element - Scrollbar container element
  * options - configuration options: 
  * 			value, max_value, min_value, 
  * 			button_Scroll, 
  * 			html_next, html_prev, html_drag, html_line, 
  * 			on_change, on_drag,
  * 			animation_speed,
  * 			mouse_track_tick
  * 
  * Functions:
  * 	nextClick()
  * 	previousClick()
  * 	value(val)
  * 	value()
  * 
 * @param {Object} root_element
 * @param {Object} options
 */
function ScrollBar (root_element, options) {
	this._el_root = $(root_element);
	this._el_drag = null;
	this._drag_pos = 0;
	this._value = 0;
	this._line_len = 0;

	this._options = {
		value: -1,				/* Initial value */	
		max_value: 100,			/* ScrollBar max value */
		min_value: 0,			/* ScrollBar min value */
		button_scroll: 10,		/* ScrollBar Next and Previous button value change on click */
		
		html_next: '.next',		/* Selector for "next" button */
		html_prev: '.prev',		/* Selector for "previous" button */
		html_drag: '.drag',		/* Selector for "drager" button */
		html_line: '.line',		/* Selector for slider line */
		
		on_change: null,		/* Callback function for onchange */
		on_drag: null,			/* Callback function for drag */
		
		animation_speed: 500,	/* Scroller animation speed (milliseconds per 1000px) */
		
		mouse_track_tick: 32,	/* Milliseconds between checking mouse position */
		
		remember_position: false /* Allow to use URL hash to remember and restore position of the element */ 
	};
	
	if (options)
		for(i in options)
			this._options[i] = options[i];
	
	this._initialize();
}
/**
 * Resets drag element position (with animation)
 * 
 * @param {Object} val
 */
ScrollBar.prototype._refreshGUI = function (val, fast) {
	if (!val) val = this._value;
	
	var _new_pos = (val - this._options.min_value) / (this._options.max_value - this._options.min_value);
	_new_pos = Math.round(this._line_len * _new_pos);
	
	if (this._drag_pos != _new_pos)
	{
		this._el_drag.stop();
		if (_new_pos === 0 || _new_pos)
		{
			if (fast)
				this._el_drag.css({marginLeft: _new_pos + 'px'});
			else
				this._el_drag.animate({marginLeft: _new_pos + 'px'}, this._options['animation_speed']);
				
			this._drag_pos = _new_pos;
		}else{
			if (fast)
				this._el_drag.css({marginLeft: '0px'});
			else
				this._el_drag.animate({marginLeft: '0px'}, this._options['animation_speed']);
			
			this._drag_pos = 0;
		}
	}
	
};
/**
 * Clicks next button
 */
ScrollBar.prototype.nextClick = function () {
	this.value(this._value + this._options.button_scroll);
	return this._value;
};
/**
 * Clicks previous button
 */
ScrollBar.prototype.previousClick = function () {
	this.value(this._value - this._options.button_scroll);
	return this._value;	
};
/**
 * Handles mouse DragTracker callback
 * 
 * @param {Object} pos_change
 * @param {Object} state
 */
ScrollBar.prototype._dragHandler = function (pos_change, state) {
	var pos = (typeof pos_change == 'object' ? pos_change.x : typeof pos_change == 'array' ? pos_change[0] : pos_change);
	this._drag_pos += pos;
		
	if (this._drag_pos < 0) { this._drag_pos = 0; } else
	if (this._drag_pos > this._line_len) { this._drag_pos = this._line_len; }
	
	if (this._drag_pos === 0 || this._drag_pos)
	{
		this._el_drag.css({marginLeft: Math.round(this._drag_pos) + 'px'});
	}
	
	var new_val = this._drag_pos / this._line_len;
	new_val = Math.round((this._options.max_value - this._options.min_value) * new_val) + this._options.min_value;
	
	this._value = new_val;
	
	if (state == 'mousemove' && this._options.on_drag)
		this._options.on_drag(this);
	else if (state == 'mouseup' && this._options.on_change)
	{
		if (this._options['remember_position']) setUrlHash(this._value);		
		this._options.on_change(this);
	}
	else if (state == 'mouseup')
	{
		if (this._options['remember_position']) setUrlHash(this._value);
	}
};
/**
 * Set / get scrollbar value
 *  
 * @param {Object} value
 */
ScrollBar.prototype.value = function (value) {
	if (typeof value != 'undefined' && typeof value != null)
	{
		var prev_value = this._value;
		this._value = value;
		
		if (this._value > this._options.max_value) {
			this._value = this._options.max_value;
		} else if (this._value < this._options.min_value) {
			this._value = this._options.min_value;
		}
		
		this._refreshGUI();
		
		if (this._value != prev_value && this._options.on_change)
			this._options.on_change(this);
			
		if (this._options.remember_position)
		{
			setUrlHash(this._value);
		}
	}
	return this._value;
};
ScrollBar.prototype.scrollToIndex = function (index) {
	if (typeof index != 'undefined' && typeof index != null)
	{
		var val = this._options.button_scroll * index + this._options.min_value;
		
		if (val > this._options.max_value)
			val = this._options.max_value;
			
		if (val < this._options.min_value)
			val = this._options.min_value;
			
		this.value(val);
	}
};
/**
 * Class constructor
 */
ScrollBar.prototype._initialize = function () {
	var el_next = $(this._options.html_next, this._el_root);
	var el_prev = $(this._options.html_prev, this._el_root);
	var el_line = $(this._options.html_line, this._el_root);
	this._el_drag = $(this._options.html_drag, this._el_root);
	
	this._line_len = el_line.width() - this._el_drag.width();
	
	var _self = this;
	var dt = new DragTracker(this._el_drag, function(p1, p2) { _self._dragHandler(p1, p2); }, this._options.mouse_track_tick);
	
	var _self = this;
	
	this._el_drag.click(function (e) {
		eventBuble(e);
	});
	el_line.click(function(e) {
		var o = $(this).offset();
		var cur_pos = parseInt(_self._el_drag.css('marginLeft'));
		
		o.left = e.pageX - o.left;
		o.top  = e.pageY - o.top;
		
		if (o.left < cur_pos)
			_self.previousClick();
		else
			_self.nextClick();
		
		eventBuble(e);
	});
		
	el_next.click(function(e) {
		eventBuble(e);
		_self.nextClick();
	});
	el_prev.click(function(e) {
		eventBuble(e);
		_self.previousClick();
	});
	
	if (!typeof this._options.on_drag == 'function')
		this._options.on_drag = null;
		
	if (!typeof this._options.on_change == 'function')
		this._options.on_change = null;
	
	if (this._options.min_value > this._options.max_value)
		this._options.max_value = this._options.min_value;
	
	if (this._options['value'] >= this._options.min_value && this._options.value <= this._options.max_value)
		this._value = this._options.value;
	else
		this._value =  this._options.min_value;
		
	if (this._options.max_value == this._options.min_value)
	{
		this._el_drag.css('display', 'none');
		el_line.css('cursor', 'default');
		el_next.css('cursor', 'default');
		el_prev.css('cursor', 'default');
	}
	
	if (this._options.remember_position)
	{
		var url_hash = parseInt(getUrlHash());
		if (url_hash && url_hash >= this._options.min_value && url_hash <= this._options.max_value)
		{
			this._value = url_hash;
					
		}
	}

	this._refreshGUI(this._value, true);
	
	/* If option to restore position from url hash is enabled, restore it */
};


function setUpMouseWheel(scrollbar_object, content_container, scroll_container)
{
	var sb = scrollbar_object;
	
	function handle(delta) {
	  if (typeof handle.delta == 'undefined') handle.delta = 0;
	  
	  if (delta < 0 && scroller.max_pos == scroller.actual_pos) return false;
	  if (delta > 0 && 0 == scroller.actual_pos) return false;
	  
	  handle.delta += delta;
	  if (handle.delta > 1) {
	    sb.previousClick()
	    handle.delta  = 0;
	  }
	  if (handle.delta < -1) {
	    sb.nextClick()
	    handle.delta  = 0;
	  }
	  return true;
	}
	
	/** Event handler for mouse wheel event.
	 */
	function wheel(event){
	        var delta = 0;
	        if (!event) /* For IE. */
	                event = window.event;
	        if (event.wheelDelta) { /* IE/Opera. */
	                delta = event.wheelDelta/120;
	        } else if (event.detail) { /** Mozilla case. */
	                delta = -event.detail/3;
	        }

	        if (delta)
	                var result = handle(delta);

	        if (result) {
	          if (event.preventDefault)
                  event.preventDefault();
		          event.returnValue = false;
	        }
	}
	
	if (scroll_container)
	{
		slider = $(scroll_container)[0];
	
		if (slider.addEventListener)
			slider.addEventListener('DOMMouseScroll', wheel, false);
	
		slider.onmousewheel = wheel;
	}
	
	if (content_container)
	{
		wrapper = $(content_container)[0];
		
		if (wrapper.addEventListener)
	        wrapper.addEventListener('DOMMouseScroll', wheel, false);
	
		wrapper.onmousewheel = wheel;
	}
}

