var cal_cache=window.cal_cache;
if(!cal_cache){
  cal_cache={confs :{},cals:{}};
  window.cal_cache=cal_cache;
}

function datumsbereich(heute,anfang,ende){
//////////////////////////////////////////////////////
// Übergabewerte:                                   //
// heute:  Datum heute                              //
// anfang: x Tage vor oder nach heute               //
// ende:   x Tage vor oder nach heute               //
//                                                  //
// Berechnung - Beispiel:                           //
// Start:  Ausgangswert plus 10 Tage                //
// Ende:   Ausgangswert plus 3 Monate (3 * 30 Tage) //
//                                                  //
// Rückgabewerte:                                   //
// Start:  start_jahr,start_monat,start_tag         //
// Ende:   ende_jahr,ende_monat,ende_tag            //
//////////////////////////////////////////////////////

// Start
  var start_datum = new Date();
  start_datum.setTime(heute.getTime());
  start_datum.setDate(start_datum.getDate()+anfang);
  var start_tag = start_datum.getDate();
  var start_monat = start_datum.getMonth();
  var start_jahr = start_datum.getYear();

// Ende

  var ende_datum = new Date();
  ende_datum.setTime(heute.getTime());
  ende_datum.setDate(ende_datum.getDate()+ende);
  var ende_tag = ende_datum.getDate();
  var ende_monat = ende_datum.getMonth();
  var ende_jahr = ende_datum.getYear();

// Rückgabewerte
  return [new Date(start_jahr,start_monat,start_tag),new Date(ende_jahr,ende_monat,ende_tag)];
}

function cal_initConfs(){
  cal_registerConf('cal2',cal_setupConf({weekNumbers:false
                                       ,disableWeekends:false
                                       ,disableFeiertage:false
                                       ,showFeiertageTooltip:true
                                      ,range:[new Date(1950,7,26),new Date(2015,9,1)]}));
  
  cal_registerConf('cal1',cal_setupConf({weekNumbers:false
                                         ,range:[new Date(2000,9,1),new Date(2010,3,20)]}));

  cal_registerConf('cal3',cal_setupConf({weekNumbers:false
                                       ,disableWeekends:false
                                       ,disableFeiertage:false
                                       ,showFeiertageTooltip:false
                                      ,range:[new Date(2008,1,1),new Date(2100,1,1)]}));
}

function cal_setupConf(params){
	function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };

	param_default("ifFormat",       "%d.%m.%Y");
	param_default("singleClick",    true);
	param_default("dateText",       null);
	param_default("firstDay",       1);
	param_default("range",          [new Date(1583,0,1), new Date(2499,11,31)]); // Jahr-Klick-Bereich
	param_default("weekNumbers",    true);
	param_default("onSelect",       cal_onSelect);
	param_default("onClose",        function(cal) { cal.hide(); });
	param_default("onUpdate",       null);
	param_default("date",           null);
	param_default("showsTime",      false);
	param_default("timeFormat",     "24");
	param_default("step",           1);
	param_default("showOthers",     false);
	param_default("multiple",       null);

  // Displayparameter
  // werden vom Parameter 'displayparameter' der popup-Funktion 
  // ueberschrieben. Einer 'position' oder 'align' und 'align_element' 
  // sollte hier oder in der popup-Funktion angegeben werden.
  // 'position' hat Vorrang.
	param_default("position",   [0,0]); // configures the calendar absolute position
	param_default("align",      'Br'); // alignment; siehe Doku of 'align'-Parameter
	
	param_default("heute",          new Date()); // wird in calendar.js direkt ausgewertet

  // 'disableWeekend', 'styleWeekend', 'disableFeiertage' und 
  // 'styleFeiertage' werden ignoriert, wenn 'dateStatusFunc' 
  // nicht null ist
	param_default("disableWeekends",        false);
	param_default("styleWeekends",          null);  // wenn nicht null und disabled, wird automatisch '_disabled' angehaengt
	param_default("disableFeiertage",      false);
	param_default("styleFeiertage",        null);  // wenn nicht null und disabled, wird automatisch '_disabled' angehaengt
	param_default("dateStatusFunc",        null);  // callback (date,y,m,d)

  // wird ignoriert, wenn 'tooltipFunc' nicht null ist
	param_default("showFeiertageTooltip",  false);
	param_default("tooltipFunc",    null); // callback (date,y,m,d)
	
	return params;
}

function cal_registerConf(confid,conf){
  if(cal_cache['confs'][confid])
    cal_cache['cals'][confid]=null;
    
  cal_cache['confs'][confid]=conf;
}

function cal_getCal(confid){
  var cal=cal_cache['cals'][confid];

  if(!cal){
    cal=cal_createCal(confid);
    cal_cache['cals'][confid]=cal;
  }
    
 	cal.refresh();

  return cal;
}

