/*
 * jQuery-Calendar-DayCalendar
 * 
 * Requires:
 * - jquery 1.4.2
 * - jquery-ui 1.8.1 (widget, drag, drop, resize)
 *
 * Copyright (c) 2010 Onno Lissenberg
 * 
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 * Inspired by the jQuery-Week-Calendar from Rob Monie
 *
 *  Sources:      
 *     http://everydayicons.jp/patterns.html
 *     http://jacwright.com/projects/javascript/date_format
 *     http://github.com/robmonie/jquery-week-calendar
 *     
 *  References:
 *     http://api.jquery.com/
 *     http://www.learningjquery.com/2007/10/a-plugin-development-pattern
 *     http://github.com/jquery/jquery-ui/tree/master/ui/
 *     http://code.jquery.com/jquery-1.4.2.js
 *     https://developer.mozilla.org/en/Gecko_DOM_Reference
 *     ( future reference: http://www.datejs.com/ )
 */

(function($) {	
	var debug = false; // enable to show debug information.
	function log(obj) {     
		if (typeof console != 'undefined' && debug) { console.debug(obj); }
	};
   
   /* -------------------------------------------- *
    * SIMPLE EVENT WIDGET                          *
    * -------------------------------------------- */ 
   $.widget("calendar.simpleevent", {
      millis_in_day : 86400000,
      millis_in_minute : 86400000 / 24 / 60, 
      
      options : {
         'calendar' : null,
         'period' : {
            'start':null, 
            'end':null
         },
         'height': 40,
         'width': 200,
         'offset': {},
         'container': null,         
         'title': 'Unknown',
         // The edit event will be triggered after first time creation.
         'autoedit': false,
         // Event will remove itself after clicking the delete button.
         'autoremove': true,
         'resizable': true,
         'buttons': [],
         'userdata': {}                  
      },
      
      _create : function() {
         var self = this;              
      },
      
      _init : function() {
         var self = this;
                                    
         self._initRender();
      },
      
      _initRender : function() {
         var self = this;
         self.options = $.extend(true,{},self.options,$.simpleevent.options);                  
         
         self.eventContainer = $(this.element)
            .addClass('calendar-event')                           
            .css({   
               'position': 'absolute',
               'display': 'block'
            });

         self.eventTable = $('<table style="width:100%;"/>')
            .appendTo(self.eventContainer);

         var headerRow = $('<tr/>').appendTo(self.eventTable);

         //MOVE
         self.moveHandle = $('<div/>')
            .addClass('ui-state-default ui-corner-all drag-handle event-action')
            .append('<span class="ui-icon ui-icon-arrow-4-diag"></span>');
            
         // EDIT            
         self.editHandle = $('<div/>')
            .addClass('ui-state-default ui-corner-all edit-handle event-action')
            .append('<span class="ui-icon ui-icon-pencil"></span>');            
         
         // DELETE
         self.deleteHandle = $('<div/>')
            .addClass('ui-state-default ui-corner-all delete-handle event-action')
            .append('<span class="ui-icon ui-icon-trash"></span>');

         self.handleContainer = $('<td/>')            
            .appendTo(headerRow)
            .append(self.moveHandle)
            .append(self.editHandle)
            .append(self.deleteHandle);

         // ADD Custom Buttons!
         for (var handle in self.options.buttons) {            
            var item = self.options.buttons[handle];
            var handle = $('<div/>')
            .addClass('ui-state-default ui-corner-all '+item.name+'-handle event-action')
            .append('<span class="ui-icon '+item.icon+'"></span>');
            
            self.handleContainer.append(handle);
            
            /*
             * A nice reminder of something I always trip over.
             * http://robertnyman.com/2008/10/09/explaining-javascript-scope-and-closures/
             * Hence creating these "custom" envent handles requires a closure.
             */
            (function (name, element) {
               element.bind(name+'-event', function(e){
                  log(e);
                  log(name+'-event triggered');
               });
               
               handle.click(function() {
                  element.trigger(name+'-event');
               });            
            })(item.name, self.eventContainer);
         }
         
         // TITLE         
         var titleRow = $('<tr/>').appendTo(self.eventTable);

         self.eventTitle = $('<td/>')            
            .appendTo(titleRow);
            
         // CONTENT         
         var contentRow = $('<tr/>').appendTo(self.eventTable);
         
         self.eventContent = $('<td/>')
            .attr({'colspan':'4'})
            .appendTo(contentRow);

         if (self.options.resizable) {
            self.eventContainer.resizable({ 
               // grid: [slotsize,slotsize],
               maxWidth: self.eventContainer.width,
               minWidth: self.eventContainer.width,
               stop: function(event, ui) {
                  // defaults when an event is not attached to a calendar.
                  var calendar = self.options.calendar;  
                  var slotsize = 20;
                  var minutesPerSlot = 60;
                  var millisPerPixel = (minutesPerSlot * 60 * 1000) / 20;
                  
                  // resized by the slotsize amount
                  if (calendar) {
                     minutesPerSlot = 60 / calendar.options.timeslotsPerHour;
                     slotsize = calendar.options.timeslotHeight; 
                  }
                  
                  var endsize = Math.round(ui.size.height / slotsize);                                    
                  var endtime = endsize * minutesPerSlot * 60 * 1000;               
                  
                  self.options.period.end = new Date(self.options.period.start.getTime() + endtime);
                  self.options.height = ui.size.height;
                  self.refresh();
               }
            });
         };
                                 
         self.eventContainer.draggable({
               'handle': '.drag-handle',
               'cursor': 'move',
               'revert': 'invalid'
            });
                        
         self._initEvents();                                                             
         self.refresh();
      },
      
      autoFit : function() {
         
         var self = $(this.element);
         var jq = $(this.options.container);         
         
         if (this.options.container && jq.length) {         
            this.options.height = jq.height();
            this.options.width = jq.width();
            this.options.offset.left = jq.offset().left;
            
            if (this.options.period.start > jq.data('period').start) {
               var calendar = this.options.calendar;         
               var millisPerPixel = ((60 / calendar.options.timeslotsPerHour) * 60 * 1000) / calendar.options.timeslotHeight;
               
               var diff = (this.options.period.start.getTime() - jq.data('period').start.getTime()) / millisPerPixel;
               this.options.offset.top = jq.offset().top + diff;
            } else {
               this.options.offset.top = jq.offset().top;
            }            
         }
         
         this.refresh();
      },
      
      duration : function() {
         var duration = this.options.period.end.getTime() - this.options.period.start.getTime();
         return duration; 
      },
         
      refresh : function() {
         var self = this;
         self.eventTitle.html(self.options.title);         

         // Remove the resizable feature.
         if (!this.options.resizable) {
            self.eventContainer.resizable( "destroy" );
         }

         var calcHeight = self.options.height;
         if (self.options.calendar) {
            // Set the height equal to the duration of the event.
            var calendar = self.options.calendar;         
            var millisPerPixel = ((60 / calendar.options.timeslotsPerHour) * 60 * 1000) / calendar.options.timeslotHeight;

            calcHeight = (this.options.period.end.getTime() - this.options.period.start.getTime()) / millisPerPixel;
            self.options.height = calcHeight;
         }
         
         self.eventContent
            .html($.daycalendar.formatDate(self.options.period.start,"h:i a") + ' - ' + $.daycalendar.formatDate(self.options.period.end,"h:i a"));
            
         self.eventContainer            
            .css({   
               'height': calcHeight +'px',
               'width': self.options.width+'px'
            });
         
         if (self.options.offset.top) { self.eventContainer.css('top',self.options.offset.top+'px'); }
         if (self.options.offset.left) { self.eventContainer.css('left',self.options.offset.left+'px'); }
      },
      
      _edit : function() {
      },
      
      _initEvents : function() {
         var self = this;
         self.eventContainer.bind('remove-event', function(){            
            if (self.options.autoremove) {               
               $(this).unbind();
               $(this).remove();
            }
         });
         
         self.eventContainer.bind('move-event', function(){              
         });
         
         self.eventContainer.bind('edit-event', function(){
            self._edit();
         });
         
         self.editHandle.click(function() {
        	   self.eventContainer.trigger('edit-event');
         });
         
         self.deleteHandle.click(function() {
        	   self.eventContainer.trigger('remove-event');
         });
         
         if (self.options.autoedit) {
            self.eventContainer.trigger('edit-event');
         }
      }
   });
	
   /* -------------------------------------------- *
    * CALENDAR WIDGET                              *
    * -------------------------------------------- */ 
	$.widget("calendar.daycalendar", {
		millis_in_day : 86400000,
		
		options : {			
			'timeslotHeight' : 40,
         'timeslotWidth' : 300,
			'timeslotsPerHour' : 1,
			'headerContent' : '&nbsp;',
			'footerContent' : '&nbsp;',
         'contextContent' : '',
         'date' : '2010-01-01T00:00:00+02:00',
         'timeOffsetInMinutes' : 0,
         'timeOffsetHide': false,
         'hourStart': 0,
         'hourEnd': 24,         
			'showRuler' : true,
         'dateFormat' : 'l j F Y',
         'userdata': {}
		},
		
      addEvents : function(eventlist) {
         var self = this;
         $.each(eventlist,function(i,item) {
            self.addEvent(item);
         });
      },
      
      getEvents : function() {
         return $(':calendar-simpleevent', this.element);
      },
      
      addEvent : function(eventitem) {
         var self = this;
         
         if ($(eventitem).is(':calendar-simpleevent')) {
            // Use the calendar event defaults.            
            var options = $(eventitem).simpleevent('option');
            options = $.extend(true, {}, options, self.options.eventoptions);
            options.calendar = self;

            $(eventitem).simpleevent('option', options).appendTo(self.element);
         }          
         else if (eventitem && eventitem.start && eventitem.end && eventitem.title) {
            var options = $.extend(true, {}, self.options.eventoptions, {               
               'calendar': self,                      
               'period': {
                  'start' : eventitem.start,
                  'end'   : eventitem.end                     
               },
               'title' : eventitem.title
            });            
            
            $('<div/>').simpleevent(options).appendTo(self.calContent);            
         }
         
         var options = {reset:true};
         self.refresh(options);
      },
      
		_create : function() {
			var self = this;					
		},
		
		_init : function() {
			var self = this;
									
			self._initRender();
			self._initEvents();
		},
		
      _resizeCalendar : function()
      {
         this.refresh();   
      },
      
      refresh : function(options) 
      {
         var self = this;
         $(':calendar-simpleevent', self.element).each(function(i,item){
            if (options && options.reset) {
               $(item).simpleevent('option','container',null);            
            
               $('td.calendar-slot', self.element).each(function(t,slot){
                  var itemperiod = $(item).simpleevent('option','period');
                  var slotperiod = $(slot).data('period');
                  
                  if (null == $(item).simpleevent('option','container')) {
                     if ((itemperiod.start >= slotperiod.start && itemperiod.start < slotperiod.end)
                         || (slotperiod.start < itemperiod.end && itemperiod.end <= slotperiod.end)) {
                        $(item).simpleevent('option','container',slot);
                        $(item).simpleevent('option','calendar',$(slot).data('calendar'));                     
                     };
                  }
               });
               
               // TODO?
               if (null == $(item).simpleevent('option','container')) {
            	   $(item).css({'display':'none'});
               }
            }
            
            $(item).data('simpleevent').autoFit();
         });            
      },
      
		_initEvents : function() {			
			var self = this;
         
         $(window).bind("resize.calendar", function() {
            self._resizeCalendar();
         });
         
         // Add event on click!!
			$('.calendar-slot', this.element).click( function(event) {
			var self = $(this);
            var calendar = self.data('calendar');                    
                                          
            if ('function' == typeof(self.data('acceptevent')) && self.data('acceptevent')(self)) {
               var options = {
                  calendar : calendar,
                  period : $.extend(true,{},self.data('period')),
                  height: self.height(),
                  width: self.width(),
                  offset: {'top':self.offset().top, 'left':self.offset().left},
                  container: self
               };
               
               if (calendar.options.eventoptions) {                  
                  options = $.extend(true,{},calendar.options.eventoptions, options);
               };
               
               $('<div/>').simpleevent(options).appendTo(calendar.calContent);               
			   };
         });			
		},
		      
		_initRender : function() {
			var self = this;
         
         var date = new Date();  
         date.setISO8601(self.options.date);
         
         var dateFrom = new Date(date.getFullYear(), date.getMonth(), date.getDate());
         if (self.options.timeOffsetInMinutes) {
            dateFrom = new Date(dateFrom.getTime() + (self.millis_in_day / 24 / 60 * self.options.timeOffsetInMinutes ));
         }
         
         var dateTo = new Date(dateFrom.getTime() + (self.millis_in_day / 24 / self.options.timeslotsPerHour));
                  
			$(self.element).addClass('ui-widget');		
			
         // HEADER
			calHeader = (self.calHeader = $('<div/>'))
				.appendTo(self.element)
				.append(self.options.headerContent)
				.addClass('ui-widget-header ui-corner-all');
			
         // CONTEXT         
         self.options.contextContent = $.daycalendar.formatDate(dateFrom, self.options.dateFormat);         
         calContext = (self.calContext = $('<div/>'))
            .appendTo(self.element)
            .append(self.options.contextContent)
            .addClass('calendar-contextheader');
         
         // CONTENT
			calContent = (self.calContent = $('<div/>'))
				.appendTo(self.element)
				.addClass('ui-widget-content ui-corner-all calendar-slot-container')
			   .append(self.calContentTable = 
               $('<table celpadding="0" cellspacing="0"/>')
               .addClass('calendar-eventtable')
               );
         
         // FOOTER
			calFooter = (self.calFooter = $('<div/>'))
				.appendTo(self.element)
				.append(self.options.footerContent)
				.addClass('ui-widget-header ui-corner-all ui-widget-footer');

         var bodyHeight = self.options.timeslotsPerHour * 24 * self.options.timeslotHeight;
         
         if (self.options.timeOffsetInMinutes && !self.options.timeOffsetHide) {
            var calcHeight = self.options.timeOffsetInMinutes / (60 / self.options.timeslotsPerHour);
            var row = $('<tr/>')
               .append( 
                  $('<td/>')
                     .attr({'colspan':'2'})
                     .css({
                        'height':(self.options.timeslotHeight * calcHeight) + 'px',
                        'background-color' : 'gray',
                        'background-image' : "url('images/13.gif')"                        
                     })
               )
               .appendTo(self.calContentTable);            
         }
               
         for (var i = 0; i < self.options.timeslotsPerHour * 24; i++) {
            if (dateFrom.getHours() >= self.options.hourStart && 
                  dateFrom.getHours() <= self.options.hourEnd) {            
               var row = $('<tr/>')
                  .appendTo(self.calContentTable);
                                          
               var formatted = $.daycalendar.formatDate(dateFrom,"h:i a");
               
               if (self.options.showRuler && 0 == i%self.options.timeslotsPerHour) {
                  var rowspancount = self.options.timeslotsPerHour > 0 ? self.options.timeslotsPerHour : 1;
                  
                  var timecolumn = $('<td/>')
                  .attr({'rowspan':rowspancount,'valign':'top'})
                  .html(formatted)
                  .addClass('calendar-hour')               
                  .appendTo(row);
               }
               
               var formatted = '&nbsp;';
               var column = $('<td/>').html(formatted)
                  .addClass('calendar-slot')
                  .css({
                        'width':self.options.timeslotWidth + 'px',
                        'height':self.options.timeslotHeight + 'px'
                     })
                  .data({
                     'calendar': self, 
                     'period': {'start': dateFrom, 'end': dateTo},
                     'events': new Array(),                     
                     'acceptevent': function(context, drag) {
                           var self = $(context);
                           var hasEvent = false;
                           
                           var slotstart =  self.data('period').start;
                           var slotend = self.data('period').end;                     
                           
                           $(':calendar-simpleevent', self.data('calendar').element).each(function(i,e){
                              if (period = $(e).simpleevent('option').period) {                           
                                 var eventstart = period.start;
                                 var eventend = period.end;                     
                                 
                                 if (eventstart >= slotstart && eventstart < slotend) {
                                    hasEvent = true;                                                                  
                                 }
                              }
                           });
                                                
                           return !hasEvent;
                        }
                     })
                  .droppable({
                     'tolerance': 'pointer',
                     'hoverClass': 'ui-state-active',
                     accept: function(drag){
                   	  	var self = $(this);                	  
                   	  	if (self.data('acceptevent') && 'function' == typeof(self.data('acceptevent'))) {
                   	  		return self.data('acceptevent')(this, drag);                	  		
                   	  	} else {
                   	  		// BUG: ghost columns?
                   	  		return false;
                   	  	}                                            
                     },
                     drop: function(event, ui) {
                        var self = $(this);
                        ui.draggable.appendTo(self.data('calendar').element);                        
                        
                        if (ui.draggable.is(':calendar-simpleevent')) {
                           var options = ui.draggable.simpleevent('option');                        
                           
                           // Current duration.
                           var duration = ui.draggable.simpleevent('duration');
                           
                           // Set the start of the event to the start of the slot.
                           options.period.start = self.data('period').start;
                           
                           // Set the end to the start and add the old duration to it.
                           options.period.end = new Date(self.data('period').start.getTime() + duration);
                           
                           options.width = self.width();
                           options.height = self.height();
                           options.offset.top = self.offset().top;
                           options.offset.left = self.offset().left;
                           options.calendar = self.data('calendar');
                           options.container = self;
                           ui.draggable.simpleevent('option',options);
                           ui.draggable.simpleevent('refresh');
                           $(ui.draggable).trigger('move-event');
                        };
                     }
                  })               
                  .appendTo(row);
               
               if (dateFrom.getHours()%2 != 0) {
                  column.css({"background-color":"#F0F0F0"});
               }
            }
            
            dateFrom = new Date(dateTo.getTime());
            dateTo = new Date(dateFrom.getTime() + (self.millis_in_day / 24 / self.options.timeslotsPerHour)); 
         }                           
		}     		
	});
   
   $.simpleevent = {
      options : {}     
   };
   
   /*
    * date formatting is adapted from
    * http://jacwright.com/projects/javascript/date_format
    */    
   $.daycalendar = {
         formatDate : function(date, format) {
         var options = {
            shortDays : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
            longDays : ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
            shortMonths : ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
            longMonths : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']                         
         };
         var returnStr = ''; 
         var replaceChars = {
               // Day
               d: function(date) { return (date.getDate() < 10 ? '0' : '') + date.getDate(); },
               D: function(date, options) { return options.shortDays[date.getDay()]; },
               j: function(date) { return date.getDate(); },
               l: function(date, options) { return options.longDays[date.getDay()]; },
               N: function(date) { return date.getDay() + 1; },
               S: function(date) { return (date.getDate() % 10 == 1 && date.getDate() != 11 ? 'st' : (date.getDate() % 10 == 2 && date.getDate() != 12 ? 'nd' : (date.getDate() % 10 == 3 && date.getDate() != 13 ? 'rd' : 'th'))); },
               w: function(date) { return date.getDay(); },
               z: function(date) { return "Not Yet Supported"; },
               // Week
               W: function(date) { return "Not Yet Supported"; },
               // Month
               F: function(date, options) { return options.longMonths[date.getMonth()]; },
               m: function(date) { return (date.getMonth() < 9 ? '0' : '') + (date.getMonth() + 1); },
               M: function(date, options) { return options.shortMonths[date.getMonth()]; },
               n: function(date) { return date.getMonth() + 1; },
               t: function(date) { return "Not Yet Supported"; },
               // Year
               L: function(date) { return "Not Yet Supported"; },
               o: function(date) { return "Not Supported"; },
               Y: function(date) { return date.getFullYear(); },
               y: function(date) { return ('' + date.getFullYear()).substr(2); },
               // Time
               a: function(date) { return date.getHours() < 12 ? 'am' : 'pm'; },
               A: function(date) { return date.getHours() < 12 ? 'AM' : 'PM'; },
               B: function(date) {
                  return "Not Yet Supported";
               },
               g: function(date) { return date.getHours() % 12 || 12; },
               G: function(date) { return date.getHours(); },
               h: function(date) { return ((date.getHours() % 12 || 12) < 10 ? '0' : '') + (date.getHours() % 12 || 12); },
               H: function(date) { return (date.getHours() < 10 ? '0' : '') + date.getHours(); },
               i: function(date) { return (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); },
               s: function(date) { return (date.getSeconds() < 10 ? '0' : '') + date.getSeconds(); },
               // Timezone
               e: function(date) { return "Not Yet Supported"; },
               I: function(date) { return "Not Supported"; },
               O: function(date) { return (date.getTimezoneOffset() < 0 ? '-' : '+') + (date.getTimezoneOffset() / 60 < 10 ? '0' : '') + (date.getTimezoneOffset() / 60) + '00'; },
               T: function(date) { return "Not Yet Supported"; },
               Z: function(date) { return date.getTimezoneOffset() * 60; },
               // Full Date/Time
               c: function(date) { return "Not Yet Supported"; },
               r: function(date) { return date.toString(); },
               U: function(date) { return date.getTime() / 1000; }
            };
            
         for (var i = 0; i < format.length; i++) {
            var curChar = format.charAt(i);
            if ($.isFunction(replaceChars[curChar])) {
              var res = replaceChars[curChar](date, options);
   
              if (res === '00' && options.alwaysDisplayTimeMinutes === false) {
                //remove previous character
                returnStr = returnStr.slice(0, -1);
              } else {
                 
                  returnStr += res;
              }
            } else {
               returnStr += curChar;
            }
         }
   
         return returnStr;
      }
   };         
})(jQuery);

