/**
 * SELECT element replacement
 * 
 * @param {Object} class_conf Configuration
 */
function Selector(class_conf) {
	/* Reference to self */
	var _self = this;

	/* Configuration */
	this.conf = jQuery.extend({
								auto_resize: false,
								select_input: $('select'),		//SELECT element
								custom_input: $('div'),			//Element which will trigger popup
								popup: $('div'),				//Popup element
								popup_clipper: $('div'),		//Container element
								popup_content: $('div'),		//Content element
								popup_opacity: 1,				//Opacity
								on_change: null,				//Callback function which will be executed onchange
								popup_max_height: 768,			//Max height of the popup, if content > max height then it's scrolled
								popup_offset_y: 0,				//Popup y offset position
								
								_elements_a: [],				//List of a elements inside popup
								_elements_a_height: [],			//Height of a elements inside popup
								_selected: 0,					//Index of the selected option
								_popup_container_height: 0,		//Popup container height
								_popup_content_height: 0,		//Popup content height, >= container height
								_popup_state: 0,				//0 - hidden, 1 - visible, -1 - changing state
								_scroll_pos: 0,					//Popup content offset (scroll position)
								_scroll_in_progress: false,		//Content is scrolling or not
								_scroll_direction: 1			//1 - popup content is moving down, logicaly scrolling to the top; 0 - opposite to 1
							},
							class_conf);
	
	/* Calculates scroll */
	var recalculateScroll = function (stop_calc, mouse_y) {
		var old_scroll_direction = this.conf['_scroll_direction'];
		var start_scroll = false;
		
		if (!stop_calc && mouse_y < 50)
		{
			if (!this.conf['_scroll_in_progress'] || old_scroll_direction != 1)
			{
				start_scroll = true;
				this.conf['_scroll_direction'] = 1;
			}
		} else if (!stop_calc && mouse_y > this.conf['_popup_container_height'] - 50) {
			if (!this.conf['_scroll_in_progress'] || old_scroll_direction != -1)
			{
				start_scroll = true;
				this.conf['_scroll_direction'] = -1;
			}
		} else {
			if (this.conf['_scroll_in_progress'])
			{
				this.conf['popup_content'].stop();
				this.conf['_scroll_in_progress'] = false;
			}
		}
		
		if (start_scroll) {
			var a_pos = (this.conf['_scroll_direction'] == -1 ? - (this.conf['_popup_content_height'] - this.conf['_popup_container_height']) : 0);
			var time_pos = Math.abs(parseInt(this.conf['popup_content'].css('marginTop')) - a_pos) * 10;
			
			this.conf['popup_content'].stop().animate({marginTop: a_pos + 'px'}, time_pos, "linear");
			this.conf['_scroll_in_progress'] = true;
		}
	};
	
	/* Select item */
	var selectItem = function (a) {
		var sel = this.conf._selected;
		if (sel !==  null)
		{
			var old_a = this.conf._elements_a[sel];
			old_a._select_option.selected = false;
			$(old_a).removeClass('selected');
		}
		
		a._select_option.selected = true;
		$(a).addClass('selected');
		
		this.closeDropDown();
		this.conf._selected = a._select_index;
		
		this.conf.custom_input.html($(a).html());
		
		if (this.conf['on_change'].constructor === Function)
		{
			this.conf['on_change'](a._select_value);
		}
	};
	
	/* Initialize element list etc. */
	var initDOM = function () {
		var select  = this.conf.select_input;
		var options = select[0].options;
		var cont    = this.conf.popup_content;
		var _self   = this;
		
		this.conf.popup.css({display: 'block'});
		
		/* 
		 * Mouse has been moved, get mouse position relative to the popup and
		 * call recalculateScroll
		 */
		var initScroll = function (e) {
			var m_pos = (e.layerX !== undefined ? e.layerY : e.offsetY);
			
			/* Fix for #63 */
			if ($.browser.opera && $.browser.version >= 9 && $.browser.version < 10)
			{
				if (this.tagName == 'A' || e.target.tagName == 'A')
				{
					var o = (this.tagName == 'A' ? this : e.target);
					m_pos = o.offsetTop;
				}else{
					m_pos += parseInt(_self.conf['popup_content'].css('marginTop'));
				}
			}
			
			recalculateScroll.apply(_self, [false,m_pos]);
			
			/* Prevent propagation, because on document mouse over animation stops */
			return false;
		};
		
		
		for(var i=0, j=options.length; i<j; i++)
		{
			var a_element  = $('<a href="#">' + options[i].innerHTML + '</a><br />');
			cont.append(a_element);
			
			a_element[0]._select_object = this;					//'Selector' class instance
			a_element[0]._select_value  = options[i].value;		//Option value
			a_element[0]._select_option = options[i];			//Option element
			a_element[0]._select_index	= i;					//A element index in element list == option index
			
			this.conf._elements_a.push(a_element[0]);
			this.conf._elements_a_height.push(a_element[0].offsetTop);
			
			if (options[i].selected)
			{
				a_element.addClass('selected');
				this.conf._selected = i;
				this.conf.custom_input.html(a_element[0].innerHTML);
			}
			
			$(a_element[0]).click(function () {
				selectItem.apply(_self, [this]);
			});
		}
		
		
		/* Interaction */
		
		this.conf.popup_clipper
			.mousemove(initScroll)
			.mouseover(initScroll);
			
		$(document).mouseover(function (e) {
			if (_self.conf._scroll_in_progress)
				recalculateScroll.apply(_self, [true, 0, 0]);
		});
			
		this.conf.popup.click(function () {
			return false;
		});
		this.conf.custom_input.click(function () {
			if (_self.conf.popup.css('display') == 'block')
				_self.closeDropDown();
			else
				_self.openDropDown();
				
			return false;
		});
		$(document).click(function () {
			_self.closeDropDown();
		});
		
		
		/* Style */
		
		if (this.conf.auto_resize)
		{
			var w = select.width();
			this.conf.custom_input.css({width: w + 'px'});
			this.conf.popup.css('width', w + 20 + 'px');
		}
		
		select.css({display: 'none'});
		this.conf.custom_input.css({display: 'block'});
		
		var clipper = this.conf.popup_clipper;
		var max_h = this.conf.popup_max_height;
		var h = clipper.height();
		
		if (max_h > h) max_h = h;
		
		this.conf._popup_container_height = max_h;
		this.conf._popup_content_height = h;
		
		this.conf.popup.css({opacity: 0, display: 'none', marginTop: parseInt(-max_h / 2 + this.conf.popup_offset_y)});
		this.conf.popup_clipper.css({'height': max_h + 'px'});
	};
	
	initDOM.apply(this, []);
}

