/*
  Objekt, ktery obsahuje zkratky dnu. Diky tomu, ze se musi kalendar volat
  vzdy s instanci nejakeho takoveho objektu, muze byt na jedne strance
  treba anglicky a cesky kalendar.
*/
function DayNames () {
  this[0]='Ne';
  this[1]='Po';
  this[2]='Út';
  this[3]='St';
  this[4]='Čt';
  this[5]='Pá';
  this[6]='So';
}

/*
  To same, co objekt se dny, ale tentokrat s mesici.
*/
function MonthNames () {
  this[0]='leden';
  this[1]='únor';
  this[2]='březen';
  this[3]='duben';
  this[4]='květen';
  this[5]='červen';
  this[6]='červenec';
  this[7]='srpen';
  this[8]='září';
  this[9]='říjen';
  this[10]='listopad';
  this[11]='prosinec';
}

function ImDay (forbidden,repeat,reminder,day,month,year) {
  this.text=reminder;
  this.date=new Date (year,month-1,day);
  this.forbidden=forbidden;
  this.repeat=repeat;
}

/*
  Konstruktor objektu kalendare. Parametry jsou: pocatecni den tydnu (0=nedele,
  1=pondeli, ...), format data, ktere se bude z kalendare vracet (zatim mozno
  pouzit znaky d, m, Y pro cisla dnu, mesicu a roku - priklad: 'd. m. Y' dopadne
  treba jako '16. 12. 2004').
*/
function Calendar (dateFormat,cssPrefix,fixdatum) {
  if (fixdatum!=null) {
    this.datum=new Date (fixdatum);
  } else {
    this.datum=new Date();
  }
  /*
    vetsinu veci je treba ulozit jako vlastnosti objektu, aby byly k dispozici
    i dalsim metodam objektu.
  */
  this.currentYear=this.datum.getFullYear();
  this.currentMonth=this.datum.getMonth();
  this.startingDay=1;
  this.days=new DayNames();
  this.months=new MonthNames ();
  this.dateFormat=dateFormat;
  this.cssPrefix=cssPrefix;
  this.todayEnabled=true;
  this.inputElement=null;
  this.inputElements=new Object ();
  this.inputElements.day=null;
  this.inputElements.month=null;
  this.inputElements.year=null;
  this.visible=false;
  this.popup=true;
  this.startDate=null;
  this.endDate=null;
  this.importantDays=new Array (ImDay);
  this.iDayCounter=0;
  this.daysCount=new Array(31,28,31,30,31,30,31,31,30,31,30,31);
	if (((this.currentYear%4==0) && (this.currentYear%100!=0)) || (this.currentYear%400==0)) {
		this.daysCount[1]=29;
	}
	if (this.currentMonth>0) {
	  this.lastMonth=this.currentMonth-1;
  } else {
    this.lastMonth=11;
  }
  if (this.currentMonth<11) {
	  this.nextMonth=this.currentMonth+1;
  } else {
    this.nextMonth=0;
  }
  // deklarace metod
  this.drawMonth=draw_Month;
  this.redrawHeader=redraw_Header;
  this.show=show_Calendar;
  this.hide=hide_Calendar;
  this.attachInput=attach_Input;
  this.attachInputs=attach_Inputs;
  this.save=save_Date;
  this.setStartingDay=set_Starting_Day;
  this.setDayNames=set_Day_Names;
  this.setMonthNames=set_Month_Names;
  this.setEndDate=set_End_Date;
  this.setTodayEnabled=set_today_enabled;
  this.setStartDate=set_Start_Date;
  this.addSpecialDay=add_Special_Day;
  this.attach=attach_calendar;
  // vlastni prvni vykresleni zakladu tela kalendare
  this.calendar=document.createElement ('table');
  this.calendar.className=this.cssPrefix+'cal_main';
  this.calendar.calendar=this;
  this.thead=document.createElement ('thead');
  this.tbody=document.createElement ('tbody');
  tr=document.createElement ('tr');
  // predesly rok
  th=document.createElement ('th');
  text=document.createTextNode ('«');
  th.className=this.cssPrefix+'cal_yearbefore';
  th.onclick=last_Year;
  th.calendar=this;
  th.appendChild (text);
  tr.appendChild (th);
  // predesly mesic
  th=document.createElement ('th');
  text=document.createTextNode ('‹');
  th.className=this.cssPrefix+'cal_monthbefore';
  th.onclick=last_Month;
  th.calendar=this;
  th.appendChild (text);
  tr.appendChild (th);
  // jmeno mesice
  th=document.createElement ('th');
  text=document.createTextNode (this.months[this.currentMonth]+' '+this.currentYear);
  th.colSpan='3';
  th.appendChild (text);
  tr.appendChild (th);
  // nasledujici mesic
  th=document.createElement ('th');
  text=document.createTextNode ('›');
  th.className=this.cssPrefix+'cal_monthafter';
  th.onclick=next_Month;
  th.calendar=this;
  th.appendChild (text);
  tr.appendChild (th);
  // nasledujici rok
  th=document.createElement ('th');
  text=document.createTextNode ('»');
  th.className=this.cssPrefix+'cal_yearafter';
  th.onclick=next_Year;
  th.calendar=this;
  th.onclick=next_Year;
  th.appendChild (text);
  tr.appendChild (th);
  // pripojit 1. radek hlavicky
  this.thead.appendChild (tr);
  tr=document.createElement ('tr');
  // dny v tydnu
  for (i=this.startingDay;i<7;i++) {
    th=document.createElement ('th');
    text=document.createTextNode (this.days[i]);
    th.appendChild (text);
    tr.appendChild (th);
  }
  for (i=0;i<this.startingDay;i++) {
    th=document.createElement ('th');
    text=document.createTextNode (this.days[i]);
    th.appendChild (text);
    tr.appendChild (th);
  }
  // pospojovani tabulky a vlozeni do tela stranky
  this.thead.appendChild (tr);
  this.calendar.appendChild (this.thead);
  this.calendar.appendChild (this.tbody);
  document.body.appendChild (this.calendar);
  this.redrawHeader ();
  this.drawMonth ();
}