Date.prototype.setISO8601 = function (string) {   
   var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
     "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\\.([0-9]+))?)?" +
     "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
   var d = string.match(new RegExp(regexp));
   
   var offset = 0;
   var date = new Date(d[1], 0, 1);
   
   if (d[3]) { date.setMonth(d[3] - 1); }
   if (d[5]) { date.setDate(d[5]); }
   if (d[7]) { date.setHours(d[7]); }
   if (d[8]) { date.setMinutes(d[8]); }
   if (d[10]) { date.setSeconds(d[10]); }
   if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
   if (d[14]) {
     offset = (Number(d[16]) * 60) + Number(d[17]);
     offset *= ((d[15] == '-') ? 1 : -1);
   }   
   offset -= date.getTimezoneOffset();
   time = (Number(date) + (offset * 60 * 1000));
   this.setTime(Number(time));
};

Date.prototype.toISO8601String = function (format, offset) {
   /* accepted values for the format [1-6]:
   1 Year:
    YYYY (eg 1997)
   2 Year and month:
    YYYY-MM (eg 1997-07)
   3 Complete date:
    YYYY-MM-DD (eg 1997-07-16)
   4 Complete date plus hours and minutes:
    YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
   5 Complete date plus hours, minutes and seconds:
    YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
   6 Complete date plus hours, minutes, seconds and a decimal
    fraction of a second
    YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
   */
   if (!format) { var format = 6; }
   if (!offset) {
     var offset = 'Z';
     var date = this;
   } else {
     var d = offset.match(/([-+])([0-9]{2}):([0-9]{2})/);
     var offsetnum = (Number(d[2]) * 60) + Number(d[3]);
     offsetnum *= ((d[1] == '-') ? -1 : 1);
     var date = new Date(Number(Number(this) + (offsetnum * 60000)));
   }
   var zeropad = function (num) { return ((num < 10) ? '0' : '') + num; };
   
   var str = "";
   str += date.getUTCFullYear();
   if (format > 1) { str += "-" + zeropad(date.getUTCMonth() + 1); }
   if (format > 2) { str += "-" + zeropad(date.getUTCDate()); }
   if (format > 3) {
     str += "T" + zeropad(date.getUTCHours()) +
            ":" + zeropad(date.getUTCMinutes());
   }
   if (format > 5) {
     var secs = Number(date.getUTCSeconds() + "." +
                ((date.getUTCMilliseconds() < 100) ? '0' : '') +
                zeropad(date.getUTCMilliseconds()));
     str += ":" + zeropad(secs);
   } else if (format > 4) { str += ":" + zeropad(date.getUTCSeconds()); }
   
   if (format > 3) { str += offset; }
   return str;
};

