/* Скрипт написан Жарковым Н.Н.  
  Скрипт встраивает в страницу календарь и если указанно то выводит дату в
  приемник, которым может служить поле для ввода текста или любой объект имеющий
  свойство innerHTML, например: div, span, h1 и т.д.
  Возможна смена расцветки, размера календаря и выбор языка */

var 
  // nameMonth - массив содержащий названия месяцев на русском и английском языках

  nameMonth = new Array("Январь","Февраль","Март","Апрель","Май","Июнь",
                        "Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь",
                        "January","February","March","April","May","June",
                        "July","August","September","October","November","December"),
  // nameDay - массив содержащий сокращения названий дней на русском и английском языках

  nameDay   = new Array("Пн","Вт","Ср","Чт","Пт","Сб","Вс",
                        "Mo","Tu","We","Th","Fr","Sa","Su"),
  // sunDays - массив содержащий праздничные дни

  sunDays   = new Array(new Array(3,1,2,7),new Array(1,23),new Array(1,8),
                        new Array(0),new Array(3,1,2,9),new Array(1,12),
                        new Array(0),new Array(0),new Array(0),
                        new Array(0),new Array(1,7),new Array(1,12)),
  // dayMonth - массив содержащий количество дней по месяцам

  dayMonth  = new Array(31,28,31,30,31,30,31,31,30,31,30,31),
  // cal - массив содержащий все календари встроенные в страницу

  cal       = new Array(),
  // checked - флаг указывающий на возможность встраивания календарей в страницу

  checked   = -1;      

 // function checkBrowser() 

 // Функция проверяет броузер на некоторые функциональные возможности и если

 // броузер чего либо не поддерживает, то календаря не будет.

 function checkBrowser()
 {
   checked = 0;
   if(document && document.write && document.getElementById && document.body && document.body.innerHTML)
   {
     document.write("<span id=\"caltest\" class=\"caltest\"></span>");
     var t = document.getElementById("caltest");
     if(t && t.className)
       { check = true; checked = 1 }    
   }
 }

/* function calendarSetColor()
   передаваемые параметры:
   name           - идентификатор календаря
   mainSizeText   - размер шрифта
   mainColor      - основной цвет календаря
   mainColorLight - основной цвет "освещенных" границ
   mainColorDark  - основной цвет "затемненных" границ
   mainColorText  - основной цвет текста
   clickColor     - цвет выбранной даты (ячейки)
   clickColorText - цвет текста выбранной даты (ячейки)
   satColor       - цвет суббот
   satColorLight  - цвет "освещенных" границ суббот 
   satColorDark   - цвет "затемненных" границ суббот
   sunColor       - цвет воскресений и праздников,
   sunColorLight  - цвет "освещенных" границ воскресений
   sunColorDark   - цвет "затемненных" границ воскрессений

 Функция устанавливает стили для каждого календаря в отдельности, что делает
 возможным одновременное нахождение календарей разных цветов на одной странице.
 Если цвета не установлены цвет календаря определяется по умолчанию.
 Если цвет первого календаря установлен, а цвет последующих нет, цвет последующих
 будет соответствовать цвету первого. 
 При установке цвета не обязательно задавать все параметры
 Цвет может быть задан тремя способами : #FFFFFF, rgb(255,255,255), white. */

