/*
 * jQuery selectbox plugin
 *
 * Copyright (c) 2007 Sadri Sahraoui (brainfault.com)
 * Licensed under the GPL license and MIT:
 *   http://www.opensource.org/licenses/GPL-license.php
 *   http://www.opensource.org/licenses/mit-license.php
 *
 * The code is inspired from Autocomplete plugin (http://www.dyve.net/jquery/?autocomplete)
 *
 * Revision: $Id$
 * Version: 0.4
 * 
 * Changelog :
 *  - Fix width when the select is in a hidden div   @Pawel Maziarz
 *  - Add a unique id for generated li to avoid conflict with other selects and empty values @Pawel Maziarz
 */
jQuery.fn.extend({
    selectbox: function(options) {
        return this.each(function() {
            new jQuery.SelectBox(this, options);
        });
    }
});


/* pawel maziarz: work around for ie logging */
if (!window.console) {
    var console = {
        log: function(msg) {
        }
    }
}
/* */

jQuery.SelectBox = function(selectobj, options) {
    var opt = options || {};
    opt.inputClass = opt.inputClass || "selectbox";
    opt.wrapperClass = opt.wrapperClass || "selectbox-wrapper";
    opt.containerClass = opt.containerClass || "selectbox-container";

    // Add by Alex Kachayev, 2010
    // <kachayev@gmail.com>
    classes = $(selectobj).attr('class').split(' ');
    if (classes.length > 1) {
        // We have few classes, so add every to container object
        opt.containerClass += ' ' + classes[1];
    }

    opt.hoverClass = opt.hoverClass || "selected";
    opt.debug = opt.debug || false;
	
    var elm_id = selectobj.id;
    var active = -1;
    var inFocus = false;
    var hasfocus = 0;
    //jquery object for select element
    var $select = $(selectobj);
    // jquery container object
    var $container = setupContainer(opt);
    //jquery input object
    var $input = setupInput(opt);
    var $wrapper = setupWrapper(opt);
	
    $wrapper.append($input);
    // hide select and append newly created elements
    $select.hide().before($wrapper);
	
    $('body').append($container);
	
    $.data($select.get(0), 'SelectBox', this);
	
    init();
	
    var justBlurForWrapperClick = false;
	
    $input
        .click(function(event) {
            justBlurForWrapperClick = false;
        })
        .focus(function(){
            /*if (!$container.is(':visible')) {
                   inFocus = true;
                   showMe();
               }*/
            })
        .keydown(function(event) {
            switch(event.keyCode) {
                case 38: // up
                    event.preventDefault();
                    moveSelect(-1);
                    break;
                case 40: // down
                    event.preventDefault();
                    moveSelect(1);
                    break;
                //case 9:  // tab
                case 13: // return
                    event.preventDefault(); // seems not working in mac !
                    setCurrent();
                    hideMe();
                    break;
            }
        })
        .blur(function(event) {
            setTimeout(function(event){
                if(!$container.hasClass('non-blurable')) {
                    if ($container.is(':visible') && hasfocus > 0 ) {
                        if(opt.debug) console.log('container visible and has focus');
                    } else {
                        hideMe();
                    }
                    justBlurForWrapperClick = true;
                } else {
                    $container.removeClass('non-blurable');
                }
            }, Browser.isIE() ? 400 : 10);
            return false;
        });
	
    $wrapper.click(function(event){
        /*if (inFocus) {
		  inFocus = false;
		  return;
		}*/
        if (justBlurForWrapperClick) {
            justBlurForWrapperClick = false;
            return;
        }
        if ($container.is(':visible')) {
            hideMe();
        } else {
            showMe();
            $(this).css('backgroundPosition','right bottom');
            $input.focus();
        }
    });
        
    this.reInit = function() {
        $container.empty();
        init();
    };
	
    this.syncValue = function() {
        var value = $select.val();
        selectValue(value);
    };

    function showMe() {
        var pos = $input.offset();
		
        var containerOffsetHeight = opt.containerOffsetHeight ? opt.containerOffsetHeight : 5;
		
        $container.css('left', pos.left + "px");
        $container.css('top', ( pos.top + $input.height() + containerOffsetHeight) + "px");
	    
        $container.show();
    }
	
    function hideMe() {
        hasfocus = 0;
        $container.hide();
        $($wrapper).css('backgroundPosition','right top');
    }
	
    function init() {
        $container.append(getSelectOptions($input.attr('id'))).hide();
        
        //var width = $input.css('width');
        //$container.width(width);
        if (opt.containerCss) {
            $container.css(opt.containerCss);
        }
    }
	
    function setupContainer(options) {
        var container = document.createElement("div");
        var $container = $(container);
        $container.attr('id', elm_id+'_container');
        $container.addClass(options.containerClass).css('zIndex', 12000);
                
        return $container;
    }
	
    function setupWrapper(options) {
        var wrapper = document.createElement("div");
        var $wrapper = $(wrapper);
        $wrapper.attr('id', elm_id+'_wrapper');
        $wrapper.addClass(options.wrapperClass);
        return $wrapper;
    }
	
    function setupInput(options) {
        var input = document.createElement("input");
        var $input = $(input);
        $input.attr("id", elm_id+"_input");
        $input.attr("type", "text");
        $input.addClass(options.inputClass);
        $input.attr("autocomplete", "off");
        $input.attr("readonly", "readonly");
        $input.attr("tabIndex", $select.attr("tabindex")); // "I" capital is important for ie
        //$input.css({ display:'block' });
		
        return $input;
    }
	
    function moveSelect(step) {
        var lis = $("li", $container);
        if (!lis) return;

        active += step;

        if (active < 0) {
            active = 0;
        } else if (active >= lis.size()) {
            active = lis.size() - 1;
        }

        lis.removeClass(opt.hoverClass);

        $(lis[active]).addClass(opt.hoverClass);
    }
	
    var previous = null;
    function setCurrent() {
        var li = $("li."+opt.hoverClass, $container).get(0);
        var ar = (''+li.id).split('---');
        var el = ar[ar.length-1];
        if (previous != el) {
            $select.val(el);
            $input.val($(li).text()); // Fixed by Alex Kachayev to avoid problems with '>' showing, 2010
            previous = el;
            $select.trigger('change');
        }
        return true;
    }
	
    function selectValue(value) {
        unselectAll();
        var li = $container.find('li#' + $input.attr('id') + '---' + value);
        li.addClass(opt.hoverClass);
        $input.val(li.text());
        previous = value;
        $select.val(value);
    }
	
    // select value
    function getCurrentSelected() {
        return $select.val();
    }
	
    // input value
    function getCurrentValue() {
        return $input.val();
    }
	
    function unselectAll() {
        $container.find('li.' + opt.hoverClass).removeClass(opt.hoverClass);
    }
	
    function getSelectOptions(parentid) {
        var select_options = new Array();
        var ul = document.createElement('ul');
        $select.children('option').each(function() {
            var li = document.createElement('li');
            li.setAttribute('id', parentid + '---' + $(this).val());
            li.innerHTML = $(this).html();
            if ($(this).is(':selected')) {
                $input.val($(this).text());   // Fixed by Alex Kachayev to avoid problems with '>' showing, 2010
                $(li).addClass(opt.hoverClass);
            }
            ul.appendChild(li);
            
            $(li)
            .mouseover(function(event) {
                hasfocus = 1;
                if (opt.debug) console.log('out on : '+this.id);
                unselectAll();
                jQuery(event.target, $container).addClass(opt.hoverClass);
            })
            .mouseout(function(event) {
                hasfocus = -1;
                if (opt.debug) console.log('out on : '+this.id);
                if ($container.is(':visible')) {
                    unselectAll();
                }
            //jQuery(event.target, $container).removeClass(opt.hoverClass);
            })
            .click(function(event) {
                if (opt.debug) console.log('click on :'+this.id);
                $(this).addClass(opt.hoverClass);
                setCurrent();
                hideMe();
                justBlurForWrapperClick = false;
            });
        });
        
        return ul;
    }
	
};
