/**
 * Sascha Hühdepohl und Andreas Wittek
 * 
 * benötigt
 * - validate.js
 * - lib.js (d.h. eigentlich nur Date.prototype.isBefore, bindOn
 */

var Messages = {
  MSG_DAYOVERFLOW : "Given month has only %s days! Please correct your dates!",
  MSG_UNPARSEABLE : "Sorry, but i can't interpret your input!",

  MSG_WARN_EMPTY  : "The input %s must not be empty",

  EMSG_DAY1       : "Please use one or two digits for day",                                                                                                                                                     
  EMSG_DAY2       : "Date must be from 1 to 31!",
  EMSG_YEAR1      : "Please use 4 digits for year!",
  EMSG_MONTH1     : "Please use one or two digits for month!",
  EMSG_MONTH2     : "Month must be from 1 to 12",
  EMSG_COMBI_JMD  : "Given month has only %s days!",
  EMSG_PLEASE_CR  : "Please correct your dates!",
  ETFORMAT        : "Please give time as HH:MM!",
  EDFORMAT        : "Please give date as %s or DDMMYY",
  EMSG_HOURS      : "Please use hours between 0 and 23.",
  EMSG_MINUTES    : "Please use minutes between 0 and 59.",
  EMSG_SECONDS    : "Please use seconds between 0 and 59.",
  EMSG_MINBOOK    : "Your times do not match or are below the minimal reservation time of %s minutes.",
  EMSG_BOOKBEGIN  : "Your reservation period starts too far in the past.",
  EMSG_WAGEN      : "Please select a car class!",
  EMSG_STATION    : "Please select a location!",
  EMSG_24_zu_00   : "We change the hour of departure / arrival to 0:00 a.m. next day.",

  MONTHNAMES      : new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'),
  DAYNAMES        : new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat'),

  setMessage : function(id, message) {
    if (this[id]) {
      this[id] = message;
    } else {
      var error = "invalid message id '" + id + "'";
      throw error;
    }
  }
};