function calendarSetColor(name, mainSizeText,
                          mainColor, mainColorLight, mainColorDark, mainColorText,
                          clickColor, clickColorText,
                          satColor, satColorLight, satColorDark,
                          sunColor, sunColorLight, sunColorDark)
{
  if(!checked) return;
  if(checked<0) checkBrowser();

  var i, c=-1, st="";

  if((c=findCalendar(name))<0) return;

  cal[c].mc = mainColor ? mainColor : (c>0 ? cal[0].mc : "#CACACA");
  cal[c].mcl= mainColorLight ? mainColorLight : (c>0 ? cal[0].mcl : "#FFF");
  cal[c].mcd= mainColorDark ? mainColorDark : (c>0 ? cal[0].mcd : "#505050");
  cal[c].mct= mainColorText ? mainColorText : (c>0 ? cal[0].mct : "#000");
  cal[c].mst= parseInt(mainSizeText) ? mainSizeText : 10;
  cal[c].cc = clickColor ? clickColor : (c>0 ? cal[0].cc : "#000090");
  cal[c].cct= clickColorText ? clickColorText : (c>0 ? cal[0].cct : "#FFF");
  cal[c].ac = satColor ? satColor : (c>0 ? cal[0].ac : "#FFA0A0");
  cal[c].acl= satColorLight ? satColorLight : (c>0 ? cal[0].acl : "#FFE0E0");
  cal[c].acd= satColorDark ? satColorDark : (c>0 ? cal[0].acd : "#500000");
  cal[c].uc = sunColor ? sunColor : (c>0 ? cal[0].uc : "#FF5050");
  cal[c].ucl= sunColorLight ? sunColorLight : (c>0 ? cal[0].ucl : "#FFA0A0");
  cal[c].ucd= sunColorDark ? sunColorDark : (c>0 ? cal[0].ucd : "#500000");
  cal[c].setcolor = 1;

  // Установка стилей календаря производится путем установки классов для 

  // ячеек таблицы. Возможно это не очень хорошее решение, но это 

  // имеет свои преимущества например: не надо проверять цвета, т.е. если вы

  // задали цвет не верно, то стиль просто будет игнорирован, ошибки JavaScript

  // выдаваться не будут

  st += "<style rel=\"stylesheet\" type=\"text/css\">";
  st += " .c"+c+"tabu { cursor: default; background-color:"+cal[c].mc+"; border:1px solid; border-color:"+cal[c].mcl+" "+cal[c].mcd+" "+cal[c].mcd+" "+cal[c].mcl+";}";
  st += " .c"+c+"tabd { border:1px solid; border-color:"+cal[c].mcd+" "+cal[c].mcl+" "+cal[c].mcl+" "+cal[c].mcd+"; font: "+cal[c].mst+"pt Verdana, arial, sans-serif; color:"+cal[c].mct+";}";
  st += " .c"+c+"u    { border:1px solid; border-color:"+cal[c].mcl+" "+cal[c].mcd+" "+cal[c].mcd+" "+cal[c].mcl+";}";
  st += " .c"+c+"d    { border:1px solid; border-color:"+cal[c].mcd+" "+cal[c].mcl+" "+cal[c].mcl+" "+cal[c].mcd+";}";
  st += " .c"+c+"cl   { background-color:"+cal[c].cc+"; border:1px solid "+cal[c].cc+"; color:"+cal[c].cct+";}";
  st += " .c"+c+"sau  { background-color:"+cal[c].ac+"; border:1px solid; border-color:"+cal[c].acl+" "+cal[c].acd+" "+cal[c].acd+" "+cal[c].acl+";}";
  st += " .c"+c+"sad  { background-color:"+cal[c].ac+"; border:1px solid; border-color:"+cal[c].acd+" "+cal[c].acl+" "+cal[c].acl+" "+cal[c].acd+";}";
  st += " .c"+c+"suu  { background-color:"+cal[c].uc+"; border:1px solid; border-color:"+cal[c].ucl+" "+cal[c].ucd+" "+cal[c].ucd+" "+cal[c].ucl+";}";
  st += " .c"+c+"sud  { background-color:"+cal[c].uc+"; border:1px solid; border-color:"+cal[c].ucd+" "+cal[c].ucl+" "+cal[c].ucl+" "+cal[c].ucd+";}";
  st += " .c"+c+"no   { border:1px solid "+cal[c].mc+";}";
  st += "</style>";

  document.write(st);
}

/* function calendarSetOut()
   передаваемые параметры:
   name         - идентификатор календаря
   out_id       - id объекта которому будет передана дата
   cal_type     - вид выдаваемой даты 
                  возможно: 0- цифры, 1- с названием месяца

 Функция определяет существование объекта которому следует передавать дату.
 Если функция на вызавалась календарь дату никуда отсылать не будет */

