/*
Stylish Select 0.4.1 - $ plugin to replace a select drop down box with a stylable unordered list
http://github.com/sko77sun/Stylish-Select

Requires: jQuery 1.3 or newer

Contributions from Justin Beasley: http://www.harvest.org/ & Anatoly Ressin: http://www.artazor.lv/

Dual licensed under the MIT and GPL licenses.

*/
(function($){
   //add class to html tag
   $('html').addClass('stylish-select');

   function arrayIndexOf(array, obj, start) {
      for (var i = (start || 0); i < this.length; i++) {
         if (this[i] == obj) {
            return i;
         }
      }
   }

   //utility methods
   $.fn.extend({
      getSetSSValue: function(value){
         if (value){
            //set value and trigger change event
            $(this).val(value).change();
            return this;
         } else {
            return $(this).find(':selected').val();
         }
      },
      //added by Justin Beasley
      resetSS: function(){
         var oldOpts = $(this).data('ssOpts');
         $this = $(this);
         $this.next().remove();
         //unbind all events and redraw
         $this.unbind('.sSelect').sSelect(oldOpts);
      }
   });

   $.fn.sSelect = function(options) {

      return this.each(function(){

         var defaults = {
            defaultText: 'Selecteer...',
            animationSpeed: 0, //set speed of dropdown
            ddMaxHeight: '', //set css max-height value of dropdown
            containerClass: '', //additional classes for container div
            onTop: true // added by Szabó Gábor // ha ez FALSE, akkor mindig lefelé nyílik a select
         };

         //initial variables
         var opts = $.extend(defaults, options),
         $input = $(this),
         $containerDivText = $('<div class="selectedTxt"><div class="selectedTxt_label"></div></div>'),
         $containerDiv = $('<div class="newListSelected ' + opts.containerClass + '"></div>'),
         $newUl = $('<ul class="newList" style="visibility:hidden;"></ul>'),
         itemIndex = -1,
         currentIndex = -1,
         keys = [],
         prevKey = false,
         prevented = false,
         $newLi;

         //added by Justin Beasley
         $(this).data('ssOpts',options);

         //build new list
         $containerDiv.insertAfter($input);
         $containerDiv.attr("tabindex", $input.attr("tabindex") || "0");
         $containerDivText.prependTo($containerDiv);
         $newUl.appendTo($containerDiv);
         $input.hide();

         //added by Justin Beasley (used for lists initialized while hidden)
         $containerDivText.data('ssReRender',!$containerDivText.is(':visible'));

         //test for optgroup
         if ($input.children('optgroup').length == 0){
             $input.children().each(function(i){
                 var option = $(this).html();
                 var key = $(this).val();

                 //add first letter of each word to array
                 keys.push(option.charAt(0).toLowerCase());
                 if ($(this).attr('selected') == true){
                     opts.defaultText = option;
                     currentIndex = i;
                 }
                 $newUl.append($('<li><a href="JavaScript:void(0);">'+option+'</a></li>').data('key', key));

             });
             //cache list items object
             $newLi = $newUl.children().children();

         }
         else { //optgroup
             $input.children('optgroup').each(function(){

                 var optionTitle = $(this).attr('label'),
                 $optGroup = $('<li class="newListOptionTitle">'+optionTitle+'</li>');

                 $optGroup.appendTo($newUl);

                 var $optGroupList = $('<ul></ul>');

                 $optGroupList.appendTo($optGroup);

                 $(this).children().each(function(){
                     ++itemIndex;
                     var option = $(this).html();
                     var key = $(this).val();
                     //add first letter of each word to array
                     keys.push(option.charAt(0).toLowerCase());
                     if ($(this).attr('selected') == true){
                         opts.defaultText = option;
                         currentIndex = itemIndex;
                     }
                     $optGroupList.append($('<li><a href="JavaScript:void(0);">'+option+'</a></li>').data('key',key));
                 })
             });
             //cache list items object
             $newLi = $newUl.find('ul li a');
         }

         //get heights of new elements for use later
         var newUlHeight = $newUl.height(),
         containerHeight = $containerDiv.height(),
         newLiLength = $newLi.length;

         //check if a value is selected
         if (currentIndex != -1) {
             navigateList(currentIndex, true);
         }
         else {
             //set placeholder text
             $('.selectedTxt_label', $containerDivText).text(opts.defaultText);
         }

         //decide if to place the new list above or below the drop-down
         function newUlPos() {
            var containerPosY = $containerDiv.offset().top,
            docHeight = jQuery(window).height(),
            scrollTop = jQuery(window).scrollTop();

            //if height of list is greater then max height, set list height to max height value
            if (newUlHeight > parseInt(opts.ddMaxHeight)) {
               newUlHeight = parseInt(opts.ddMaxHeight);
            }

            containerPosY = containerPosY-scrollTop;

            // added by Szabó Gábor
            if (opts.onTop == false) {
               $newUl.css({
                   top: containerHeight+'px',
                   height: newUlHeight
               });
               $input.onTop = false;
            }
            else if (containerPosY+newUlHeight >= docHeight) {
               $newUl.css({
                   top: '-'+newUlHeight+'px',
                   height: newUlHeight
               });
               $input.onTop = true;
            }
            else {
               $newUl.css({
                   top: containerHeight+'px',
                   height: newUlHeight
               });
               $input.onTop = false;
            }
         }

         //run function on page load
         newUlPos();

         //run function on browser window resize
         $(window).bind('resize.sSelect scroll.sSelect', newUlPos);

         //positioning
         function positionFix(){
             $containerDiv.css('position','relative');
         }

         function positionHideFix(){
             $containerDiv.css('position','static');
         }

         $containerDivText.bind('click.sSelect',function(event){
             event.stopPropagation();

            //added by Justin Beasley
            if($(this).data('ssReRender')) {
               newUlHeight = $newUl.height('').height();
               containerHeight = $containerDiv.height();
               $(this).data('ssReRender',false);
               newUlPos();
            }

            //hide all menus apart from this one
            $('.newList').not($(this).next()).hide()
                    .parent()
                        .css('position', 'static')
                        .removeClass('newListSelFocus');

             //show/hide this menu
             $newUl.toggle();
             positionFix();
             //scroll list to selected item
             $newLi.eq(currentIndex).focus();

         });

         $newLi.bind('click.sSelect',function(e){
             var $clickedLi = $(e.target);

             //update counter
             currentIndex = $newLi.index($clickedLi);

             //remove all hilites, then add hilite to selected item
             prevented = true;
             navigateList(currentIndex);
             $newUl.hide();
             $containerDiv.css('position','static');//ie

         });

         $newLi.bind('mouseenter.sSelect',
            function(e) {
               var $hoveredLi = $(e.target);
               $hoveredLi.addClass('newListHover');
            }
         ).bind('mouseleave.sSelect',
            function(e) {
               var $hoveredLi = $(e.target);
               $hoveredLi.removeClass('newListHover');
            }
         );

         function navigateList(currentIndex, init){
            $newLi.removeClass('hiLite')
            .eq(currentIndex)
            .addClass('hiLite');

            if ($newUl.is(':visible')){
                $newLi.eq(currentIndex).focus();
            }

            var text = $newLi.eq(currentIndex).html();
            var val = $newLi.eq(currentIndex).parent().data('key');

            //page load
            if (init == true){
                $input.val(val);
                $('.selectedTxt_label', $containerDivText).text(text);
                return false;
            }

            try {
                $input.val(val)
            }
            catch(ex) {
                // handle ie6 exception
                $input[0].selectedIndex = currentIndex;
            }

             $input.change();
             $('.selectedTxt_label', $containerDivText).text(text);
         }

         $input.bind('change.sSelect',function(event){
            $targetInput = $(event.target);
            //stop change function from firing
            if (prevented == true){
                prevented = false;
                return false;
            }
            $currentOpt = $targetInput.find(':selected');

            currentIndex = $targetInput.find('option').index($currentOpt);

            navigateList(currentIndex, true);
         });

         //handle up and down keys
         function keyPress(element) {
             //when keys are pressed
             $(element).unbind('keydown.sSelect').bind('keydown.sSelect',function(e){
                 var keycode = e.which;

                 //prevent change function from firing
                 prevented = true;

                 switch(keycode) {
                     case 40: //down
                     case 39: //right
                         incrementList();
                         return false;
                         break;
                     case 38: //up
                     case 37: //left
                         decrementList();
                         return false;
                         break;
                     case 33: //page up
                     case 36: //home
                         gotoFirst();
                         return false;
                         break;
                     case 34: //page down
                     case 35: //end
                         gotoLast();
                         return false;
                         break;
                     case 13:
                     case 27:
                         $newUl.hide();
                         positionHideFix();
                         return false;
                         break;
                 }

                 //check for keyboard shortcuts
                 keyPressed = String.fromCharCode(keycode).toLowerCase();

                 var currentKeyIndex = arrayIndexOf(keys, keyPressed);

                 if (typeof currentKeyIndex != 'undefined') { //if key code found in array
                     ++currentIndex;
                     currentIndex = arrayIndexOf(keys, keyPressed, currentIndex); //search array from current index
                     if (currentIndex == -1 || currentIndex == null || prevKey != keyPressed)
                        currentIndex = arrayIndexOf(keys, keyPressed); //if no entry was found or new key pressed search from start of array


                     navigateList(currentIndex);
                     //store last key pressed
                     prevKey = keyPressed;
                     return false;
                 }
             });
         }

         function incrementList(){
             if (currentIndex < (newLiLength-1)) {
                 ++currentIndex;
                 navigateList(currentIndex);
             }
         }

         function decrementList(){
             if (currentIndex > 0) {
                 --currentIndex;
                 navigateList(currentIndex);
             }
         }

         function gotoFirst(){
             currentIndex = 0;
             navigateList(currentIndex);
         }

         function gotoLast(){
             currentIndex = newLiLength-1;
             navigateList(currentIndex);
         }

         $containerDiv.bind('click.sSelect',function(e){
             e.stopPropagation();
             keyPress(this);
         });

         $containerDiv.bind('focus.sSelect',function(){
             $(this).addClass('newListSelFocus');
             keyPress(this);
         });

         $containerDiv.bind('blur.sSelect',function(){
             $(this).removeClass('newListSelFocus');
         });

         //hide list on blur
         $(document).bind('click.sSelect',function(){
             $containerDiv.removeClass('newListSelFocus');
             $newUl.hide();
             positionHideFix();
         });

         //add classes on hover
         $containerDivText.bind('mouseenter.sSelect',
            function(e) {
               var $hoveredTxt = $(e.target);
               $hoveredTxt.parent().addClass('newListSelHover');
            }
         ).bind('mouseleave.sSelect',
            function(e) {
               var $hoveredTxt = $(e.target);
               $hoveredTxt.parent().removeClass('newListSelHover');
            }
         );

         //reset left property and hide
         $newUl.css({
             left: '0',
             display: 'none',
             visibility: 'visible'
         });

      });

   };

})(jQuery);