/*
  Vykresluje aktualni mesic v aktualnim roce. Nikdy se nevola z programu,
  slouzi jen k vnitrnimu pouziti v ovladacich udalosti mysi.
*/
function draw_Month () {
  tbody=document.createElement ('tbody');
  a=0;
  dat=new Date(this.currentYear,this.currentMonth,1);
  for (i=0;i<this.daysCount[this.currentMonth];i++) {
    tr=document.createElement ('tr');
    volne=dat.getDay()-this.startingDay;
    if (volne<0) {
      volne=7+volne;
    }
    if (volne!=0 && i==0) {
      for (a=0;a<volne;a++) {
        td=document.createElement ('td');
        text=document.createTextNode (this.daysCount[this.lastMonth]-(volne-a-1));
        td.className=this.cssPrefix+'cal_outofmonth';
        td.appendChild (text);
        swap=this.dateFormat.replace ('d',this.daysCount[this.lastMonth]-(volne-a-1));
        swap=swap.replace ('m',(this.lastMonth+1));
        swap=swap.replace ('M',(this.months[this.lastMonth]));
        if (this.lastMonth==11) {
          swap=swap.replace ('Y',this.currentYear-1);
          aYear=this.currentYear-1;
        } else {
          swap=swap.replace ('Y',this.currentYear);
          aYear=this.currentYear;
        }
        td.title=swap;
        td.date=swap;
        td.day=this.daysCount[this.lastMonth]-(volne-a-1);
        td.month=this.lastMonth+1;
        td.year=aYear;
        td.calendar=this;
        td.onclick=day_Click;
        HoverElement (td,'onHover');
        if (this.iDayCounter!=0) {
          for (d=0;d<this.iDayCounter;d++) {
            if (this.importantDays[d].date.getFullYear()==aYear || this.importantDays[d].repeat) {
              if (this.importantDays[d].date.getMonth()==this.lastMonth) {
                if (this.importantDays[d].date.getDate()==this.daysCount[this.lastMonth]-(volne-a-1)) {
                  td.title+=" - "+this.importantDays[d].text;
                  td.className+=' '+this.cssPrefix+'cal_specialday';
                  if (this.importantDays[d].forbidden) {
                    td.onclick=null;
                    if (this.importantDays[d].text=='') {
                      td.className=this.cssPrefix+'cal_forbiddenday';
                      HoverElement (td,'cal_forbiddendayonHover');
                    }
                  }
                }
              }
            }
          }
        }
        tddate=new Date (td.year,td.month-1,td.day);
        if (this.startDate!=null) {
          if (tddate.getTime()<this.startDate.getTime()) {
            td.onclick=null;
            td.className=this.cssPrefix+'cal_forbiddenday';
            HoverElement (td,'cal_forbiddendayonHover');
          }
        }
        if (this.endDate!=null) {
          if (tddate.getTime()>this.endDate.getTime()) {
            td.onclick=null;
            td.className=this.cssPrefix+'cal_forbiddenday';
            HoverElement (td,'cal_forbiddendayonHover');
          }
        }
        tr.appendChild (td);
      }
    }
    while (a<7 && i<this.daysCount[this.currentMonth]) {
      td=document.createElement ('td');
      text=document.createTextNode (i+1);
      td.appendChild (text);
      swap=this.dateFormat.replace ('d',(i+1));
      swap=swap.replace ('m',(this.currentMonth+1));
      swap=swap.replace ('M',(this.months[this.currentMonth]));
      swap=swap.replace ('Y',this.currentYear);
      td.title=swap;
      td.date=swap;
      td.day=i+1;
      td.month=this.currentMonth+1;
      td.year=this.currentYear;
      if (a==(7-this.startingDay)%7) {
        td.className=this.cssPrefix+'cal_holiday';
      }
      if (this.datum.getDate()==(i+1) && this.datum.getFullYear()==this.currentYear && this.datum.getMonth()==this.currentMonth) {
        td.className+=' today';
      }
      td.calendar=this;
      td.onclick=day_Click;
      HoverElement (td,'onHover');
      if (this.iDayCounter!=0) {
        for (d=0;d<this.iDayCounter;d++) {
          if (this.importantDays[d].date.getFullYear()==this.currentYear || this.importantDays[d].repeat) {
            if (this.importantDays[d].date.getMonth()==this.currentMonth) {
              if (this.importantDays[d].date.getDate()==i+1) {
                td.title+=" - "+this.importantDays[d].text;
                td.className+=' '+this.cssPrefix+'cal_specialday';
                if (this.importantDays[d].forbidden) {
                  td.onclick=null;
                  if (this.importantDays[d].text=='') {
                    td.className=this.cssPrefix+'cal_forbiddenday';
                    HoverElement (td,'cal_forbiddendayonHover');
                  }
                }
              }
            }
          }
        }
      }
      tddate=new Date (td.year,td.month-1,td.day);
      if (this.startDate!=null) {
        if (tddate.getTime()<this.startDate.getTime()) {
          td.onclick=null;
          td.className=this.cssPrefix+'cal_forbiddenday';
          HoverElement (td,'cal_forbiddendayonHover');
        }
      }
      if (this.endDate!=null) {
        if (tddate.getTime()>this.endDate.getTime()) {
          td.onclick=null;
          td.className=this.cssPrefix+'cal_forbiddenday';
          HoverElement (td,'cal_forbiddendayonHover');
        }
      }
      tr.appendChild (td);
      a++;
      i++;
    }
    if (a<7) {
      for (x=6;x>a-1;x--) {
        td=document.createElement ('td');
        text=document.createTextNode (7-x);
        td.className=this.cssPrefix+'cal_outofmonth';
        td.appendChild (text);
        swap=this.dateFormat.replace ('d',(7-x));
        swap=swap.replace ('m',(this.nextMonth+1));
        swap=swap.replace ('M',(this.months[this.nextMonth]));
        if (this.nextMonth==0) {
          swap=swap.replace ('Y',this.currentYear+1);
          aYear=this.currentYear+1;
        } else {
          swap=swap.replace ('Y',this.currentYear);
          aYear=this.currentYear;
        }
        td.title=swap;
        td.date=swap;
        td.day=7-x;
        td.month=this.nextMonth+1;
        td.year=aYear;
        td.calendar=this;
        td.onclick=day_Click;
        HoverElement (td,'onHover');
        if (this.iDayCounter!=0) {
          for (d=0;d<this.iDayCounter;d++) {
            if (this.importantDays[d].date.getFullYear()==aYear || this.importantDays[d].repeat) {
              if (this.importantDays[d].date.getMonth()==this.nextMonth) {
                if (this.importantDays[d].date.getDate()==7-x) {
                  td.title+=" - "+this.importantDays[d].text;
                  td.className+=' '+this.cssPrefix+'cal_specialday';
                  if (this.importantDays[d].forbidden) {
                    td.onclick=null;
                    if (this.importantDays[d].text=='') {
                      td.className=this.cssPrefix+'cal_forbiddenday';
                      HoverElement (td,'cal_forbiddendayonHover');
                    }
                  }
                }
              }
            }
          }
        }
        tddate=new Date (td.year,td.month-1,td.day);
        if (this.startDate!=null) {
          if (tddate.getTime()<this.startDate.getTime()) {
            td.onclick=null;
            td.className=this.cssPrefix+'cal_forbiddenday';
            HoverElement (td,'cal_forbiddendayonHover');
          }
        }
        if (this.endDate!=null) {
          if (tddate.getTime()>this.endDate.getTime()) {
            td.onclick=null;
            td.className=this.cssPrefix+'cal_forbiddenday';
            HoverElement (td,'cal_forbiddendayonHover');
          }
        }
        tr.appendChild (td);
      }
    }
    tbody.appendChild (tr);
    a=0;
    i--;
  }
  if (this.todayEnabled) {
  tr=document.createElement ('tr');
  td=document.createElement ('td');
  td.colSpan='7';
  td.className=this.cssPrefix+'cal_bottom';
  text=document.createTextNode ('dnešní datum');
  td.appendChild (text);
  swap=this.dateFormat.replace ('d',this.datum.getDate());
  swap=swap.replace ('m',(this.datum.getMonth()+1));
  swap=swap.replace ('M',(this.months[this.datum.getMonth()]));
  swap=swap.replace ('Y',this.datum.getFullYear());
  td.title=swap;
  td.date=swap;
  td.day=this.datum.getDate();
  td.month=this.datum.getMonth()+1;
  td.year=this.datum.getFullYear();
  td.calendar=this;
  td.onclick=day_Click;
  HoverElement (td,'onHover');
  if (this.startDate!=null) {
    if (this.datum.getTime()<this.startDate.getTime()) {
      td.onclick=null;
      td.className=this.cssPrefix+'cal_forbiddenday';
      HoverElement (td,'cal_forbiddendayonHover');
    }
  }
  if (this.endDate!=null) {
    if (this.datum.getTime()>this.endDate.getTime()) {
      td.onclick=null;
      td.className=this.cssPrefix+'cal_forbiddenday';
      HoverElement (td,'cal_forbiddendayonHover');
    }
  }
  tr.appendChild (td);
  tbody.appendChild (tr);
  }
  this.calendar.replaceChild (tbody,this.tbody);
  this.tbody=tbody;
}