function cal_getConf(confid){
  if(!confid)
    config="__default__";
  
  var conf=cal_cache['confs'][confid];
  if(!conf){
    conf=cal_setupConf({});
    cal_cache['confs'][confid]=conf;
  }
    
  return conf;
}

function cal_createCal(confid){
  var params=cal_getConf(confid);
  var cal=new Calendar(
      params.firstDay,
			params.date,
			params.onSelect,
			params.onClose
		);
	cal.showsTime = params.showsTime;
	cal.time24 = (params.timeFormat == "24");
	cal.weekNumbers = params.weekNumbers;
	
	if (params.date)
		cal.setDate(params.date);

	if (params.multiple) {
		cal.multiple = {};
		for (var i = params.multiple.length; --i >= 0;) {
			var d = params.multiple[i];
			var ds = d.print("%Y%m%d");
			cal.multiple[ds] = d;
		}
	}
	
	var dt=new Date(2000,0,1);
	var yearinc=2000-dt.getYear();

	cal.showsOtherMonths = params.showOthers;
	cal.yearStep = params.step;


//20080626/DG/IE 6 gibt bei getYear unter Umstaenden eine zweistellige statt vierstellige Zahl zurueck
//	cal.setRange(params.range[0].getYear()+yearinc, params.range[1].getYear()+yearinc);
      var minYear = params.range[0].getYear()+yearinc;
      if(minYear<1900)minYear = minYear + 1900;
      var maxYear = params.range[1].getYear()+yearinc;
      if(maxYear<1900)maxYear = maxYear + 1900;
      cal.setRange(minYear, maxYear);

	
	
	cal.setDateStatusHandler(params.dateStatusFunc);
  // Standard-Callback für getDateStatus setzen, wenn keine 
  // konfiguriert wurde.
  if(!(typeof params.dateStatusFunc == 'function')){
    params.dateStatusFunc=cal_getDateStatus;
    cal.setDateStatusHandler(cal_getDateStatus);
  }

	cal.setDateToolTipHandler(params.tooltipFunc);  // Standard-Callback für tooltipFunc setzen, wenn keine 
  // konfiguriert wurde und die Funktionalitaet gewuenscht wird.
  if(!(typeof params.tooltipFunc == 'function') && params.showFeiertageTooltip){
    params.tooltipFunc=cal_getToolTip;
    cal.setDateToolTipHandler(cal_getToolTip);
  }

	cal.getDateText = params.dateText;
	cal.setDateFormat(params.ifFormat);

	cal.params = params;

  cal.create();
	cal.refresh();
	cal.hide();
	
	return cal;
}

