/*
 * Copyright (c) 2006 Sam Collett (http://www.texotela.co.uk)
 * Licensed under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 */
 
/*
 * A time picker for jQuery
 * Based on original timePicker by Sam Collet (http://www.texotela.co.uk)
 * @name     timePicker
 * @version  0.1 
 * @author   Anders Fajerson (http://perifer.se)
 * @example  $("#mytime").timePicker();
 * @example  $("#mytime").timePicker({step:30, startTime:"15:00", endTime:"18:00"}); 
 */

(function($){
  $.fn.timePicker = function(options, focusCallback, clickCallback) {
    var settings = {step:30, startTime:"00:00", endTime:"23:30"};
    $.extend(settings, options);
    
    this.each(function() {
      var elm = this;
      var times = [];
      var tpActive = false;
      var time = $.timePicker._timeStringToDate(settings.startTime);
      var endTime = $.timePicker._timeStringToDate(settings.endTime);
      while(time <= endTime) {
        times[times.length] = $.timePicker._formatTime(time);
        time = new Date(time.setMinutes(time.getMinutes() + settings.step));
      }
      var tpDiv = $('<div class="time-picker"></div>');
      var tpList = $('<ul></ul>');
      for(var i = 0; i < times.length; i++) {
        tpList.append("<li>" + times[i] + "</li>");
      }
      tpDiv.append(tpList);
      
      $("li", tpList).hover(function() {
        $(this).siblings().removeClass("selected").end().addClass("selected");
      },function() {
        $(this).removeClass("selected");
      }).mousedown(function() {
         tpActive = true;
      }).click(function() {
        // Update input field
        elm.value = $(this).text();
        // Keep focus for all but IE (which doesn't like it)
        if (!$.browser.msie)
          elm.focus();
        // Remove picker
        tpDiv.remove();
        tpActive = false;
        // Execute calback function if its defined
        if (typeof clickCallback == 'function') {
          clickCallback(elm.value);
        }
      });
      
      $(this).focus(function() {
        // Store element offset using dimension plugin
        var elmOffset = $(elm).offset();
        // Remove other time pickers, only needed when close on blur fails.
        $("div.time-picker").remove();
        // Insert and position picker
        $(tpDiv).appendTo('body').unbind().css({'top':elmOffset.top, 'left':elmOffset.left})
        .mouseover(function() { // Have to use mouseover instead of mousedown because of Opera
          tpActive = true;
        }).mouseout(function() {
          tpActive = false;
        }); 
        $("li", tpDiv).removeClass("selected");
        if (this.value) { // This is needed as contains() returns all time lists if input is empty
          var time = $.timePicker._timeStringToDate(this.value);
          var minutes = $.timePicker._timeStringToDate(settings.startTime).getMinutes();
          // Try to find a time in the list that matches the entered time.
          // Todo: this fails with some steps that are not evenly divided to 60 (7,8,9 etc)
          time = new Date(time.setMinutes(Math.round(time.getMinutes() / settings.step) * settings.step + minutes));
          var matchedTime = $("li", tpDiv).contains($.timePicker._formatTime(time));
          if (matchedTime.length) {
            matchedTime.addClass("selected");
            // Scroll to matched time using dimension plugin
            tpDiv.scrollTop(matchedTime[0].offsetTop);
          }
        }
        // Execute calback function if its defined
        if (typeof focusCallback == 'function') {
          focusCallback(elm.value);
        }
      })
      // Remove timepicker on blur
      .blur(function() {
        if (!tpActive && tpDiv[0].parentNode) { // Don't remove when timePicker is clicked or when already removed
          tpDiv.remove();
        }
      });
    
    });
    return this;
  };
  
  // Helper functions
  $.timePicker = {
    _formatTime: function(input) {
      if(input && input.constructor == Date) {
        return input.toUTCString().match(/\d{2}:\d{2}/);
      }
      throw "Not a valid date.";
    },
    _timeStringToDate: function(input) {
      var error;
      if(typeof input != "string") {
        error = "A string must be supplied.";
      }
      else if(input.match(/^\d{2}:\d{2}$/)) {
        var s = input.split(":");
        var hours = parseFloat(s[0]);
        var minutes = parseFloat(s[1]);
        minutes += hours * 60;
        var output = new Date();
        output.setTime(minutes * 60 * 1000);
        return output;
      }
      else {
        error = "Not a valid time string - should be in 24 hour format, i.e. 15:00.";
      }
      if(error) {
        throw error;
      }
    }
  }
  
})(jQuery);