function HoverElement(node, className) {
  if (document.all) {
	if(!node.hovers) node.hovers = {};
	if(node.hovers[className]) return;
	node.hovers[className] = true;
	node.attachEvent('onmouseover',
		function() { node.className += ' ' + className; });
	node.attachEvent('onmouseout',
		function() { node.className = 
			node.className.replace((new RegExp('\\s+'+className)),''); });
	}
}

/*
  Upravuje hlavicku kalendare podle aktualnich hodnot mesice a roku. Opet neni
  k normalnimu uzivani v programu.
*/
function redraw_Header () {
  th=this.thead.firstChild.firstChild.nextSibling.nextSibling;
  text=document.createTextNode (this.months[this.currentMonth]+' '+this.currentYear);
  th.replaceChild (text,th.firstChild);
  tr=document.createElement ('tr');
  for (i=this.startingDay;i<7;i++) {
    th=document.createElement ('th');
    text=document.createTextNode (this.days[i]);
    th.appendChild (text);
    tr.appendChild (th);
  }
  for (i=0;i<this.startingDay;i++) {
    th=document.createElement ('th');
    text=document.createTextNode (this.days[i]);
    th.appendChild (text);
    tr.appendChild (th);
  }
  this.thead.replaceChild (tr,this.thead.firstChild.nextSibling);
}

