/*
 * 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.containerClass = opt.containerClass || "selectbox-wrapper";
   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);
   // hide select and append newly created elements
   $select.hide().before($input).before($container);
   // Mouse position in document on click action
   var mousex;
   var mousey;
   
   // For Firefox and Safari
   $(window).click(function(e) {
      mousex = e.pageX;
      mousey = e.pageY;
      if (!$.browser.msie && $container.is(':visible')) {
        $input.blur();
        if (opt.debug) 
          console.log(mousex + ' ' + mousey);
      }
   });
  
   // Get Top and Left position
   function getLeft(MyObject) {
     if (MyObject.offsetParent)
       return (MyObject.offsetLeft + getLeft(MyObject.offsetParent));
     else
       return (MyObject.offsetLeft);
   }
   function getTop(MyObject) {
     if (MyObject.offsetParent)
       return (MyObject.offsetTop + getTop(MyObject.offsetParent));
     else
       return (MyObject.offsetTop);
   }
   
   init();
   
   $input
   .click(function(){
        if (!inFocus) {
        $container.toggle();
      }
   })
   .focus(function(){
      if ($container.not(':visible')) {
          inFocus = true;
          $container.show();
      }
   })
   .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(e) {
		if ($container.is(':visible') && hasfocus > 0 ) {
			if(opt.debug) console.log('container visible and has focus')
		} else {
		  if($.browser.msie){ //For IE
        if(document.activeElement.getAttribute('id').indexOf('_container')==-1){
          hideMe();
        } else {
          $input.focus();
        }
      } else { //For Firefox and Safari
        var xzoneStart = getLeft($container.get(0));
        var xzoneEnd = getLeft($container.get(0)) + $container.get(0).offsetWidth;
        var yzoneStart = getTop($input.get(0));
        var yzoneEnd = getTop($input.get(0)) + $input.get(0).offsetHeight + $container.get(0).offsetHeight;
        if(opt.debug) console.log(xzoneStart+' '+xzoneEnd+' '+yzoneStart+' '+yzoneEnd+' '+mousex+' '+mousey);
        if(mousex >= xzoneStart && mousex <= xzoneEnd && mousey >= yzoneStart && mousey <= yzoneEnd) {
          $input.focus();
        } else {
          hideMe();
        }
      }
		}
	})
	/* SQLI */
    .resize(function(e) {
		hideMe();
	});
  
   function hideMe() { 
      hasfocus = 0;
      $container.hide(); 
   }
   
   function init() {
      $container.append(getSelectOptions($input.attr('id'))).hide();
      var width = $input.css('width');
      $container.width(width);
    }
   
   function setupContainer(options) {
      var container = document.createElement("div");
      $container = $(container);
      $container.attr('id', elm_id+'_container');
      $container.addClass(options.containerClass);
      
      return $container;
   }
   
   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
      
      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);
   }
   
   function setCurrent() { 
      var li = $("li."+opt.hoverClass, $container).get(0);
      var ar = (''+li.id).split('_');
      var el = ar[ar.length-1];
      $select.val(el);
      $input.val($(li).html());
      return true;
   }
   
   // select value
   function getCurrentSelected() {
      return $select.val();
   }
   
   // input value
   function getCurrentValue() {
      return $input.val();
   }
   
   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());
         
         /* Update SQLI */
         if($(this).attr('class')) {
         	$(li).attr('class', $(this).attr('class'));
         }
         
         li.innerHTML = $(this).html();
         if ($(this).is(':selected')) {
            $input.val($(this).html());
            $(li).addClass(opt.hoverClass);
         }
         ul.appendChild(li);
         $(li)
         .mouseover(function(event) {
            hasfocus = 1;
            if (opt.debug) console.log('out on : '+this.id);
            jQuery(event.target, $container).addClass(opt.hoverClass);
         })
         .mouseout(function(event) {
            hasfocus = -1;
            if (opt.debug) console.log('out on : '+this.id);
            jQuery(event.target, $container).removeClass(opt.hoverClass);
         })
         .click(function(event) {
            if (opt.debug) console.log('click on :'+this.id);
            
            /* SQLI : pb with select an item after scroll : we remove old active item class */
            ulParent = $(this).parent();
            $('li',ulParent).removeClass(opt.hoverClass);
            /********/
            
            $(this).addClass(opt.hoverClass);
            setCurrent();
            hideMe();
         });
      });
      return ul;
   }
   
};