function calendarSetOut(name, out_id, cal_type)
{
  if(!checked) return;
  if(checked<0) checkBrowser();

  var out = document.getElementById(out_id), c=-1, i;

  for(i=0; i<cal.length; i++)
    if(cal[i].name == name) { c = i; break; }

  if(!name || !out || c<0) return;

  cal[c].out = out;
  cal[c].prop = out.nodeName=="INPUT" ? "value" : "innerHTML";
  cal[c].type = cal_type ? 1 : 0;

  outdate(c);
}

/* function calendarInit()
   передаваемые параметры:
   name     - идентификатор календаря
   width    - ширина календаря
   height   - высота календаря
   language - язык на котором календарь отображается
              возможно: "rus"- русский, "eng"- английский

 Функция создает календарь и устанавливает обработчики событий.
 Повторный вызов функции для одного итого-же календаря не возможен.
*/

function calendarInit(name, width, height, language, nextmon)
{
  if(!checked) return;
  if(checked<0) checkBrowser();

  var st="", h, w, i, j, c=-1, dat = new Date();                

  if((c=findCalendar(name))<0) return;

  if(!cal[c].setcolor) calendarSetColor(name);
  else if(cal[c].last) return;

  cal[c].last = 0;
  cal[c].day  = dat.getDate();
  cal[c].month= dat.getMonth()+1;
  if (nextmon == 1)
  {
	  cal[c].month++;
  }
  cal[c].year = dat.getYear();
  
  cal[c].lang = language=="eng"?1:0;

  if(window.navigator.appName != "Microsoft Internet Explorer" && window.navigator.appName != "Opera") 
    cal[c].year += 1900;
  else 
    if(cal[c].year < 100) cal[c].year += 1900;

  w = parseInt(width/7);
  width = w*7;
  h = parseInt((height-11)/9);
  height = h*9+10;

  st += "<table class=c"+c+"tabu cellspacing=2 cellpadding=0 width="+width+" height="+height+">";
  st += "<tr><td>";
    st += "<table class=c"+c+"tabd cellspacing=0 cellpadding=0 width=100% height="+(h*2)+"><tr>";
      st += "<th id=_"+c+"0 class=c"+c+"u style=\"visibility: hidden\">&lt;&lt;&lt;</th>";
      st += "    <th id=_"+c+"1 class=c"+c+"u style=\"visibility: hidden\">&lt;&lt;</th>";
      st += "    <th id=_"+c+"2 class=c"+c+"u >&lt;</th>";
      st += "    <th id=_"+c+"year class=c"+c+"u>&nbsp;</th>";
      st += "    <th id=_"+c+"3 class=c"+c+"u>&gt;</th>";
      st += "    <th id=_"+c+"4 class=c"+c+"u style=\"visibility: hidden\">&gt;&gt;</th>";
      st += "    <th id=_"+c+"5 class=c"+c+"u style=\"visibility: hidden\">&gt;&gt;&gt;</th>";
      st += "</tr><tr><th id=_"+c+"6 class=c"+c+"u>&lt;</th>";
      st += "    <th id=_"+c+"month colspan=5 class=c"+c+"u>&nbsp;</th>";
      st += "    <th id=_"+c+"7 class=c"+c+"u>&gt;</th>";
    st += "</tr></table>";
  st += "</td></tr><tr><td>";
    st += "<table class=c"+c+"tabd cellspacing=0 cellpadding=0 width=100% height="+(h*7)+">";

      for(i=0; i<7; i++)
      {
        st += "<tr>";
        for(j=0; j<7; j++)
          if(i==0) st += "<th class=c"+c+"u width="+w+">"+nameDay[j+cal[c].lang*7]+"</th>";
          else st += "<td id=_"+c+((i-1)*7+j+8)+" align=center class=c"+c+"u>&nbsp;</td>";
        st += "</tr>";
      }

    st += "</table>";
  st += "</td></tr></table>";

  document.write(st);

  // установка обработчиков событий

  for(i=0; i<50; i++)
  {
    var o = document.getElementById("_"+c+i);
    o.onmouseover = eventHandler;
    o.onmouseout  = eventHandler;
    o.onclick     = eventHandler;
  }

  // отрисовка календаря

  showCalendar(c);
}