/* Open dropdown */
Selector.prototype.openDropDown = function () {
	if (this.conf._popup_state !== 0) return;
	this.conf._popup_state = -1;
	
	var opac = this.conf.popup_opacity;
	
	var offset = this.conf._elements_a_height[this.conf._selected] - this.conf['_popup_container_height'] / 2;
	var max_pos = this.conf._popup_content_height - this.conf._popup_container_height;
	var __self = this;
	
	if (offset > max_pos)
		offset = max_pos;
	else if (offset < 0)
		offset = 0;
	
	this.conf['_scroll_pos'] = -offset;
	
	this.conf['popup_content']
			.css({marginTop: - parseInt(offset) + 'px'});

	this.conf['popup']
			.css({display: 'block'})
			.animate({opacity: opac}, function () {
					__self.conf._popup_state = 1;
				});
			
	this.conf['custom_input'][0]._prev_html = this.conf['custom_input'].html();
	this.conf['custom_input'].html('');
};

/* Close dropdown */
Selector.prototype.closeDropDown = function () {
	if (this.conf._popup_state !== 1) return;
	this.conf._popup_state = -1;
	
	var p = this.conf.popup;
	var __self = this;
	
	p.animate({opacity: 0}, function () {
		p.css({display: 'none'});
		__self.conf._popup_state = 0;
	});
	
	this.conf.custom_input.html(this.conf.custom_input[0]._prev_html);
};