/*
 * Copyright (C) by Netcetera AG.
 * All rights reserved.
 *
 * The copyright to the computer program(s) herein is the property of
 * Netcetera AG, Switzerland.  The program(s) may be used and/or copied
 * only with the written permission of Netcetera AG or in accordance
 * with the terms and conditions stipulated in the agreement/contract
 * under which the program(s) have been supplied.
 *
 */

ONE_MINUTE = 60000;
ONE_HOUR = 60 * ONE_MINUTE;
ONE_DAY = 24 * ONE_HOUR;

// add methods to the Date class for handling ISO
$.extend(Date.prototype, {
  /**
   * converts the date object into a iso 8061 string
   * 
   * @param withTime (Boolean) if true, the time portion will be apended,
   *   default is true.
  */
  toISOString: function(withTime) {
    withTime = (typeof withTime == "undefined") ? true : withTime;
    
    if (withTime) {
      return sprintf("%04d%02d%02dT%02d%02d",
               this.getFullYear(), this.getMonth() + 1, this.getDate(),
               this.getHours(), this.getMinutes());
    } else {
      return sprintf("%04d%02d%02d", this.getFullYear(), this.getMonth() + 1, this.getDate());
    }
  },
  
  /** 
   * Sets the time to the 3am the next day. Returns this.
   */
  setTo3amNextDay: function() {
    this.setToNextMidnight();
    this.setTime(this.getTime() + (3 * ONE_HOUR));
    
    return this;
  },
  
  /** 
   * Sets the time to the begining of the next day. Returns this.
   */
  setToNextMidnight: function() {
    this.setToMidnight();
    this.setTime(this.getTime() + ONE_DAY);
    
    return this;
  },
  
  /** 
   * Sets the time to the begining of the day. Returns this.
   */
  setToMidnight: function() {
    this.setHours(0);
    this.setToHourStart();
    
    return this;
  },
  
  setToHourStart: function() {
    this.setMinutes(0);
    this.setToMinuteStart();
    
    return this;
  },
  
  /** 
   * Sets the time to the begining of the minute. Returns this.
   */
  setToMinuteStart: function() {
    this.setSeconds(0);
    this.setMilliseconds(0);
    
    return this;
  },
  
  setToNextMinute: function() {
    this.setToMinuteStart();
    this.setTime(this.getTime() + 60000);
    
    return this;
  },
  
  clone: function() {
    return new Date(this.getTime());
  },
  
  minus: function(other) {
    return this.getTime() - other.getTime();
  },
  
  plus: function(other) {
    return this.getTime() + other.getTime();
  },
  
  equals: function(otherDate) {
    return this.getTime() == otherDate.getTime();
  },
  
  getMonthString: function() {
    switch(this.getMonth()) {
      case 0: return "Jan";
      case 1: return "Feb";
      case 2: return "Mar";
      case 3: return "Apr";
      case 4: return "May";
      case 5: return "Jun";
      case 6: return "Jul";
      case 7: return "Aug";
      case 8: return "Sep";
      case 9: return "Oct";
      case 10: return "Nov";
      case 11: return "Dec";
    }
  },

  getWeekDayString: function() {
    switch(this.getDay()) {
      case 1: return "Montag";
      case 2: return "Dienstag";
      case 3: return "Mittwoch";
      case 4: return "Donnerstag";
      case 5: return "Freitag";
      case 6: return "Samstag";
      case 0: return "Sonntag";
    }
  }
});

// add a parse method to 
$.extend(Date, {
  /**
   * Parses a iso 8061 condensed string
   */
  parseISO: function(dateString) {
    var regex = /^(\d{4})(\d{2})(\d{2})(?:T(\d{2})(\d{2})(\d{2})?)?$/
    
    dateString  = dateString || "";
    
    var r;
    if (r = dateString.match(regex)) {
      var y, m, d, hh, mm, ss;
      y = r[1];
      m = r[2];
      d = r[3];
      if (r[4] && r[5]) {
        hh = r[4];
        mm = r[5];
        if (r[6]) {
          ss = r[6];
        } else {
          ss = 0;
        }
        return new Date(y, m - 1, d, hh, mm, ss, 0);
      } 
      return new Date(y, m - 1, d);
      
      
    } 
    
    return null;
  }
});

/**
 * Global object that contains time related functions 
 */
DateTime = {
    
  REL_TRAMDROID_TIME_API_ROOT: "http://netcetera.biz/tramdroid/restapi/time",
  
  // the offset between the system's clock time and the actual time
  _offset: 0,
  
  // initialize from the configuration
  initialize: function(config, systemClockTime, callback) {
    if (config != null) {
      if (config.opts.ctime) {
        var ctime = config.opts.ctime;
        this._offset = ctime.getTime() - systemClockTime.getTime();
        callback();
      } else {
        var s = this;
        $.ajax({
          type: "GET",
          url: wemlinFrontendContext + $("html>head>link[rel='" + s.REL_TRAMDROID_TIME_API_ROOT + "']").attr('href'),
          dataType: "json",
          cache: false,
          
          success: function(data) {
            // calculate offset between ctime and systemClockTime 
            if (data.iso8601_time) {
              var ctime = config.opts.ctime || Date.parseISO(data.iso8601_time) || systemClockTime;
            } else {
              var ctime = config.opts.ctime || systemClockTime;
            }
            
            s._offset = ctime.getTime() - systemClockTime.getTime();
            callback();
          },
          
          error: function() {
            var ctime = config.opts.ctime || systemClockTime;
            s._offset = ctime.getTime() - systemClockTime.getTime();
            callback();
          }
        });
      }
    } else {
      callback();
    }
    return this;
  },
  
  // returns the current time
  now: function() {
    return new Date((new Date()).getTime() + this._offset);
  }
  
};