// Eventhandler zum Anzeigen eines Kalenders.
//
// Parameter:
//  confid: 
//    Bestimmt den Typ des Kalenders. Muss eine ID eines vorher mittels 
//    cal_registerConf() registrieten Konfigurations-Objektes sein.      
//  params:
//    Objekt mit folgenden Properties
//    Positionierungs-Parameter:
//      pos_position: [x,y]
//        absolute Position des Kalenders
//        default ist Conf-Parameter position([0,0]) nur, wenn kein pos_element angegeben wurde
//      pos_element: string
//        ID des Elementes an dem der Kalender ausgerichtet werden soll
//        default ist null
//      pos_element_align: string
//        Ausrichtungsparameter siehe 'align' in Doku
//        default ist Conf-Parameter align('Br')
//    Zielfeldparameter:
//      field: string
//        ID des Feldes(der Felder), in dem(denen) das Datum geschrieben werden soll
//      field_split: boolean
//        wenn false(default)
//    sonstige Parameter:
//      today: Date
//        Datum des aktuellen Tages
//        default ist Conf-Parameter heute(new Date())
// Return:
//  false 
function cal_popup(confid,params){
  var cal=cal_getCal(confid);
  
  if(!params || !params.field)
    alert("Nothing specified to write the date to.");

  var conf=cal.params;

  // Feld-Parameter in die Kalenderkonfiguration schreiben, damit
  // die onSelect-Callback darauf zugreifen kann
  conf['field']=params.field;
  conf['field_split']=params.field_split;

  // aktuelles Datum setzen/selektiertes Datum setzen
  
  // Selektiertes Datum ist entweder das in den Parametern
  // gesetzte oder das im Zielfeld stehende, sofern parsbar 
  // oder das aktuelle Datum aus den Parametern, sofern 
  // gesetzt oder der Wert aus den Kalenderparametern oder 
  // das aktuelle Datum des Clients.
  // Aktuelles Datum ist entweder das in den Parametern 
  // gesetzte oder der Wert aus den Kalenderparametern oder das aktuelle Datum des Clients.
  
  // aktuelles Datum aus Parameter
  var currentdate=null;
  if(params.today)
    currentdate=params.today;
    
  if(currentdate==null)
  	currentdate=new Date();

  // selektiertes Datum aus Parameter
  var selecteddate=null;
  if(params.selected)
    selecteddate=params.selected;

  // selektiertes Datum aus Zielfeld
  if(!selecteddate && conf.field){
    if(!conf.field_split){
      var el=document.getElementById(conf.field);
      if(el){
  			var pd=Date.parseDate(el.value, conf.ifFormat);

        // Rückgabe checken, da parseDate bei ungültigem Datum das aktuelle zurückgibt
  			if(el.value==pd.print(conf.ifFormat))
  			  selecteddate=pd;
      }
    }else{
      var ely=document.getElementById(conf.field+"_year");
      var elm=document.getElementById(conf.field+"_month");
      var eld=document.getElementById(conf.field+"_day");

      if(ely && elm && eld){
        var pd=new Date(Number(ely.value),Number(elm.value)-1,Number(eld.value));
        if(!isNaN(pd.getTime())){
          if(pd.getFullYear()==Number(ely.value)
             && pd.getMonth()+1==Number(elm.value)
             && pd.getDate()==Number(eld.value)){
            selecteddate=pd;
          }
        }
      }
    }
	}
	
	// selektiertes Datum = aktuelles aus Parametern
	if(!selecteddate && currentdate)
	  selecteddate=new Date(currentdate.getTime());
	  
	// aktuelles Datum setzen
	if(currentdate){
	  conf.heute=currentdate;
	  cal.refresh();
	}
		
  // selectiertes Datum in Datumsbereich waehlen
  if(conf.range){
    var startdate=conf.range[0];
    var enddate=conf.range[1];

    var selt=selecteddate.getTime();

	  if(startdate){
	    var st=startdate.getTime();

      if(selt<st)
        selecteddate=new Date(st);
  	}

  	if(enddate){
	    var et=enddate.getTime();

      if(selt>et){
        selecteddate=new Date(et);
      }
  	}
  }

	// gueltiges Datum Innerhalb des Bereichs waehlen
	selecteddate=cal_selectValidDate(conf,selecteddate);	
	
	if(selecteddate){
	  cal.setDate(selecteddate);
	  cal.refresh();
	}
  
  // Positionierungsinfos ermitteln
  var pos_position=null;
  var pos_element=null;
  var pos_element_align=null;

  if(params.pos_position)
    pos_position=params.pos_position;
    
  if(!pos_position && params.pos_element){
    var el=document.getElementById(params.pos_element);
    if(el){
      pos_element=el;
      if(params.pos_element_align)
        pos_element_align=params.pos_element_align;
      else
        pos_element_align=conf.align;
    }
  }

  if(!pos_position && !pos_element){
    if(conf.position)
      pos_position=conf.position;
    else
      pos_position=[0,0];
  }

	if (pos_position)
		cal.showAt(pos_position[0], pos_position[1]);
	else
		cal.showAtElement(pos_element, pos_element_align);
		
  return false;
}

// callback fuer 'dateStatusFunc'
function cal_getDateStatus(cal,date,y,m,d){
  var conf=cal.params;

//alert("cal_getDateStatus: "+date);

  var d1=new Date(date.getTime());
  d1.setHours(0,0,0,0);
  var t1=d1.getTime();

  if(conf.disableWeekends || conf.styleWeekends){
    var weekday=date.getDay();
    if(weekday==0 || weekday==6){    
      if(conf.disableWeekends && conf.styleWeekends)
        return conf.styleWeekends+"_disabled";
        
      if(conf.styleWeekends)
        return conf.styleWeekends;
      
      // if(conf.disableWeekends)
      return true;
    }
  }

  // Datumsbereich checken
  if(conf.range){
    var startdate=conf.range[0];
    var enddate=conf.range[1];

    if(startdate && enddate){
      if(t1<startdate.getTime() || t1>enddate.getTime())
        return true;
    }else if(startdate){
      if(t1<startdate.getTime())
        return true;
    }else if(enddate){
      if(t1>enddate.getTime())
        return true;
    }
  }

  // Feiertage checken
  if(conf.disableFeiertage || conf.styleFeiertage){
    var feiertage=getFeiertage(y);
    if(feiertage != null){
      for (var i=0;i<feiertage.length;i++){
        var d2=feiertage[i].date;
        d2.setHours(0,0,0,0);
        if(t1==d2.getTime()){
          if(conf.disableFeiertage && conf.styleFeiertage)
            return conf.styleFeiertage+"_disabled";
            
          if(conf.styleFeiertage)
            return conf.styleFeiertage;
          
          // if(conf.disableFeiertage)
          return true;
        }
      }
    }
  }
  
  return false;
}