var MessagesGerman = {
  MSG_DAYOVERFLOW : "Der Monat hat nur %s Tage! Bitte pruefen Sie Ihre Eingabe.",
  MSG_UNPARSEABLE : "Ich kann Ihre Eingabe nicht auswerten.",

  MSG_WARN_EMPTY  : "Das Eingabefeld %s darf nicht leer sein",

  EMSG_DAY1      : "Bitte geben Sie den Tag als ein- oder zweistellige Zahl an!",
  EMSG_DAY2      : "Der Tag muss zwischen 1 und 31 liegen!",
  EMSG_YEAR1     : "Bitte geben Sie das Jahr 4-stellig an!",
  EMSG_MONTH1    : "Bitte geben Sie den Monat als ein- oder zweistellige Zahl an!",
  EMSG_MONTH2    : "Der Monat liegt nicht zwischen 1 und 12!",
  EMSG_COMBI_JMD : "Der von Ihnen angegebene Monat hat nur %s Tage!",
  EMSG_PLEASE_CR : "Bitte korrigieren Sie die Reisedaten!",
  ETFORMAT       : "Bitte die Zeit in der Form: SS:MM",
  EDFORMAT       : "Bitte das Datum in der Form: %s oder TTMMJJ eingeben!",
  EMSG_HOURS     : "Bitte geben Sie die Stunde zwischen 0 und 23 Uhr an.",
  EMSG_MINUTES   : "Bitte geben Sie die Minuten zwischen 0 und 59 an.",
  EMSG_SECONDS   : "Bitte geben Sie die Sekunden zwischen 0 und 59 an.",
  EMSG_MINBOOK   : "Ihre Buchungszeiten passen nicht zusammen oder unterschreiten die Mindestbuchungsdauer von %s Minuten.",
  EMSG_BOOKBEGIN : "Ihr Buchungsbeginn liegt unnoetig weit in der Vergangenheit.",
  EMSG_WAGEN     : "Bitte waehlen Sie eine Wagenklasse!",
  EMSG_STATION   : "Bitte waehlen Sie eine Station!",
  EMSG_24_zu_00  : "Wir aendern den Buchungsanfang/das Buchungsende auf 0:00 am folgenden Tag.",

  MONTHNAMES     : new Array('Januar', 'Februar', 'Maerz', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember', 'Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'),
  DAYNAMES       : new Array('Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Son', 'Mon', 'Die', 'Mit', 'Don', 'Fre', 'Sam')
};

MessagesGerman.prototype = Messages;



function DateInput(id, initialDate, surpresshandler) {
  this.JUMP_DAY = 1;
  this.JUMP_MONTH = 2;
  this.JUMP_YEAR = 3;
  this.JUMP_MONTH_YEAR = 4;

  this.messages = Messages;

  if (initialDate) {
    var day = parseInt(initialDate.substr(0, 2), 10);
    var month = parseInt(initialDate.substr(3, 2), 10);
    var year = parseInt(initialDate.substr(6, 4), 10);
	
	this.setDateOnly(year,month,day);
/*    
    this.date.setDate(day);
    this.date.setMonth(month - 1);
    this.date.setFullYear(year);
*/    
  }
  else  {
  	this.date = new Date();
	this.setDateOnly(this.date.getFullYear(),this.date.getMonth()+1,this.date.getDate());  	
  }


  if( (typeof id) == 'string') {
	  this.input = document.getElementById(id);
  }
  else {
  	this.input = id;
  }
  
  this.refDate = new Date(this.date.getTime());
  this.formatString = 'dd.MM.yyyy';
  this.maxDaysPast = -1;
  this.forceNextFirst = false;
  this.silentCorrect = false;
  this.jumpFuture = this.JUMP_MONTH_YEAR;
  this.userEntered = 0;
  
  if(!surpresshandler) {
	  if (this.input.addEventListener) {
	    this.input.addEventListener('blur', this.blurHandler.bindOn(this), false);
	    this.input.addEventListener('keypress', this.keypressHandler.bindOn(this), false);
	    this.input.addEventListener('keyup', this.keyupHandler.bindOn(this), false);
	    this.input.form.addEventListener('submit', this.blurHandler.bindOn(this), false);
	  } else {
	    this.input.attachEvent('onblur', this.blurHandler.bindOn(this));
	    this.input.attachEvent('onkeypress', this.keypressHandler.bindOn(this));
	    this.input.attachEvent('onkeyup', this.keyupHandler.bindOn(this), false);
	    this.input.form.attachEvent('onsubmit', this.blurHandler.bindOn(this));
	  }
	  
  }
  // initialisieren, d.h. auslesen des inputs
  if (this.input.value != "") {
    this.blurHandler();
  }
  this.changeCallbackObj = null;
  this.changeCallback = null;
  this.allowEmpty = false;
  this.completeEmpty = true;
  this.warnIfEmpty = true;
}

DateInput.prototype.setClone = function(targetID, formatString) {
  this.cloneTarget = document.getElementById(targetID);
  if (!this.cloneTarget) {
    throw new Error("No Element with id '" + targetID + "'");
  }
  if (this.cloneTarget.hasChildNodes) {
    if (this.cloneTarget.firstChild) {
      if (this.cloneTarget.firstChild.nodeType != 3) {
        this.cloneTarget.insertBefore(document.createTextNode(""), this.cloneTarget.firstChild);
      }
    } else {
      this.cloneTarget.appendChild(document.createTextNode(""));
    }
  } else {
    this.cloneTarget.appendChild(document.createTextNode(""));
  }
  this.cloneTarget = this.cloneTarget.firstChild;
  this.cloneFormatString = formatString;
};

DateInput.prototype.setWarnIfEmpty = function(warn) {
  if (warn != null) {
    this.warnIfEmpty = warn;
  } else {
    this.warnIfEmpty = true;
  }
  return this;
};

DateInput.prototype.setMessages = function(messageObj) {
  this.messages = messageObj;
  return this;
};

DateInput.prototype.setAllowEmpty = function(allowEmpty) {
  if (allowEmpty != null) {
    this.allowEmpty = allowEmpty;
  } else {
    this.allowEmpty = true;
  }
  return this;
};

DateInput.prototype.setCompleteEmpty = function(completeEmpty) {
  if (completeEmpty != null) {
    this.completeEmpty = completeEmpty;
  } else {
    this.completeEmpty = true;
  }
  return this;
};

DateInput.prototype.setChangeCallback = function(cb, obj) {
  this.changeCallbackObj = obj;
  this.changeCallback = cb;
  return this;
};

DateInput.prototype.setSilentCorrection = function(s) {
  if (s != null) {
    this.silentCorrect = s;
  } else {
    this.silentCorrect = true;
  }
  return this;
};


DateInput.prototype.setFormat = function(formatString) {
  this.formatString = formatString;
  if (this.input.value != "") {
    this.input.value = this.format();
  }
  return this;
};

DateInput.prototype.keypressHandler = function(event) {
  var code = event.keyCode;
  switch (code) {
    case 13:
      this.blurHandler(event);
      break;
  }
};

DateInput.prototype.keyupHandler = function(event) {
	  var code = event.keyCode;
	  validate_on_input_date(this.input);
};

DateInput.prototype.getDate = function() {
  return this.input.value == "" ? null : new Date(this.date);
};

DateInput.prototype.getDateAsString = function() {
  return this.input.value == "" ? null : this.format();
};

DateInput.prototype.blurHandler = function(event) {
  if (event && event.type && event.type == 'submit') {
    if (this.input.value == '' && this.warnIfEmpty && !this.allowEmpty) {
      event.preventDefault ? event.preventDefault() : event.returnValue = false;
      if (this.input.labels && this.input.labels.length == 1) {
        window.alert(this.messages.MSG_WARN_EMPTY.replace(/%s/, " '" + this.input.labels[0].text + "'"));
      } else {
        window.alert(this.messages.MSG_WARN_EMPTY.replace(/%s/, ""));
      }
      // this.input.focus();
      // this.input.select();
      return;
    }
  }
  if (this.input.value == "" && this.allowEmpty) {
    return;
  }
  if (this.input.value == "" && !this.completeEmpty) {
    return;
  }
  try {
    this.parse();
    this.input.value = this.format();
  } catch (e) {
    var exceptionPattern = /^\[ERR(\d+)\] - (.*)$/;
    var match = exceptionPattern.exec(e);
    if (match) {
      var code = parseInt(match[1], 10);
      var message = match[2];
      switch (code) {
        case 100:
        case 101:
        case 102:
        case 103:
        case 105:
          window.alert(message);
          // event.preventDefault ? event.preventDefault() : event.returnValue = false;
          // this.input.focus();
          // this.input.select();
          break;
        default:
          throw e;
      }
    } else {
      throw e;
    }
  }
  if (this.changeCallback) {
    this.changeCallback.call(this.changeCallbackObj);
  }
  if (this.cloneTarget) {
    this.cloneTarget.nodeValue = this.format(this.cloneFormatString);
  }
};

DateInput.prototype.daysOfMonth = function(year, month) {
  var leapYear = false;
  var days;
  if (year % 4 == 0) { leapYear = true; }
  if (year % 100 == 0 && year % 400 != 0) { leapYear = false; }
  if (month == 2) {
    days = leapYear ? 29 : 28;
  } else {
    if (month < 7) {
      days = (month % 2 == 1) ? 31 : 30;
    } else {
      if (month == 7) {
        days = 31;
      } else {
        days = (month % 2 == 1) ? 30 : 31;
      }
    }
  }
  return days;
};

DateInput.prototype.setMaxDaysInPast = function(days) {
  this.maxDaysPast = days;
  return this;
};


DateInput.prototype.setJumpDay = function() {
  this.jumpFuture = this.JUMP_DAY;
  return this;
};

DateInput.prototype.setJumpMonth = function() {
  this.jumpFuture = this.JUMP_MONTH;
  return this;
};

DateInput.prototype.setJumpYear = function() {
  this.jumpFuture = this.JUMP_YEAR;
  return this;
};

DateInput.prototype.setJumpMonthYear = function() {
  this.jumpFuture = this.JUMP_MONTH_YEAR;
  return this;
};

DateInput.prototype.setForceNextFirst = function(n) {
  if (n != null) {
    this.forceNextFirst = n;
  } else {
    this.forceNextFirst = true;
  }
  return this;
};

DateInput.prototype.parse = function() {
  var value = this.input.value;
  var i = 0;
  var token;
  var num;
  var phase = 'PARSE_DAY';
  var day = this.refDate.getDate();;
  var month = this.refDate.getMonth() + 1;
  var year = this.refDate.getFullYear();
  this.userEntered = 0;

  var error = null;
  
  if (value.match(/^\d+$/)) {
    switch (value.length) {
      case 1:
      case 2:
        day = parseInt(value, 10);
        month = this.refDate.getMonth() + 1;
        year = this.refDate.getFullYear();
        this.userEntered = 1;
        break;
      case 4:
        day = parseInt(value.substr(0, 2), 10);
        month = parseInt(value.substr(2, 2), 10);
        year = this.refDate.getFullYear();
        this.userEntered = 3;
        break;
      case 6:
        day = parseInt(value.substr(0, 2), 10);
        month = parseInt(value.substr(2, 2), 10);
        year = parseInt(value.substr(4, 2), 10);
        this.userEntered = 7;
      case 8:
        day = parseInt(value.substr(0, 2), 10);
        month = parseInt(value.substr(2, 2), 10);
        year = parseInt(value.substr(4, 4), 10);
        this.userEntered = 7;
        break;
      default:
        error = "[ERR103] - " + this.messages.EDFORMAT.replace(/%s/, this.formatString);
        throw error;
    }
  } else {
    while (value.length > 0) {
      i = value.search(/[^\d]/);
      if (i == -1) {
        token = value;
        value = '';
      } else {
        token = value.substr(0, i);
        value = value.substr(i + 1);
      }
      num = parseInt(token, 10);
      if (isNaN(num) || (num < 1)) {
        error = "[ERR103] - " + this.messages.EDFORMAT.replace(/%s/, this.formatString);
        throw error;
      }
      switch (phase) {
        case 'PARSE_DAY':
          day = num;
          phase = 'PARSE_MONTH';
          this.userEntered |= 1;
          break;
        case 'PARSE_MONTH':
          month = num;
          phase = 'PARSE_YEAR';
          this.userEntered |= 2;
          break;
        case 'PARSE_YEAR':
          year = num;
          phase = 'NO_MORE';
          this.userEntered |= 4;
          break;
        default:
          error = "invalid phase '" + phase + "'";
          throw error;
      }
    }
  }
  if (year < 100) {
    year += 2000;
  }
  if(year < 2000) {
    error = "[ERR105] - " + this.messages.EDFORMAT;
    throw error;
  
  }
  if(year > 2050) {
    error = "[ERR105] - " + this.messages.EDFORMAT;
    throw error;
  }
  if (day > 31) {  
    error = "[ERR100] - " + this.messages.EMSG_DAY2;
    throw error;
  }
  if (month > 12) {
    error = "[ERR101] - " + this.messages.EMSG_MONTH2;
    throw error;
  }
  if (day > this.daysOfMonth(year, month)) {
    if (this.silentCorrect) {
      day = this.daysOfMonth(year, month);
    } else {
      error = "[ERR102] - " + this.messages.MSG_DAYOVERFLOW.replace(/%s/, this.daysOfMonth(year, month));
      throw error;
    }
  }
  this.setDateOnly(year,month,day);
  /*
  this.date.setFullYear(year);
  this.date.setMonth(month - 1);
  this.date.setDate(day);
  */
  this.checkConstraints();
};

/*
	aw 2009-02-25
	Datum genau auf den Tag setzen, keine Stunden etc
*/
DateInput.prototype.copyDateOnlyTo = function(date,fromdate) {
	if(!fromdate) {
		fromdate = this.date;
	}
	date.setFullYear(fromdate.getFullYear());
	date.setMonth(fromdate.getMonth());
	date.setDate(fromdate.getDate());
};

DateInput.prototype.setDateOnly = function(year,month,day) {
	this.date= new Date(0);
	this.date.setFullYear(year);
	this.date.setMonth(month-1);
	this.date.setDate(day);
	this.date.setHours(0);
	this.date.setMinutes(0);
    this.date.setSeconds(0);    
	this.date.setMilliseconds(0);
};


DateInput.prototype.checkConstraints = function() {
  var now = this.refDate.getTime();
  var daysInPastMillis = this.maxDaysPast * 24 * 60 * 60 * 1000;
  if (this.maxDaysPast == -1) {
    var maxPastDate = new Date(0);
  } else {
    var maxPastDate = new Date(this.refDate.getTime() - daysInPastMillis);
  }

  if (this.forceNextFirst) {
    var day = this.date.getDate();
    var month = this.date.getMonth() + 1;
    var year = this.date.getFullYear();
    if (day != 1) {
      day = 1;
      month++;
      if (month > 12) {
        month = 1;
        year++;
      }
	  this.setDateOnly(year,month,day);
/*      
      this.date.setDate(1);
      this.date.setMonth(month - 1);
      this.date.setFullYear(year);
*/      
    }
    while (this.date.isBefore(this.refDate)) {
      this.date.setMonth(this.date.getMonth() + 1);
    }
  } else {
    if (this.date.isBefore(maxPastDate)) {
      switch (this.jumpFuture) {
        case this.JUMP_DAY:
          this.date = maxPastDate;
          break;
        case this.JUMP_MONTH:
          var month = this.date.getMonth() + 1;
          var year = this.refDate.getFullYear();
          month++;
          if (month > 12) {
            month = 1;
            year++;
          }
          this.date.setMonth(month - 1);
          this.date.setFullYear(year);
          break;
        case this.JUMP_YEAR:
          this.date.setFullYear(this.refDate.getFullYear() + 1);
          break;
        case this.JUMP_MONTH_YEAR:
          var day = this.date.getDate();
          var month = this.date.getMonth() + 1;
          var year = this.date.getFullYear();

          switch (this.userEntered) {
            case 3:
              year++;
              break;
            case 1:
              month++;
              if (month > 12) {
                year++;
                month = 1;
              }
              break;
          }

		  this.setDateOnly(year,month,day);
/*		
          this.date.setDate(day);
          this.date.setMonth(month - 1);
          this.date.setFullYear(year);
*/
          break;
        default:
          var error = "unknown jump constant " + this.jumpFuture;
          throw error;
      }
    }
  }
};

DateInput.prototype.format = function(formatString) {
  if (!formatString) {
    if (!this.formatString) {
      throw 'no formatstring';
    } else {
      formatString = this.formatString;
    }
  }

  var values = new Object();
  values.d = new String(this.date.getDate());
  values.dd = values.d;
  if (values.dd.length == 1) { values.dd = '0' + values.dd; }

  values.M = new String(this.date.getMonth() + 1);
  values.MM = values.M;
  values.MMM = this.messages.MONTHNAMES[this.date.getMonth()];
  if (values.MM.length == 1) { values.MM = '0' + values.MM; }

  values.y = new String(this.date.getFullYear());
  values.yy = new String(values.y).substr(2, 2);
  values.yyyy = values.y;

  values.EEEE = this.messages.DAYNAMES[this.date.getDay()];
  values.EE = this.messages.DAYNAMES[this.date.getDay() + 7];

  var result = '';  

  var i = 0;
  var token = '';
  var div = '';
  while (formatString.length > 0) {
    i = formatString.search(/[ .:\-/]/);
    if (i == -1) {
      token = formatString;
      formatString = '';
      div = '';
    } else {
      token = formatString.substring(0, i);
      div = formatString.charAt(i);
      formatString = formatString.substr(i + 1);
    }
    if (values[token]) {
      result += values[token] + div;
    } else {
      var error = "invalid formatstring - unknown token: '" + token + "'";
      throw error;
    }
  }
  
  return result;
};


// Liegt das Datum in der Vergangenheit
DateInput.prototype.isPast = function() {
  if (this.date.getFullYear() < this.refDate.getFullYear()) {
    return true;
  }
  if (this.date.getFullYear() > this.refDate.getFullYear()) {
    return false;
  }
  if (this.date.getMonth() < this.refDate.getMonth()) {
    return true;
  }
  if (this.date.getMonth() > this.refDate.getMonth()) {
    return false;
  }
  if (this.date.getDate() < this.refDate.getDate()) {
    return true;
  }
  return false;
};

// Liegt das Datum in der Zukunft
DateInput.prototype.isFuture = function() {
  if (this.date.getFullYear() > this.refDate.getFullYear()) {
    return true;
  }
  if (this.date.getFullYear() < this.refDate.getFullYear()) {
    return false;
  }
  if (this.date.getMonth() > this.refDate.getMonth()) {
    return true;
  }
  if (this.date.getMonth() < this.refDate.getMonth()) {
    return false;
  }
  if (this.date.getDate() > this.refDate.getDate()) {
    return true;
  }
  return false;
};

DateInput.prototype.isEqualTo = function(refDate) {
  return (this.date.getFullYear() == refDate.getFullYear() &&
  this.date.getMonth() == refDate.getMonth() &&
  this.date.getDate() == refDate.getDate());
}

// Das heutige Datum (ueber refDate gesetzt)

DateInput.prototype.isToday = function() { 
	return this.isEqualTo(this.refDate); 
};

DateInput.prototype.increaseOneDay = function() {
  this.date.setDate(this.date.getDate() + 1);
  this.input.value = this.format();
  return this;
};

/******************************************************************************************/

function TimeInput(id, initialTime, surpresshandler) {
  if( (typeof id) == 'string') {
	  this.input = document.getElementById(id);
  }
  else {
  	this.input = id;
  }
  this.date = new Date();
  if (initialTime) {
    var hour = parseInt(initialTime.substr(0, 2), 10);
    var minute = parseInt(initialTime.substr(3, 2), 10);
    this.setHoursMinutes(hour,minute);
  }
  this.refDate = new Date(this.date);

  this.messages = Messages;
  
  this.formatString = 'HH:mm';
  this.stepInterval = 0;
  this.stepBack = false;
  this.userEntered = 0;
  this.dateField = null;
  if(!surpresshandler) {
	  if (this.input.addEventListener) {
	    this.input.addEventListener('blur', this.blurHandler.bindOn(this), false);
	    this.input.addEventListener('keyup', this.keyupHandler.bindOn(this), false);
	    this.input.form.addEventListener('submit', this.blurHandler.bindOn(this), false);
	  } else {
	    this.input.attachEvent('onblur', this.blurHandler.bindOn(this));
	    this.input.attachEvent('onkeyup', this.keyupHandler.bindOn(this), false);
	    this.input.form.attachEvent('onsubmit', this.blurHandler.bindOn(this));
	  }
  }
  // initialisieren, d.h. auslesen des inputs
  if (this.input.value != "") {
    this.blurHandler();
  }
  
  this.changeCallbackObj = null;
  this.changeCallback = null;
  this.allowEmpty = false;
  this.completeEmpty = true;
  this.warnIfEmpty = true;
}

TimeInput.prototype.setHoursMinutes = function(hour,minute) {
    this.date.setHours(hour);
    this.date.setMinutes(minute);
    this.date.setSeconds(0);    
}

TimeInput.prototype.setWarnIfEmpty = function(warn) {
  if (warn != null) {
    this.warnIfEmpty = warn;
  } else {
    this.warnIfEmpty = true;
  }
  return this;
};


TimeInput.prototype.setCompleteEmpty = function(completeEmpty) {
  if (completeEmpty != null) {
    this.completeEmpty = completeEmpty;
  } else {
    this.completeEmpty = true;
  }
  return this;
};

TimeInput.prototype.setAllowEmpty = function(allowEmpty) {
  if (allowEmpty != null) {
    this.allowEmpty = allowEmpty;
  } else {
    this.allowEmpty = true;
  }
  return this;
};

TimeInput.prototype.setMessages = function(messageObj) {
  this.messages = messageObj;
  return this;
};

TimeInput.prototype.setChangeCallback = function(cb, obj) {
  this.changeCallback = cb;
  this.changeCallbackObj = obj;
  return this;
};

TimeInput.prototype.setDateField = function(obj) {
  this.dateField = obj;
  if(this.dateField) {
  	// aw gleich angleichen, 2009-09-16 aber getrennt nach Ref und date
  	this.dateField.copyDateOnlyTo(this.refDate,this.dateField.refDate);
  	this.dateField.copyDateOnlyTo(this.date);
  }
  return this;
};


TimeInput.prototype.setMinuteInterval = function(interval, back) {
  this.stepInterval = interval;
  if (back != null) {
    this.stepBack = back;
  }
  return this;
};

TimeInput.prototype.setFormat = function(formatString) {
  this.formatString = formatString;
  if (this.input.value != "") {
    this.input.value = this.format();
  }
  return this;
};

TimeInput.prototype.round = function() {
	if (this.stepInterval != 0) {
		var hours = this.date.getHours();
		var minutes = this.date.getMinutes();

		var mod = minutes % this.stepInterval;
		if (mod != 0) {
			if (this.stepBack) {
				minutes -= mod;
			} else {
				minutes += this.stepInterval - mod;
			}
			
			// eigentlich == 60, da es immer nur maximal auf 60 aufschlagen kann
			if (minutes > 59) {
				hours++;
				if (hours > 23) {
					if(this.dateField) {
						// aw 2009-09-16 auch hier hochzählen
						this.dateField.increaseOneDay();
						window.alert(this.messages.EMSG_24_zu_00);
						this.dateField.copyDateOnlyTo(this.date);
					}
					hours = 0;
				}
				minutes = 0;
			}
		}

		this.setHoursMinutes(hours,minutes);
	}
};

TimeInput.prototype.checkConstraints = function() {
  // wenn die Uhrzeit in der Vergangenheit liegt, wird sie auf den juengsten
  // moeglichen Zeitpunkt in der Vergangenheit gesetzt

  // wenn ein DatumsFeld definiert ist
  if (this.dateField) {
	  // aw 2009-09-16 auf jeden fall sicher stellen, dass das
	  // datum dieser Zeit richtig gesetzt ist
	this.dateField.copyDateOnlyTo(this.date); 
    if (this.dateField.isPast()) {
      // eh egal
      this.round();
    }
    if (this.dateField.isFuture()) {
      // auch egal
      this.round();
    }
    if (this.dateField.isToday()) {
      // schon vorbei?
      if (this.date.isBefore(this.refDate)) {
        this.date = new Date(this.refDate);
        this.userEntered = 3;
      }
      this.round();
    }
  } else {
    this.round();
  }
};

TimeInput.prototype.parse = function() {
	  // aw 2009-09-16 auf jeden fall sicher stellen, dass das
	  // datum dieser Zeit richtig gesetzt ist
	  if (this.dateField) {
		  this.dateField.copyDateOnlyTo(this.date);
	  }
  var value = this.input.value;
  var i = 0;
  var token;
  var num;
  var phase = 'PARSE_HOURE';
  var hour = this.refDate.getHours();
  var minute = this.refDate.getMinutes();
  this.userEntered = 0;
  if (value.match(/^\d+$/)) {
    switch (value.length) {
      case 1:
      case 2:
        hour = parseInt(value, 10);
        minute = 0;
        this.userEntered = 1;
        break;
      case 3:
        hour = parseInt(value.substr(0,1), 10);
        minute = parseInt(value.substr(1, 2), 10);
        this.userEntered = 3;
        break;
      case 4:
        hour = parseInt(value.substr(0, 2), 10);
        minute = parseInt(value.substr(2, 2), 10);
        this.userEntered = 3;
        break;
      default:
        throw "[ERR103] - " + this.messages.MSG_UNPARSEABLE;
    }
  } else {
    while (value.length > 0) {
      i = value.search(/[^\d]/);
      if (i == -1) {
        token = value;
        value = '';
      } else {
        token = value.substr(0, i);
        value = value.substr(i + 1);
      }
      num = parseInt(token, 10);
      if (isNaN(num) || (num < 0)) {
        var error = "invalid Input";
        throw error;
      }
      switch (phase) {
        case 'PARSE_HOURE':
          hour = num;
          phase = 'PARSE_MINUTE';
          this.userEntered |= 1;
          break;
        case 'PARSE_MINUTE':
          minute = num;
          phase = 'NO_MORE';
          this.userEntered |= 2;
          break;
        default:
          var error = "invalid phase '" + phase + "'";
          throw error;
      }
    }
  }
  if (hour == 24) { // Tag hochzaehlen und Zeit auf 0
    if (this.dateField) {
      this.dateField.increaseOneDay();
      hour = 0;
      minute = 0;
      window.alert(this.messages.EMSG_24_zu_00);
	  // aw 2009-09-16 auf jeden fall sicher stellen, dass das
	  // datum dieser Zeit richtig gesetzt ist
      this.dateField.copyDateOnlyTo(this.date);
      
    } else {
      var error = "[ERR200] - " + this.messages.EMSG_HOURS;
      throw error;
    }
  }
  if (hour > 24) {
    var error = "[ERR200] - " + this.messages.EMSG_HOURS;
    throw error;
  }
  if (minute > 59) {
    var error = "[ERR201] - " + this.messages.EMSG_MINUTES;
    throw error;
  }
  if (this.stepInterval != 0 && this.userEntered == 1) {
    minute = 0;
  }
  this.setHoursMinutes(hour,minute);
  this.checkConstraints();
};

TimeInput.prototype.format = function(formatString) {
  if (!formatString) {
    if (!this.formatString) {
      throw 'no formatstring';
    } else {
      formatString = this.formatString;
    }
  }

  var values = new Object();
  values.H = new String(this.date.getHours());
  values.HH = values.H;
  if (values.HH.length == 1) { values.HH = '0' + values.HH; }

  values.m = new String(this.date.getMinutes());
  values.mm = values.m;
  if (values.mm.length == 1) { values.mm = '0' + values.mm; }

  values.h = new String(this.date.getHours() % 12);
  values.hh = values.h;
  if (values.hh.length == 1) { values.hh = '0' + values.hh; }

  values.k = new String(this.date.getHours() == 0 ? '24' : this.date.getHours());
  values.kk = values.k;
  if (values.kk.length == 1) { values.kk = '0' + values.kk; }

  values.K = new String((this.date.getHours() % 12) == 0 ? '0' : (this.date.getHours() % 12));
  values.KK = values.K;
  if (values.KK.length == 1) { values.KK = '0' + values.KK; }

  values.s = new String(this.date.getSeconds());
  values.ss = values.s;
  if (values.ss.length == 1) { values.ss = '0' + values.ss; }


  var result = '';

  var i = 0;
  var token = '';
  var div = '';
  while (formatString.length > 0) {
    i = formatString.search(/[.:\-/ ]/);
    if (i == -1) {
      token = formatString;
      formatString = '';
      div = '';
    } else {
      token = formatString.substring(0, i);
      div = formatString.charAt(i);
      formatString = formatString.substring(i + 1);
    }
    if (values[token]) {
      result += values[token] + div;
    } else  {
      var error = "invalid formatstring - unknown token: '" + token + "'";
      throw error;
    }
  }
  return result;
};

TimeInput.prototype.keyupHandler = function(event) {
	  var code = event.keyCode;
	  try {
		  validate_on_input_time(this.input);
	  }
	  catch(e) {}
};


TimeInput.prototype.blurHandler = function(event) {
  if (event && event.type && event.type == 'submit') {
    if (this.input.value == '' && this.warnIfEmpty && !this.allowEmpty) {
      event.preventDefault ? event.preventDefault() : event.returnValue = false;
      if (this.input.labels && this.input.labels.length == 1) {
        window.alert(this.messages.MSG_WARN_EMPTY.replace(/%s/, " '" + this.input.labels[0].text + "'"));
      } else {
        window.alert(this.messages.MSG_WARN_EMPTY.replace(/%s/, ""));
      }
      this.input.select();
      return;
    }
  }
  if (this.input.value == "" && this.allowEmpty) {
    return;
  }
  if (this.input.value == "" && !this.completeEmpty) {
    return;
  }
  try {
    this.parse();
    this.input.value = this.format();
  } catch (e) {
    var exceptionPattern = /^\[ERR(\d+)\] - (.*)$/;
    var match = exceptionPattern.exec(e);
    if (match) {
      var code = parseInt(match[1], 10);
      var message = match[2];
      switch (code) {
        case 200:
        case 201:
          window.alert(message);
          this.input.focus();
          this.input.select();
          break;
        default:
          throw e;
      }
    } else {
      throw e;
    }
  }
  if (this.changeCallback) {
    this.changeCallback.call(this.changeCallbackObj);
  }
};


/**************************************************************************************/

TimeInterval = function() {
  this.minIntervalSize = 0; 
  this.messages = Messages;
};

TimeInterval.prototype.setMessages = function(messageObj) {
  this.messages = messageObj;
  if (this.startDate) { this.startDate.setMessages(this.messages); }
  if (this.startTime) { this.startTime.setMessages(this.messages); }
  if (this.endDate) { this.endDate.setMessages(this.messages); }
  if (this.endTime) { this.endTime.setMessages(this.messages); }
  return this;
};

TimeInterval.prototype.setMinIntervalSize = function(minutes) {
  this.minIntervalSize = minutes;
};


TimeInterval.prototype.setStartDate = function(obj) {
  this.startDate = obj;
  this.setupHandler();
  return this;
};

TimeInterval.prototype.setStartTime = function(obj) {
  this.startTime = obj;
  this.setupHandler();
  return this;
};

TimeInterval.prototype.setEndDate = function(obj) {
  this.endDate = obj;
  this.setupHandler();
  return this;
};

TimeInterval.prototype.setEndTime = function(obj) {
  this.endTime = obj;
  this.setupHandler();
  return this;
};

TimeInterval.prototype.setFields = function(startDate, startTime, endDate, endTime) {
  this.startDate = startDate;
  this.startTime = startTime;
  this.endDate = endDate;
  this.endTime = endTime;
  this.setupHandler();
  this.endDate.setMaxDaysInPast(0);
  return this;
};

TimeInterval.prototype.checkConstraints = function() {
  // Bedingung: endDate >= startDate
  
  // sicher stellen, auch wenn es schon ueber startDateChangedHandler
  // erledigt wurde
  
  this.adjustEndDateTime();
  /*
  this.endDate.refDate = new Date(this.startDate.date);
  
  if (this.endDate.date.isBefore(this.startDate.date)) {
    this.endDate.date = new Date(this.startDate.date);
    this.endDate.input.value = this.endDate.format();
  }
  */
  
  // Wenn endDate == startDate
  // muss Mindestzeitspanne eingehalten werden
  // erst wenn der Benutzer auch in beide Zeitfelder etwas eingegeben hat
  if (this.startDate.isEqualTo(this.endDate.date)    ) {
	
	if (this.startTime.input.value != "" && this.endTime.input.value != "") {

      var start = this.startTime.date.getMinutes() + this.startTime.date.getHours() * 60;
      var end = this.endTime.date.getMinutes() + this.endTime.date.getHours() * 60;

      if ((start + this.minIntervalSize) > end) {
        this.endTime.date = new Date(this.startTime.date);
        this.endTime.refDate = new Date(this.endTime.date);
        this.endTime.date.setMinutes(this.endTime.date.getMinutes() + this.minIntervalSize);
        this.endTime.input.value = this.endTime.format();
      }
      // wenn startTime + minIntervalSize > 24 Stunden
      if (start + this.minIntervalSize >= 24 * 60) {
        this.endDate.date.setDate(this.endDate.date.getDate() + 1);
        this.endDate.input.value = this.endDate.format();
      }
    }
  }
};

TimeInterval.prototype.startDateChangedHandler = function() {
	this.startDate.copyDateOnlyTo(this.startTime.date);
	this.adjustEndDateTime();
}

TimeInterval.prototype.adjustEndDateTime = function() {
	// die refs immer aktualisieren
	this.endDate.refDate = new Date(this.startDate.date);
	this.endTime.refDate = new Date(this.startTime.date.getTime());

	// sicherheitshalber auch das date von endTime.date richtig setzen 

	if(this.endDate.input.value !== '')  {
		this.endDate.copyDateOnlyTo(this.endTime.date);
	}
	
	// das nur, wenn die Datumsangaben nicht passen
	if(this.endDate.input.value === ''
		|| this.endDate.date.isBefore(this.startDate.date)) {

		this.endDate.date = new Date(this.endDate.refDate);
		this.endDate.input.value = this.endDate.format();
		
		this.endDate.copyDateOnlyTo(this.endTime.date);
	} 
};

TimeInterval.prototype.setupHandler = function() {
  if (this.startDate && this.startTime && this.endDate && this.endTime) {
    this.startTime.setDateField(this.startDate);
    this.endTime.setDateField(this.endDate);

    addEvent(this.startDate.input, 'blur', this.startDateChangedHandler.bindOn(this));
    this.startDate.setChangeCallback(this.checkConstraints, this);
    this.startTime.setChangeCallback(this.checkConstraints, this);
    this.endDate.setChangeCallback(this.checkConstraints, this);
    this.endTime.setChangeCallback(this.checkConstraints, this);
    
    // und schon mal sicher stellen, dass alles konsistent ist
    this.adjustEndDateTime();
  }
  return this;
};


