/**
 * jQuery Plastic Select 1.4
 * 
 * Создает псевдоселекты
 * 
 * @required jQuery 1.4.4
 * 
 * @author Evgeny Samsonov (bitniks@bitniks.ru)
 * @date 2010/09/12 
 * 
 */

(function(){

    /**
     * @param {Object} options
     *                    options.block {object} Выпадающий блок. По умолчанию следующий за select блок
     *                    options.label {string} Псевдо option в select. По умолчанию .plastic-select-option  
     *
     * @example
     *         $('select').plasticSelect();		Стилизация всех select на странице с параметрами по умолчанию
     *
     *         $('.megaselect').plasticSelect({
     *             block    : "#megaselect-combo"
     *         });
     *         									Стилизация select с классом megaselect. Выпадающий блок с id megaselect-combo
     *
     *         $('select').plasticSelect('disable');		Деактивировать select
     *         $('select').plasticSelect('enable');			Активировать select
     *
     */
    $.fn.plasticSelect = function(options) {
    	    	
        if (typeof options === 'object' || ! options) {
        	// Передан объект с конфигурацией, либо ничего не передано. => Инициализация
            return methods.init.apply( this, arguments );
        }
        else {
        	// Передано название внутренней функции. Вызываем ее 
            return methods[ options ].apply( this, Array.prototype.slice.call( arguments, 1 ));
        }
    }

    // Методы библиотеки
    var methods = {
    	
    	/**
    	 * Инициализация
    	 * 
    	 * @param <string, object> options[block]  	Выпадающий блок
    	 * @param <string, object> options[label]	Какие элементы внтури block считать за option
    	 * 				    		   
    	 */
    	init : function(options) {
    		
            var o = options;

            this.each(function() {
            	
            	// Соединяем опции по умолчанию с переданными опциями
                var options = jQuery.extend({
                        block : $(this).next(),
                        label : '.plastic-select-option'
                    },
                    o
                );

                // Псевдоселект в html
                var wrapperMain = $("<div class='plastic-select'></div>");	// Основной обертка селект
                var wrapperCombo = $("<div class='plastic-select-combo'></div>");	// Выпадающий блок селект
                // Видимый блок селект
                var fakeSelect = $("<div class='plastic-select-input'><div class='plastic-select-text'></div><span class='plastic-select-button'></span><span class='plastic-select-extra'></span></div");

                // Оборачиваем block псевдоселектом
                $(options.block).wrap(wrapperCombo);
                $(options.block).parent().wrap(wrapperMain);                
                var wrapperDiv = $(options.block).parents('.plastic-select');
                var selectCombo = $('.plastic-select-combo', wrapperDiv);
                
                // Верхняя граница селекта
                var topSelectCombo = parseInt($(selectCombo).css('top').replace(/px/gi, ''));  
                
                $(selectCombo).hide();
                $(this).hide();
                $(wrapperDiv).attr("tabindex", $(this).attr("tabindex") || "0");
                $(wrapperDiv).prepend(fakeSelect);
                	
                var selectInput = $('.plastic-select-input', wrapperDiv);
                var selectText = $('.plastic-select-text', selectInput);

                // Получаем текущие значения
                var selected = $('option:selected', this);
                var selectedValue = $(selected).val();
                var selectedText = $(selected).text();

                // Сохраняем данные для методов
                $(this).data('plasticSelect',
                    {
                        wrapperDiv : wrapperDiv,
                        selectInput : selectInput,
                        selectCombo : selectCombo,
                        wrapperCombo : wrapperCombo,
                        selectText : selectText,
                        options : options
                    }
                );

                // Цепляем на все поля селекта (options.label) события
                // Устанавливаем связь между селектом и псевдоселектом
                // Вешаем события
                var self = this; 
                selectText.text(selectedText);
                selectText.attr('title', selectedText);
                $(options.label, wrapperDiv).each(function(){
                    var input = $('input', this);
                    var value = $(input).val();
                    var text = $(input).text();
                    if (value == selectedValue) {
                        $(this).addClass('plastic-select-selected');
                        $(input).attr('selected', 'selected');
                    }

                    // На клик производим выбор значения
                    $(this).bind('click.plasticSelect', function(e){
                        $('.plastic-select-option', selectCombo).removeClass('plastic-select-selected');
                        $(this).addClass('plastic-select-selected');
                        //$(input).attr('selected', 'selected');

                        var option = $('option[value=' + value + ']', self);
                        $(option).attr('selected', selected);
                        $(selectText).text( $(option).text() );

                        $(selectText).attr('title', $(option).text() );
                        $(selectCombo).hide();
                        $(wrapperDiv).removeClass('plastic-select-focus').removeClass('plastic-select-open');

                        $(wrapperDiv).trigger('change');
                    });
                }).mouseenter(function() {
                    $(this).addClass('plastic-select-option-hover');
                }).mouseleave(function(){
                    $(this).removeClass('plastic-select-option-hover');
                }).mousedown(function(){
                    $(this).addClass('plastic-select-option-active');
                }).mouseup(function(){
                    $(this).removeClass('plastic-select-option-active');
                });

                // Включаем селект
                methods.enable.apply( this, arguments );

                // Выбираем, куда будет выпадать селект: вниз или вверх                
                var fixPosition = function() {                  
                    var offsetWrapperDiv = $(wrapperDiv).offset(),
                        heightFakeSelect = $(fakeSelect).outerHeight(),
                        scrollTop = jQuery(window).scrollTop(),
                        docHeight = jQuery(window).height();

                    // Находим высоту скрытого блока
                    var cloneSelectCombo = $(selectCombo).clone();
                    cloneSelectCombo.css({
                        top: '-3000px',
                        display: 'block'
                    });
                    var p = $(selectCombo).parent();
                    p.append(cloneSelectCombo);
                    var $ch = $(cloneSelectCombo).children();
                    $ch.show();
                    heightSelectCombo = $(cloneSelectCombo).height();
                    $(cloneSelectCombo).remove();

                        topSelectCombo = -2;	// Хак для бордера в 2 px
                    var offsetTop = offsetWrapperDiv.top - scrollTop;
                    var offsetBottom = docHeight - (offsetWrapperDiv.top + heightFakeSelect);
                    if (offsetBottom > heightSelectCombo || offsetTop < heightSelectCombo){
                    	// Вниз
                        heightFakeSelect = heightFakeSelect + topSelectCombo;
                        $(selectCombo).css({
                            top : heightFakeSelect  + 'px'
                        });
                        $(wrapperDiv).addClass('plastic-select-bottom');
                        $(wrapperDiv).removeClass('plastic-select-top');
                    }
                    else {
                    	// Вверх
                        heightSelectCombo = heightSelectCombo - topSelectCombo * -1;
                        $(selectCombo).css({
                            top : '-' + heightSelectCombo + 'px'
                        });
                        $(wrapperDiv).addClass('plastic-select-top');
                        $(wrapperDiv).removeClass('plastic-select-bottom');
                    }
                }

                fixPosition();
                var timer = 0;
                $(window).bind('resize.sSelect scroll.sSelect', function(){
                    clearTimeout(timer);
                    timer = setTimeout(fixPosition, 500);
                });
            });
        },
        // Отключение селекта
        disable : function() {
            var ps  = $(this).data('plasticSelect');

            //$(this).attr('disabled', 'disabled');

            with (ps) {
                $(wrapperDiv).addClass('plastic-select-disabled');
                $(wrapperDiv).unbind('.plasticSelect');
                $(selectInput).unbind('.plasticSelect');
                $(selectCombo).hide();
            }
        },
        // Включение селекта
        enable : function() {

            var ps  = $(this).data('plasticSelect');

            if (!ps) return;

            $(this).removeAttr('disabled');

            with (ps) {

                $(wrapperDiv).removeClass('plastic-select-disabled');
                
                // Вешаем снова события                
                $(wrapperDiv).bind('focus.plasticSelect', function(){
                    $(wrapperDiv).addClass('plastic-select-focus');
                });

                $(wrapperDiv).bind('blur.plasticSelect', function(){
                    $(wrapperDiv).removeClass('plastic-select-focus').removeClass('plastic-select-open');
                    $(selectCombo).hide();
                });

                $(wrapperDiv).bind('mouseover.plasticSelect', function(){
                    $(this).addClass('plastic-select-hover');
                });

                $(wrapperDiv).bind('mouseout.plasticSelect', function(){
                    $(this).removeClass('plastic-select-hover')
                           .removeClass('plastic-select-active');
                });

                $(selectInput).bind('click.plasticSelect', function(e){
                    e.stopPropagation();
                    if ($(selectCombo).is(":visible")){
                        $(wrapperDiv).removeClass('plastic-select-open');
                        $(selectCombo).hide();
                    }
                    else {
                        $('.plastic-select-combo').hide(); 
                        $(wrapperDiv).addClass('plastic-select-open');
                        $(selectCombo).show();
                    }
                });

                $(selectCombo).bind('click.plasticSelect', function(e){
                    e.stopPropagation();
                });

                // Mouse Down
                $(wrapperDiv).bind('mousedown.plasticSelect', function(){
                    $(this).addClass('plastic-select-active');
                });

                // Mouse Up
                $(wrapperDiv).bind('mouseup.plasticSelect', function(){
                    $(this).removeClass('plastic-select-active');
                });

                $(document).bind('click.plasticSelect',function(){
                    $(wrapperDiv).removeClass('plastic-select-focus').removeClass('plastic-select-open');;
                    $(selectCombo).hide();
                });
            }
        },
        // Установка значения селект
        // @param <int> value 	Устанавливаемое значение
        value : function(value) {        	
            var ps  = $(this).data('plasticSelect');
            if (!ps) return;
            with (ps) {
                if (value) {
                    $('.plastic-select-option', selectCombo).removeClass('plastic-select-selected');

                    var option = $('input[value=' + value + ']', selectCombo);
                    $(option).parents('.plastic-select-option').addClass('plastic-select-selected');

                    var option = $('option[value=' + value + ']', this);
                    $(option).attr('selected', 'selected');                    
                    $(selectText).text($(option).text());
                }
                else {
                    var value = $('.plastic-select-selected input', selectCombo).val();
                    return value;
                }
            }
        },
        // Сворачивает селект
        close : function(){
            var ps  = $(this).data('plasticSelect');
            if (!ps) return;
            with (ps) {
                $(selectCombo).hide();
                $(wrapperDiv).removeClass('plastic-select-focus').removeClass('plastic-select-open');
            }
        },
        // Вешает функцию на change 
        // @param <function> fn 	Функция
        change : function(fn) {
            var ps  = $(this).data('plasticSelect');
            if (!ps) return;
            $(ps.wrapperDiv).bind('change', fn);
        },
        // Искусственно вызывает событие селекта
        // @param <string> event	Событие
        trigger : function(event) {
            var ps  = $(this).data('plasticSelect');
            if (!ps) return;
            $(ps.wrapperDiv).trigger(event);
        },
        // Вешает функцию на mouseenter 
        // @param <function> fn 	Функция 
        mouseenter : function(fn) {
            var ps  = $(this).data('plasticSelect');
            if (!ps) return;
            $(ps.options.label, ps.wrapperDiv).bind('mouseenter', fn);
        },
        // Вешает функцию на mouseleave 
        // @param <function> fn 	Функция
        mouseleave : function(fn) {
            var ps  = $(this).data('plasticSelect');
            if (!ps) return;
            $(ps.options.label, ps.wrapperDiv).bind('mouseleave', fn);
        },
        // Получает значение определенной опции селекта  
        // @pos <int> pos 	Позиция опции
        valueByPos : function(pos) {
            var ps  = $(this).data('plasticSelect');
            if (!ps) return;
            with (ps) {
                var option = $('.plastic-select-option:eq(' + (pos - 1) + ')', selectCombo);
                var value = $('input', option).val();
                return value;
            }
        }
    }

})(jQuery);