// Tooltips-Callback
function cal_getToolTip(date,y,m,d){
  var d1=new Date(date.getTime());
  d1.setHours(0,0,0,0);
  var t1=d1.getTime();
  var feiertage=getFeiertage(y);
  if(feiertage != null){
    for (var i=0;i<feiertage.length;i++){
      var d2=feiertage[i].date;
      d2.setHours(0,0,0,0);
      if(t1==d2.getTime()){
        return feiertage[i].desc;
      }
    }
  }
  
  return '';
}

// Bei Klick auf ein Datumsfeld update der Zielfelder
function cal_onSelect(calendar, date) {
  var conf=calendar.params;
  
  var update=true;

  // nur nicht gesperrte Datumswerte werden übernommen
  if(typeof conf.dateStatusFunc == 'function')
    update=!conf.dateStatusFunc(calendar,calendar.date,calendar.date.getFullYear(),calendar.date.getMonth()+1,calendar.date.getDate());
      
  // Übernahme des Datums in die Zielfelder, wenn 
  // das Datum nicht gesperrt ist
  if (update) {
    var input_field_day = document.getElementById("day");
    var input_field_month = document.getElementById("month");
    var input_field_year = document.getElementById("year");

    var day=calendar.date.getDate();
    if(day<10){
      day='0'+day;
    }

    var month=calendar.date.getMonth()+1;
    if(month<10){
      month='0'+month;
    }

    var year=calendar.date.getFullYear();

    var field=conf.field;

    if(field){
      if(!conf.field_split){
        var el=document.getElementById(field);
        if(el)
          el.value=date;
          
      }else{
        var el=document.getElementById(field+"_year");
        if(el)
          el.value=year;

        el=document.getElementById(field+"_month");
        if(el)
          el.value=month;
        
        el=document.getElementById(field+"_day");
        if(el)
          el.value=day;
      }
    }
  }

  // Kalender schliessen, wenn die Zielfelder 
  // angepasst wurden, eine Datumszelle oder der
  // Today-Button(wenn der aktuelle Tag bereits 
  // ausgewählt wurde) angeklickt wurde und der 
  // Parameter singleClick true ist.
	if (update && conf.singleClick && calendar.dateClicked)
    calendar.callCloseHandler(); // this calls "onClose" (see above)
};

// Testet, ob selected Date gueltig(Range,Weekend,Holiday) ist und versucht im negativen Falle 
// das naechste gueltige Datum zu finden und gibt es zurueck.
// Kann kein gueltiges Datum gefunden Werden, wird das Datum unveraendert zurueck gegeben.
function cal_selectValidDate(conf,selecteddate){
	var millisperday=86400000;
	selecteddate.setHours(10,0,0,0);
	
	var sd=new Date(selecteddate.getTime());

	var checkup=1;
	while(true){	
		// weekend checken
		var weekendchecked=true;
	  if(conf.disableWeekends || conf.styleWeekends){
	    var weekday=sd.getDay();
	    if(weekday==0 || weekday==6){    
	    	weekendchecked=false;
	    }
	  }
	  
	  // Feiertage checken
		var hollidaychecked=true;
	  if(conf.disableFeiertage || conf.styleFeiertage){
	    var feiertage=getFeiertage(sd.getFullYear());
	    var selt=sd.getTime();
	    if(feiertage != null){
	      for (var i=0;i<feiertage.length;i++){
	        var d2=feiertage[i].date;
	        d2.setHours(10,0,0,0);
	        if(selt==d2.getTime()){
	        	hollidaychecked=false;
	        	break;
	        }
	      }
	    }
	  }
	  
		var checkrange=false;
	  if(weekendchecked && hollidaychecked){
	  	checkrange=true;
	  }else{
    	sd.setTime(sd.getTime()+(millisperday*checkup))
	  }

		if(checkrange){	
			var rangechecked=true;

		  // Datumsbereich checken
		  if(conf.range){
		    var startdate=conf.range[0];
		    var enddate=conf.range[1];
		
		    var selt=sd.getTime();
		
				if(startdate){
			    var st=startdate.getTime();
		
					if(selt<st)
		        rangechecked=false;
		  	}
		  	
		  	if(enddate){
			    var et=enddate.getTime();
		
		    	if(selt>et)
		        rangechecked=false;
		  	}
		  }

			if(!rangechecked){
				if(checkup==1){
					checkup=-1;
					sd=new Date(selecteddate.getTime());
				}else{
					return selecteddate;
				}
			}else{
				return sd;
			}
		}
	}
}

