/**
 * DateTime class designed to ease (obviously) date and time operations. Interface is almost a 1:1 copy from PHP DateTime class.
 * Created by £ukasz Dro¿d¿, Faculty of Physics, Warsaw University of Technology
 * In case of any suggestions/questions please contact me at: lucas.drozdz@gmail.com
 * Released under LGPL license - as long as You keep this authoring comment, feel free to modify/distribute this class as your need.
 * Version 0.8, 2007-09-27
 **/
 
if(!window.__rageLib){
  window.__rageLib = {};
  window.__rageLib.instances = {};
}

__rageLib.DateTime = function(d,lang){
  this.setDate(d);
  this.lang = (lang ? lang : __rageLib.DateTime.prototype.defaultLang);
}

__rageLib.DateTime.prototype = {
  defaultLang: null,
  autoLoadModules: true, 
  langData: [], //to be loaded
  
  setDate: function(v){
    this.date = new Date();
    if(!v) return false;
    if(v instanceof Date){
      this.date.setTime(Date.parse(v.toString()));
	  }else{
	     try{
		     this.date.setTime(Date.parse(v));
		   }catch(e){}
	  }
  },
  toString: function(){ return this.date.toString(); },
  getDate: function(){ return this.date; },
  getDayLabel: function(shortFlag){
    var day = this.getISOWeekDay();
    if(shortFlag){
	    return this.langData[this.lang].dayLabelsShort[day];
	  }else{
	    return this.langData[this.lang].dayLabels[day];
	  }
  },
  setLang: function(lang){
    this.lang = lang;
  },
  getMonthLabel: function(shortFlag){
    var month = this.getMonth();
    if(shortFlag){
      return this.langData[this.lang].monthLabelsShort[month];
    }else{
      return this.langData[this.lang].monthLabels[month];
    }
  },
  modify: function(str){
    var mod = str.split(' ');
	  var actNum = null;
	  var actStr = null;
	  var add = null;
	  var num = null;
	  for(var i =0; i<mod.length/2; i++){
	    actNum = mod[i*2];
	    actStr = mod[i*2 + 1];
	    if(actNum.charAt(0) == '+' || actNum.charAt(0) == '-'){
	      num = new Number(actNum);
		    switch(actStr){
		      case 'day':
  			  case 'days':
  			    this.date.setDate(this.date.getDate() + num);
  			    break;
          case 'week':
  			  case 'weeks':
  			    this.date.setDate(this.date.getDate() + 7*num);
  			    break;
  			  case 'month':
  			  case 'months':
  			    this.date.setMonth(this.date.getMonth() + num);
  			    break;
  			  case 'year':
  			  case 'years':
  			    this.date.setFullYear(this.date.getFullYear() + num);
  			    break;
          case 'minute':
          case 'minutes':
            this.date.setMinutes(this.date.getMinutes() + num);
            break;
          case 'hour':
          case 'hours':
            this.date.setHours(this.date.getHours() + num);
            break;
          case 'second':
          case 'seconds':
            this.date.setSeconds(this.date.getSeconds() + num);
            break;
          case 'millisecond':
          case 'milliseconds':
            this.date.setMilliseconds(this.date.getMilliseconds() + num);
            break;
        }
      }
    }
  },
  getWeekDay: function(){ return this.date.getDay(); },
  getISOWeekDay: function(){ return ((this.getWeekDay() + 6)%7)+1;  },
   
  setDay: function(v){ this.date.setDate(v); },
  getDay: function(){ return this.date.getDate(); },
   
  setMonth: function(v){ this.date.setMonth(v-1); },
  getMonth: function(){ return this.date.getMonth()+1; },
   
  setYear: function(v){ this.date.setFullYear(v); },
  getYear: function(){ return this.date.getFullYear(); },
   
  setHours: function(v){ this.date.setHours(v); },
  getHours: function(){ return this.date.getHours(); },
   
  setMinutes: function(v){ this.date.setMinutes(v); },
  getMinutes: function(){ return this.date.getMinutes(); },
   
  setSeconds: function(v){ this.date.setSeconds(v); },
  getSeconds: function(){ return this.date.getSeconds(); },
   
  setMilliseconds: function(v){ this.date.setMilliseconds(v); },
  getMilliseconds: function(){ return this.date.getMilliseconds(); },
  
  getMonthDays: function(){
    var tempDate = new __rageLib.DateTime(this.getDate().toString());
    tempDate.modify('+1 month');
    tempDate.setDay(1);
    tempDate.modify('-1 day');
    return tempDate.getDay();
  },
  getSwatchTime: function(){
    var totalSec = 24*3600;
    var actSec = this.getHour()*3600 + this.getMinutes()*60 + this.getSeconds();
    return Math.floor((actSec / totalSec)* 1000);
  },
  getMeridiem: function(flag){
    if(flag) return this.getHour() >= 12 ? 'PM' : 'AM';
    else     return this.getHour() >= 12 ? 'pm' : 'am';
  },
  getDayOfTheYear: function(){
    var tempDate = new __rageLib.DateTime(this.getDate().toString());
    var actMonth = tempDate.getMonth();
    var daySum = 0;
    for(var i=1; i<actMonth; i++){
      tempDate.setMonth(i);
      daySum += tempDate.getMonthDays();
    }
    daySum += this.getDay();
    return daySum;
  },
  isLeapYear: function(){
    var year = this.getYear();
    if(year % 400 == 0) return true;
    else if(year % 100 == 0) return false
    else if(year % 4 == 0) return true
    else return false;
  },
  getWeekNumber: function(){ //US Standard
    var tempDate = new __rageLib.DateTime(this.getDate().toString());
    var actDay = tempDate.getDayOfTheYear();
    tempDate.setDay(1);
    tempDate.setMonth(1);
    tempDate.modify('+'+((8-tempDate.getISOWeekDay())%7)+' days');  //goto next monday

    var week = Math.floor((actDay - tempDate.getDayOfTheYear())/7) + 1;
    if(week > 0) return week;
    else{
      tempDate = new __rageLib.DateTime(this.getDate().toString());
      tempDate.modify('-'+(tempDate.getISOWeekDay() - 1)+' days'); //goto start of the week (in the past year)
      return tempDate.getWeekNumber();
    }
  },
  getISOYear: function(){
    var tempDate = new __rageLib.DateTime(this.getDate().toString());
    var actDay = tempDate.getDayOfTheYear();
    tempDate.setDay(1);
    tempDate.setMonth(1);
    tempDate.modify('+'+((8-tempDate.getISOWeekDay())%7)+' days');  //goto next monday
   
    var week = Math.floor((actDay - tempDate.getDayOfTheYear())/7) + 1;
    if(week > 0) return this.getYear();
    else return this.getYear() - 1;
  },
  getSuffix: function(){
    var temp = this.getDay();
    if(temp < 10 || temp > 20){
      if(temp == 0) return '';
      temp = temp % 10;
      switch(temp){
        case 1: return 'st'; break;
        case 2: return 'nd'; break;
        case 3: return 'rd'; break;
        default: return 'th'; break;
      }
    }else if(temp >= 10 || temp <= 20){
      return 'th';
    }
  },
  format: function(str){
    var l = str.length;
    var actChar = null;
    var retStr = '';
    var temp;
    for(var i=0; i<l; i++){
      actChar = str.charAt(i);
      if(actChar == "\\" || actChar == "~"){
        if(i<l-1) retStr += str.charAt(i+1);
        else retStr += actChar;
        i++;
      }else{
        switch(actChar){
          /* days */
          case 'd':
            temp = this.getDay();
            retStr += temp > 9 ? temp : '0'+temp;     break;
          case 'D':
            retStr += this.getDayLabel(true);          break;   
          case 'j':
            retStr += this.getDay();         break;
          case 'l':
            retStr += this.getDayLabel(false);          break;
          case 'N':
            retStr += this.getISOWeekDay();         break;
          case 'S':
            retStr += this.getSuffix();         break;
          case 'w':
            retStr += this.getWeekDay();         break;
          case 'z':
            retStr += this.getDayOfTheYear();         break;   
          
          /* week */
          case 'W':
            retStr += this.getWeekNumber();         break;
              
          /* months */
          case 'F':
            retStr += this.getMonthLabel(false);         break;
          case 'm':
            temp = this.getMonth();
            retStr += temp > 9 ? temp : '0'+temp;         break;
          case 'M':
            retStr += this.getMonthLabel(true);         break;
          case 'n':
            retStr += this.getMonth();         break;
          case 't':
            retStr += this.getMonthDays();         break;   
          
          /* years */
          case 'L':
            retStr += this.isLeapYear() ? 1 : 0;       break;
          case 'o':
            retStr += this.getISOYear();         break;
          case 'Y':
            retStr += this.date.getFullYear();         break;
          case 'y':
            retStr += this.date.getYear();         break;
          
          
          /* time */
          case 'a':
            retStr += this.getMeridiem(false);         break;
          case 'A':
            retStr += this.getMeridiem(true);         break;
          case 'B':
            retStr += this.getSwatchTime();         break;
          case 'g':
            retStr += ((this.getHours()+11)%12)+1;         break;
          case 'G':
            retStr += this.getHours();         break;
          case 'h':
            temp = ((this.getHours()+11)%12)+1;
            retStr += temp > 9 ? temp : '0'+temp;         break;
          case 'H':
            temp = this.getHours();
            retStr += temp > 9 ? temp : '0'+temp;         break;
          case 'i':
            temp = this.getMinutes();
            retStr += temp > 9 ? temp : '0'+temp;         break;
          case 's':
            temp = this.getSeconds();
            retStr += temp > 9 ? temp : '0'+temp;         break;
          case 'u':
            retStr += this.getMilliseconds();         break;
          
          /* Full Date/Time */
          case 'U':
            retStr += Math.floor(this.date.getTime()/1000);      break;
           
          /* default */   
          default:
            retStr += actChar;
        }
      }
    }
    return retStr;
  },
}

/*if(!__rageLib.initData.defaultLang['DateTime']){
  __rageLib.initData.defaultLang['DateTime'] = __rageLib.defaultLang;
  __rageLib.DateTime.prototype.defaultLang = __rageLib.defaultLang;
  if(__rageLib.DateTime.prototype.autoLoadModules)
    __rageLib.manipulator.addRageLibScript('js/lang/DateTime.class/'+__rageLib.defaultLang+'.js');
}else{
  if(!__rageLib.initData.classesLoaded['DateTime']){
    //load another default language 
    __rageLib.DateTime.prototype.defaultLang = __rageLib.initData.defaultLang['DateTime'];
    if(__rageLib.DateTime.prototype.autoLoadModules)
      __rageLib.manipulator.addRageLibScript('js/lang/DateTime.class/'+__rageLib.initData.defaultLang['DateTime']+'.js');
  }
}*/