/*
  Funkce, ktera se mapuje jako metoda objektu kalendar
  kalendar.show
  a zobrazuje kalendar.
*/
function show_Calendar () {
  this.calendar.style.display='block';
  this.calendar.style.zIndex='1';
  this.visible=true;
}

/*
  Funkce, ktera se mapuje jako metoda objektu kalendar
  kalendar.hide
  a skryva kalendar.
*/
function hide_Calendar () {
  this.calendar.style.display='none';
  this.visible=false;
}

function next_Month (e) {
  if (window.event) {
    obj=event.srcElement.calendar;
  } else {
    obj=e.currentTarget.calendar;
  }
  obj.lastMonth=obj.currentMonth;
  obj.currentMonth++;
  if (obj.currentMonth>11) {
	  obj.currentMonth=0;
	  obj.currentYear++;
	  obj.daysCount=new Array(31,28,31,30,31,30,31,31,30,31,30,31);
	  if (((obj.currentYear%4==0) && (obj.currentYear%100!=0)) || (obj.currentYear%400==0)) {
		  obj.daysCount[1]=29;
	  }
  }
  if (obj.currentMonth<11) {
	  obj.nextMonth=obj.currentMonth+1;
  } else {
    obj.nextMonth=0;
  }
  obj.redrawHeader();
  obj.drawMonth();
}