/* function showCalendar()
   передаваемые параметры:
   c - порядковый номер календаря в массиве календарей

 Функция производит расчет и отрисовывает календарь 
 (устанавливает ячейкам соответствующие стили).  
*/
 function showCalendar(c)
 {  
   var i,
       m = cal[c].month,
       y = cal[c].year,
       d = cal[c].day,
       fd, // первая ячейка календаря с которой начинается месяц

       dm; // количество дней в месяце


   // Проверка месяца на выход из диапазона [1..12]

   if(m == 0) { y--; m = 12 } else if(m == 13) { y++; m = 1 }

   // Проверка года на выход из диапазона [0..10000]

   if(y < 1) { y = 1; m = 1 } else if(y > 10000) { y = 10000; m = 12 }

   // Проверка на февраль високосного года

   if(m == 2 && !(y%4)) dm++;

   dm= dayMonth[m-1];
   // Проверка дня на выход из диапазона [0..dm]

   if(d < 1) d = 1; else if(d > dm) d = dm;

   // Расчет первой активной ячейки в календаре

   fd = y*365 + parseInt(y/4);
   for(i = 0; i < m-1; i++)  fd+= dayMonth[i];
   if(y%4 || (!(y%4) && m > 2)) fd++;
   fd += 5;
   fd = fd%7?fd%7:7;
      
   // Задание стилей для ячеек календаря

   for(i = 1; i < 43; i++)
     with(document.getElementById("_"+c+(i+7)))
     { 
       // если ячейка попадает в диапазон между [fd..fd+dm] она активна

       // в противном случае не активна

       if( i >= fd && i < fd + dm)
       {
         var sun = true, j;
         // проверка на празники

         for(j = 1; j < sunDays[m-1][0]+1; j++)
           if(i-fd+1 == sunDays[m-1][j])
           {
             className = "c"+c+"suu";
             sun = false;
             break;
           } 

         // проверка на остальные дни

         if(sun)
           switch(i%7)
           {
             case 0: className = "c"+c+"suu"; break; // субботы

             case 6: className = "c"+c+"sau"; break; // воскресения

             default: className = "c"+c+"u"; break;  // серые будни

           }
         // Запись в ячеку числа соответсивующего дню

         innerHTML = i-fd+1;
       }
       else
       {
         className = "c"+c+"no";
         innerHTML = "&nbsp;";
       }
     }

   // Установка в календарь текушей выбранной даты

   var o = document.getElementById("_"+c+(d+fd+6));
   o.className = "c"+c+"cl";
   // Изменение надписи года и месяца

   document.getElementById("_"+c+"year").innerHTML = y;
   document.getElementById("_"+c+"month").innerHTML = nameMonth[cal[c].lang*12+m-1];

   cal[c].last = o;
   cal[c].day  = d;
   cal[c].month= m;
   cal[c].year = y;

   // отправка установленной даты объекту приемнику

   outdate(c);
 }

