/*
@name itcSelect
@version 20100820

Методы:
$('#id').itcSelect({}) - подключение плагина к стандартному селекту
$('#id').itcSelect('setOptions', values) - установка новых вариантов(option в контексте <select>), values - массив объектов, [{name: 'Значение1', value: 'v1'},..., {name: 'ЗначениеN', value: 'vN'}]
$('#id').itcSelect('setValue', {name: 'Значение2', value: 'v2'}, [skipCallback]) - установка значения селекта. Вместо объекта может передаваться индекс варианта в ранее установленном через setOptions массиве
$('#id').itcSelect('getValue') - возвращает текущее значение(объект)


Callback:
onOpen - перед показом дропдауна. return false - не показывать меню
onClose(eventBy) - перед скрытием дропдауна. return false - не скрывать меню
onChange(oldValue, newValue) - клик по значению из списка. return false - не скрывать меню после выбора(напр., если выбран всё тот же пункт или запрещенный пункт меню)

eventBy:
 document - клик мимо дропдауна;
 control - клик по контролу(иконка или поле с текущим значением);
 option - клик по пункту из списка
*/

$.widget("ui.itcSelect", {
    options: {
        // Префикс стилей кастомизованного селекта
        cssPrefix: "itc_select",
        // Картинка для кнопки селекта
        dropdownImage: "images/select_but.gif",
        dropdownImageHover: "",
        dropdownImagePressed: "",
        width: 220,
        buttonWidth: 20,
        // Количество видимых элементов(если больше, то появляется скролл)
        listSize: 0,
		listHeight: 0,
        // Отключить hover-стили контрола
        hover: true,
        // Отключить pressed-стили контрола
        pressed: true,
        emptyName: '(Пусто)',
        // События
        onOpen: function () {},
        onClose: function () {},
        onChange: function () {},
        // Массив с объектами-значениями
        values: []
    },
    _init: function () {
        var self = this;

        if (self.options.dropdownImageHover == '') {
            self.options.dropdownImageHover = self.options.dropdownImage;
        }

        if (self.options.dropdownImagePressed == '') {
            self.options.dropdownImagePressed = self.options.dropdownImage;
        }

        var $select = this.element.find('select:eq(0)');
        this.elementClass = $select.attr('id');
        this.currentValue = '';
        this.currentName = self.options.emptyName;

        this.setOptions = function (optionsObj) {
            /* {{{ */
            var optionsHtml = '';
            self.values = optionsObj;
            self.currentValue = null;
            self.currentName = '';

            if (optionsObj.length == 0) {
                optionsHtml += '<li id="' + self.elementClass + '_value_' + self.currentValue + '" class="odd">' + self.options.emptyName + '</li>' + "\n";
            } else {
                for (var i = 0; i < optionsObj.length; i++) {
                    optionsHtml += '<li id="' + self.elementClass + '_value_' + optionsObj[i].value + '" class="' + ((i + 1) % 2 == 0 ? 'even' : 'odd') + '" unselectable="on">' + optionsObj[i].name + '</li>' + "\n";
                }
            }

            $('#' + self.elementClass + '_hidden').attr('value', '');
            $('#' + self.elementClass + '_control .caption_container div').html(self.options.emptyName).attr('title', self.options.emptyName);

            self.element.find('#' + self.elementClass + '_list_ul').html(optionsHtml);
            
            /*if (self.options.listSize > 0) {
                // Хитрый хак, позволяющий узнать высоту элемента
                self.element.find('#' + self.elementClass + '_list').css('visibility', 'hidden').css('display', 'block');
                var elementHeight = $('#' + self.elementClass + '_list_ul li:eq(0)').outerHeight();
                self.element.find('#' + self.elementClass + '_list').css('visibility', '').css('display', '');
                var allowedHeight = elementHeight * self.options.listSize;

                if ($('#' + self.elementClass + '_list').height() > allowedHeight) {
                    $('#' + self.elementClass + '_list').height(allowedHeight + 'px');
                } else {
                    $('#' + self.elementClass + '_list').height('auto');
                }
            }*/
			this._setListSize();
        };
		
		this._setListSize = function () {
			if (self.options.listSize > 0) {
                // Хитрый хак, позволяющий узнать высоту элемента
                self.element.find('#' + self.elementClass + '_list').css('visibility', 'hidden').css('display', 'block');
                var elementHeight = $('#' + self.elementClass + '_list_ul li:eq(0)').outerHeight();
                self.element.find('#' + self.elementClass + '_list').css('visibility', '').css('display', '');
			    var allowedHeight = elementHeight * self.options.listSize;

                if ($('#' + self.elementClass + '_list').height() >= allowedHeight/* || $('#' + self.elementClass + '_list').height() == 0*/) {
                    $('#' + self.elementClass + '_list').height(allowedHeight + 'px');
                } else {
                    $('#' + self.elementClass + '_list').height('auto');
                }
            } else if (self.optionis.listHeight > 0) {
				$('#' + self.elementClass + '_list').height(allowedHeight + 'px');
			}
		}

        this.setValue = function (valueObj, skipCallback) {
            if (typeof(valueObj) == 'number') {
                valueObj = self.values[valueObj];
            }
			
			if (typeof(valueObj) == 'undefined') {
				if (typeof(console) != 'undefined') {
					console.log('Try to set non-existent value: ' + self.elementClass);
				}
				
				return;
			}

            var oldName = $('#' + self.elementClass + '_control .caption_container div').html();
            var oldValue = $('#' + self.elementClass + '_hidden').attr('value');

			try {
				$('#' + self.elementClass + '_hidden').attr('value', valueObj.value);
				$('#' + self.elementClass + '_control .caption_container div').html(valueObj.name).attr('title', valueObj.name);
				self.currentName = valueObj.name;
				self.currentValue = valueObj.value;
			} catch (ex) {
			}

            if ((typeof(skipCallback) == 'undefined' || skipCallback != true) && self.options.onChange({name: oldName, value: oldValue}, valueObj) === false) {
                $('#' + self.elementClass + '_hidden').attr('value', oldValue);
                $('#' + self.elementClass + '_control .caption_container div').html(oldName).attr('title', oldName);
            self.currentName = oldName;
            self.currentValue = oldValue;
            }
            /* }}} */
        };

        self.getValue = function () {
            return {name: self.currentName, value: self.currentValue};
        }

        // Прелоадим картинки
        var image1 = document.createElement('img').setAttribute('src', self.options.dropdownImage);
        var image2 = document.createElement('img').setAttribute('src', self.options.dropdownImageHover);
        var image3 = document.createElement('img').setAttribute('src', self.options.dropdownImagePressed);

        // Определяем значение для селекта по умолчанию. <option selected="selected">
        var $default = $select.find('option[selected]:eq(0)');

        // Значения нет, берем первое из опшэнов
        if ($default.length == 0) {
            $default = $select.find('option:eq(0)');
        }

        // Опшэнов нет, пихаем текст-заглушку
        if ($default.length == 0) {
            self.currentValue = '';
            self.currentName = '(Пусто)';
        } else {
            self.currentValue = $default.attr('value');
            self.currentName = $default.html();
        }

        // Получаем все option из селекта, строим li-список.
        // Value пишется в айди, надпись - в текстовую ноду
        var $options = $select.find('option');

        var optionsObj = [];

        for (var i = 0; i < $options.length; i++) {
            optionsObj.push({value: $options.eq(i).attr('value'), name: $options.eq(i).html()});
        }

        self.options.values = optionsObj;
        var width_itc_select = self.options.width - self.options.buttonWidth - 1;


        // Генерируем код для замены стандартного селекта
        /* {{{ */
        var html =  '<table cellpadding="0" cellspacing="0" border="0" class="' + self.options.cssPrefix + '_control" id="' + self.elementClass + '_control" style="width: ' + self.options.width.toString() + 'px;">' + "\n"
                 + '    <tr>' + "\n"
                 + '        <td><div class="' + 'caption_container" id="' + self.elementClass + '_caption_container" style="width: ' + (width_itc_select + 1).toString() + 'px;"><div title="' + self.currentName + '">' + self.currentName + '</div></div></td>' + "\n"
                 + '        <td><img class="' + self.options.cssPrefix + '_button" id="' + self.elementClass + '_button" src="' + self.options.dropdownImage + '" unselectable="on"/></td>' + "\n"
                 + '    </tr>' + "\n"
                 + '</table>' + "\n"
                 + '<input type="hidden" name="' + $select.attr('name') + '" id="' + self.elementClass + '_hidden" value="' + self.currentValue + '"/>' + "\n"
                 + '<div class="' + self.options.cssPrefix + '_list" id="' + self.elementClass + '_list" style="width: ' + (self.options.width - 2).toString() + 'px;">' + "\n"
                 + '    <ul class="' + self.options.cssPrefix + '_list" id="' + self.elementClass + '_list_ul">' + "\n"
                 + '    </ul>' + "\n"
                 + '</div>' + "\n";
        /* }}} */


        $select.replaceWith(html);
        // Сохраняем текущее значение, т.к. при вставке новых оно сбрасывается
        var argValue = {name: self.currentName, value: self.currentValue};
        this.setOptions(optionsObj);
        this.setValue(argValue, true);

        // Открытие выпадающего списка
        var _dropdownClick = function() {
            /* {{{ */
			self._setListSize();
			
            if($('#' + self.elementClass + '_list').css('display') == 'none') {
                // Скрытие по клику мимо селекта
                $(document).bind('click', function (e) {
                    var offset = $('#' + self.elementClass + '_list').offset();

                    if (e.pageX > offset.left && e.pageX < (offset.left + $('#' + self.elementClass + '_list').width())
                        && e.pageY > (offset.top - $('#' + self.elementClass + '_control').height()) && e.pageY < (offset.top + $('#' + self.elementClass + '_list').height())) {
                        return false;
                    } else {
                        if (self.options.onClose('document') != false) {
                            _closeSelect('document');
                        }
                    }
                });

                if (self.options.onOpen() != false) {
                    $('#' + self.elementClass + '_list').css('display', 'block');

                    if (self.options.pressed != false) {
                        $('#' + self.elementClass + '_control').addClass(self.options.cssPrefix + '_control_pressed');
                        $('#' + self.elementClass + '_button').attr('src', self.options.dropdownImagePressed);
                    }
                }
            } else {
                if (self.options.onClose('control') != false) {
                    _closeSelect('control');
                }
            }
            /* }}} */
        };

        // Выбор значения из выпадающего списка
        var _optionClick = function () {
            var newValue = $(this).attr('id').substr((self.elementClass + '_value_').length);

            self.setValue({
                name: $(this).html(), 
                value: $(this).attr('id').substr((self.elementClass + '_value_').length)
            });

            if (self.options.onClose('option') != false) {
                _closeSelect('list');
            }
        };

        // Закрытие выпадающего списка
        var _closeSelect = function (eventBy) {
            /* {{{ */
            $('#' + self.elementClass + '_list').css('display', 'none');
            $('#' + self.elementClass + '_control').removeClass(self.options.cssPrefix + '_control_pressed');

            if (eventBy != 'control') {
                $('#' + self.elementClass + '_control').removeClass(self.options.cssPrefix + '_control_hover');
                $('#' + self.elementClass + '_button').attr('src', self.options.dropdownImage);
            }

            $(document).unbind('click');
            /* }}} */
        };

        // Вешаем клик на контрол(надпись + картинка дропдауна)
        $('#' + self.elementClass + '_control').click(_dropdownClick);

        if (self.options.hover != false) {
            $('#' + self.elementClass + '_control').hover(function () {
                /* {{{ */
                if ($(this).hasClass(self.options.cssPrefix + '_control_pressed') == false) {
                    $(this).addClass(self.options.cssPrefix + '_control_hover');
                    $('#' + self.elementClass + '_button').attr('src', self.options.dropdownImageHover);
                }
            }, function () {
                if ($(this).hasClass(self.options.cssPrefix + '_control_pressed') == false) {
                    $(this).removeClass(self.options.cssPrefix + '_control_hover');
                    $('#' + self.elementClass + '_button').attr('src', self.options.dropdownImage);
                }
                /* }}} */
            });
        }

        // Выбор пункта из меню
        $('#' + self.elementClass + '_list_ul').delegate('li', 'click', _optionClick);

        $('#' + self.elementClass + '_list_ul').delegate('li', 'hover', 
            function () {$(this).toggleClass('hover')}
        );
    }
});