function last_Month (e) {
  if (window.event) {
    obj=event.srcElement.calendar;
  } else {
    obj=e.currentTarget.calendar;
  }
  obj.nextMonth=obj.currentMonth;
  obj.currentMonth--;
  if (obj.currentMonth<0) {
	  obj.currentMonth=11;
	  obj.currentYear--;
	  obj.daysCount=new Array(31,28,31,30,31,30,31,31,30,31,30,31);
	  if (((obj.currentYear%4==0) && (obj.currentYear%100!=0)) || (obj.currentYear%400==0)) {
		  obj.daysCount[1]=29;
	  }
  }
  if (obj.currentMonth>0) {
	  obj.lastMonth=obj.currentMonth-1;
  } else {
    obj.lastMonth=11;
  }
  obj.redrawHeader();
  obj.drawMonth();
}

function next_Year (e) {
  if (window.event) {
    obj=event.srcElement.calendar;
  } else {
    obj=e.currentTarget.calendar;
  }
  obj.currentYear++;
  obj.daysCount=new Array(31,28,31,30,31,30,31,31,30,31,30,31);
  if (((obj.currentYear%4==0) && (obj.currentYear%100!=0)) || (obj.currentYear%400==0)) {
	  obj.daysCount[1]=29;
	}
  obj.redrawHeader();
  obj.drawMonth();
}

function last_Year (e) {
  if (window.event) {
    obj=event.srcElement.calendar;
  } else {
    obj=e.currentTarget.calendar;
  }
  obj.currentYear--;
  obj.daysCount=new Array(31,28,31,30,31,30,31,31,30,31,30,31);
  if (((obj.currentYear%4==0) && (obj.currentYear%100!=0)) || (obj.currentYear%400==0)) {
	  obj.daysCount[1]=29;
	}
  obj.redrawHeader();
  obj.drawMonth();
}

function attach_Input (elem) {
  this.inputElement=elem;
  par=elem.parentNode;
  par.replaceChild (this.calendar,this.inputElement);
  par.insertBefore (this.inputElement,this.calendar);
}

function attach_Inputs (day,month,year) {
  this.inputElements.day=day;
  this.inputElements.month=month;
  this.inputElements.year=year;
  par=day.parentNode;
  par.replaceChild (this.calendar,this.inputElements.day);
  par.insertBefore (this.inputElements.day,this.calendar);
}

function day_Click (e) {
  if (window.event) {
    obj=event.srcElement.calendar;
    obj.save (event.srcElement.day,event.srcElement.month,event.srcElement.year);
  } else {
    obj=e.currentTarget.calendar;
    obj.save (e.currentTarget.day,e.currentTarget.month,e.currentTarget.year);
  }
}

/*
  Implicitni funkce, ktera se vola pri zvoleni data. Je mozno ji prehrat
  jinou funkci, takze se vlastne prepise metoda daneho objektu kalendare.
  Jako parametr musi kazda takova nahradni funkce brat retezec, ve kterem
  je ulozeno zvolene datum v preddefinovanem formatu.
*/
function save_Date (d,m,y) {
  if (this.inputElement!=null) {
    swap=this.dateFormat.replace ('d',d);
    swap=swap.replace ('m',m);
    swap=swap.replace ('M',(this.months[m]));
    swap=swap.replace ('Y',y);
    this.inputElement.value=swap;
  }
  if (this.inputElements.day!=null) {
    this.inputElements.day.value=d;
  }
  if (this.inputElements.month!=null) {
    this.inputElements.month.value=m;
  }
  if (this.inputElements.year!=null) {
    this.inputElements.year.value=y;
  }
  if (this.popup) {
    this.hide();
  }
}

function set_Starting_Day (day) {
  this.startingDay=day;
  this.redrawHeader();
  this.drawMonth();
}

function set_Day_Names (daynam) {
  this.days=daynam;
  this.redrawHeader();
  this.drawMonth();
}

function set_Month_Names (monthnam) {
  this.months=monthnam;
  this.redrawHeader();
  this.drawMonth();
}

function set_End_Date (day,month,year) {
  this.endDate=new Date (year,month-1,day);
  this.redrawHeader();
  this.drawMonth();
}

function set_Start_Date (day,month,year) {
  this.startDate=new Date (year,month-1,day);
  this.redrawHeader();
  this.drawMonth();
}

function add_Special_Day (forbidden,repeat,reminder,day,month,year) {
  this.importantDays[this.iDayCounter]=new ImDay (forbidden,repeat,reminder,day,month,year);
  this.iDayCounter++;
  this.drawMonth();
}

function set_today_enabled (enabled) {
  this.todayEnabled=enabled;
  this.drawMonth();
}

function attach_calendar (element) {
  element.appendChild (this.calendar);
}