/* function eventHandler()
   ЭТОЙ ФУНКЦИИ НИКАКИЕ ПАРАМЕТРЫ ПЕРЕДАВАТЬ НЕ ТРЕБУЕТСЯ

 Функция является обработчиком событий активных ячеек
 onmouseover, onmouseout, onclick */    
 function eventHandler(e)
 {
   // если броузер не IE то е содержит объект "событие", ну а если

   // броузер IE то этот объект window.event

   if(!e) e = event;

   // События установленны и на неактивные ячейки, но нам нельзя их обрабатывать

   var end = this.className.substr(this.className.length-2, 2);
   if(end != "no" && end != "cl")
   {
     var str = this.className.substr(0,this.className.length-1);

     // е.type - содержит тип произошедшего события

     switch(e.type)
     {
       // мышь наехала на ячейку

       case "mouseover": this.className= str+"d"; break;
       // как наехала так и съехала

       case "mouseout":  this.className= str+"u"; break;
       // злобный пользователь произвел нажатие по имени клик

       case "click":    
        var reshow = true, c=0, o=this;

        // определение от какого календаря произошло событие

        while(o.className.substr(o.className.length-4,4)!="tabu") o = o.parentNode;
        c = parseInt(o.className.substr(1,o.className.length-5));

        var m = cal[c].month,
            y = cal[c].year,
            d = cal[c].day,
            l = cal[c].last,
            st = "_"+c;

        // в зависимости от нажатой ячейки или скролингуем дату, или 

        // устанавливаем новую

        switch(this.id)
        {
          case st+0: y -= 100; break;
          case st+1: y -= 10; break;
          case st+2: y--; break;
          case st+3: y++; break;
          case st+4: y += 10; break;
          case st+5: y += 100; break;
          case st+6: m--; break;
          case st+7: m++; break;
          default:
           var  num = parseInt(l.id.substr(st.length, l.id.length-st.length))-7,
                sun = true, j;

           // старая зафиксированная ячейка должна вернуться в исходное положение

           for(j = 1; j < sunDays[m-1][0]+1; j++)
            if(d == sunDays[m-1][j])
            {
                l.className = "c"+c+"suu";
                sun = false;
                break;
            }

           if(sun)
            switch(num % 7)
            {
              case 0: l.className = "c"+c+"suu"; break;
              case 6: l.className = "c"+c+"sau"; break;
              default: l.className = "c"+c+"u"; break;
            }

            // ячейка на которой произошло событие фиксируется

            this.className = "c"+c+"cl";
            cal[c].day = parseInt(this.innerHTML);
            cal[c].last = this;
            reshow=false;

            // передача даты объекту приемнику

            outdate(c);
        }

        if(reshow)
        { 
          // перерисовка календаря требуется только при смене года и месяца

          cal[c].year = y;
          cal[c].month = m;
          showCalendar(c);
        }
        break;
     }
   }
 }

/* function findCalendar()
   передаваемые параметры:
   name - идентификатор календаря

 Функция по переданному идентификатору определяет порядковый номер календаря в 
 массиве. Если такого идентификатора нет создается новый календарь. 
 Вот только нафига? */

function findCalendar(name)
{
  var i, c=-1;
  if(name)
  {
    for(i=0; i<cal.length; i++)
      if(cal[i].name == name) { c = i; break; }

    if(c<0) { c = cal.length;   cal[c] = new Array(); cal[c].name = name; }
  }
  return c;
}

/* function outdate()
   передаваемые параметры:
   c - порядковай номер календаря в массиве календарей

 Функция передает установленную дату активного календаря свойству объекта приемника
*/

function outdate(c)
{
 // если объект "приемник" существует

 if(cal[c].out)
 {
   // Передадим красивую дату. Если установлено числовое отображение даты, 

   // то добавляются нули, там где требуется, а если отображение не числовое,

   // а текстовое, то в зависимости от языка (в руском, если мне не изменяет 

   // пямять:), есть такое понятие как склонение) название месяца выводится 

   // текстом.

   var dec = cal[c].type?" ":".",
       m = cal[c].month, d = cal[c].day,
       name = nameMonth[cal[c].lang*12+m-1];

   d = d>9?d:"0"+d;
   m = m>9?m:"0"+m;

   if(cal[c].lang) 
     m = cal[c].type?name:m;
   else
     m = cal[c].type?(m=="03"||m=="08"?name+"a":name.substr(0,name.length-1)+"я"):m;

   cal[c].out[cal[c].prop] = d+dec+m+dec+cal[c].year;
 }
}