/* ----------------------------------------------------------------------------- */

function CalendarCoord(element)
{
    this.x = element.offsetLeft;
    this.y = element.offsetTop;
    while (element.offsetParent != null)
    {
        element = element.offsetParent;
        this.x += element.offsetLeft;
        this.y += element.offsetTop;
    }
}

/* ----------------------------------------------------------------------------- */

function CalendarPopup()
{
    this.visible = false;
    this.panel = document.createElement('DIV');
    this.panel.className = 'CalendarPopup';
    document.body.insertBefore(this.panel, document.body.firstChild);
}

CalendarPopup.prototype.showPanel = function(calendar)
{
    this.selected_date = new Date(calendar.value.getTime());
    this.displayed_date = new Date(calendar.value.getTime());
    coord = new CalendarCoord(calendar.input);
    this.panel.style.left = coord.x;
    this.panel.style.top = coord.y + 24;
    this.panel.style.visibility = 'visible';
    this.visible = true;
    this.showMonth();
}

CalendarPopup.prototype.hidePanel = function()
{
    this.panel.style.visibility = 'hidden';
    this.visible = false;
}

CalendarPopup.prototype.showMonth = function()
{
    this.panel.innerHTML = this.getHTML();
}

CalendarPopup.prototype.incMonth = function(increment)
{
    new_year = this.displayed_date.getFullYear();
    new_month = this.displayed_date.getMonth() + increment;
    if (new_month < 0)
    {
        new_year--;
        new_month = 11;
    }
    else
    if (new_month > 11)
    {
        new_year++;
        new_month = 0;
    }
    this.displayed_date.setYear(new_year);
    this.displayed_date.setMonth(new_month);
    this.showMonth();
}

CalendarPopup.prototype.getWeekCount = function(date)
{
    date.setDate(1);
    year = date.getFullYear();
    month = date.getMonth();
    first_day = date.getDay();
    day_count = 0;
    if (first_day != 1)
    {
        day_count = (date.getDay() == 0) ? 6 : first_day - 1;
        date.setDate(date.getDate() - day_count);
    }
    if (month == 1)
        day_count += ((year % 4) && (year % 100)) ? 28 : 29;
    else
        day_count += ((month == 3) || (month == 5) || (month == 8) || (month == 10)) ? 30 : 31;
    week_count = Math.ceil(day_count / 7);
    return week_count;
}

CalendarPopup.prototype.getHTML = function()
{
    displayed_date = new Date(this.displayed_date.getTime());
    displayed_month =  displayed_date.getMonth();
    displayed_year = displayed_date.getFullYear(); 
    week_count = this.getWeekCount(displayed_date);
    innerHTML = '';
    innerHTML += '<table cellspacing="0" class="Calendar">';
    // >> header
    innerHTML += '<tr class="HeaderPanel">';
    innerHTML += '<th class="LinkBack">';
    innerHTML += '<a href="javascript: void incMonth(-1)">&lt;</a>';
    innerHTML += '</th>';
    innerHTML += '<th class="CurrentMonth" colspan="5">';
    innerHTML += month_names[displayed_month] + ' ' + displayed_year;
    innerHTML += '</th>';
    innerHTML += '<th class="LinkForward">';
    innerHTML += '<a href="javascript: void incMonth(1)">&gt;</a>';
    innerHTML += '</th>';
    innerHTML += '</tr>';
    // << header
    // >> week days
    innerHTML += '<tr class="DaysPanel">';
    for (i = 0; i < day_names.length; i++)
        innerHTML += '<td>' + day_names[i] + '</td>';
    innerHTML += '</tr>';
    // << week days
    // >> month days
    for (i = 0; i < week_count; i++)
    {
        innerHTML += '<tr>';
        for (j = 0; j < 7; j++)
        {
            year = displayed_date.getFullYear();
            month = displayed_date.getMonth();
            day = displayed_date.getDate();
            display_str = (day <= 9) ? '0' + day : day;
            if (month < displayed_month)
                class_name = 'PrevMonth';
            else
            if (month > displayed_month)
                class_name = 'NextMonth';
            else
            if (displayed_date.getTime() == this.selected_date.getTime())
                class_name = 'CurrentDay';
            else
                class_name = '';
            innerHTML += '<td class="' + class_name + '">';
            innerHTML += '<a href="javascript: void applyDate(' + year + ', ' + month + ', ' + day + ')">' + display_str + '</a>';
            innerHTML += '</td>';
            displayed_date.setDate(day + 1);
        }
        innerHTML += '</tr>';
    }
    // << month days
    innerHTML += '<tr><td colspan="7" class="FooterPanel">';
    innerHTML += '<input type="button" value="' + button_today + '" onclick="currentDate()">';
    innerHTML += '&nbsp;';
    innerHTML += '<input type="button" value="' + button_colse + '" onclick="hideCalendar()">';
    innerHTML += '</td></tr>';
    innerHTML += '</table>';
    return innerHTML;
}

/* ----------------------------------------------------------------------------- */

function CalendarForm(id, name, x, y, form, controls)
{
    this.id = id;
    this.name = name;
    this.coord_x = x;
    this.coord_y = y;
    this.form = form;
    this.controls = controls.split(',');
    // find input
    element_id = this.id + '_Input';
    this.input = document.getElementById(element_id);
    if (!this.input)
        this.raiseError('Text input not found', element_id);
    // find button
    element_id = this.id + '_Button';
    this.button = document.getElementById(element_id);
    if (!this.button)
        this.raiseError('Button not found', element_id);
    // assign value
    this.value = new Date();
    if (this.input.value)
    {
        with (this.input.value)
        {
            var start_year = calendar_format.indexOf('yyyy');
            var start_month = calendar_format.indexOf('mm');
            var start_day = calendar_format.indexOf('dd');
            year = substring(start_year, start_year + 4);
            month = substring(start_month, start_month + 2) - 1;
            day = substring(start_day, start_day + 2);
        }
        this.value.setYear(year);
        this.value.setMonth(month);
        this.value.setDate(day);
    }
}

CalendarForm.prototype.raiseError = function(message, debug_value)
{
    throw new Error('Error in calendar <' + this.id + '>\r\n' + message + ' <' + debug_value + '>');
}

CalendarForm.prototype.setDisabled = function(value)
{
    this.input.disabled = value;
    this.button.disabled = value;
}

CalendarForm.prototype.parseDate = function()
{
    parts = this.input.value.split('.');
    if (parts.length != 3)
        return;
    year = eval(parts[0]);
    month = eval(parts[1]) - 1;
    day = eval(parts[2]);
    if ((year > 0) && (month >= 0) &&  (month <= 11) && (day >= 1) && (day <= 31))
    {
        this.value.setYear(year);
        this.value.setMonth(month);
        this.value.setDate(day);
    }
}

CalendarForm.prototype.applyDate = function(year, month, day)
{
    this.value.setYear(year);
    this.value.setMonth(month);
    this.value.setDate(day);
    month++;
    if (month <= 9) month = '0' + month;
    if (day <= 9) day = '0' + day;
    var value = calendar_format;
    value = value.replace(/yyyy/, year);
    value = value.replace(/mm/, month);
    value = value.replace(/dd/, day);
    this.input.value = value;
    if (this.input.onchange)
        this.input.onchange();
}

CalendarForm.prototype.currentDate = function()
{
    date = new Date();
    year = date.getFullYear();
    month = date.getMonth();
    day = date.getDate();
    this.applyDate(year, month, day);
    //calendar_popup.showPanel(this);
}

CalendarForm.prototype.changeControls = function(visibility)
{
    for (i = 0; i < this.controls.length; i++)
    {
        control = this.form[this.controls[i]];
        if (control)
            control.style.visibility = visibility;
    }
}

CalendarForm.prototype.hideControls = function()
{
    this.changeControls('hidden');
}

CalendarForm.prototype.showControls = function()
{
    this.changeControls('visible');
}

/* ----------------------------------------------------------------------------- */

function incMonth(increment)
{
    if (current_calendar)
    {
        calendar_popup.incMonth(increment);
    }
}

function applyDate(year, month, day)
{
    if (current_calendar)
    {
        current_calendar.applyDate(year, month, day);
        hideCalendar();
    }
}

function currentDate()
{
    current_calendar.currentDate();
    hideCalendar();
}

/* ----------------------------------------------------------------------------- */

calendar_forms = new Array();
current_calendar = null;
calendar_popup = null;

function findCalendar(id)
{
    result = null;
    for (i = 0; i < calendar_forms.length; i++)
        if (calendar_forms[i].id == id)
        {
            result = calendar_forms[i];
            break;
        }
    if (!result)
        throw new Error('Calendar <' + id + '> not found');
    return result;
}

function addCalendar(id, name, x, y, form, controls)
{
    item_count = calendar_forms.length;
    if (item_count == 0)
        calendar_popup = new CalendarPopup();
    item_count++;
    calendar_forms.length = item_count;
    calendar_forms[item_count - 1] = new CalendarForm(id, name, x, y, form, controls);
}

function setCalendarDisabled(id, value)
{
    calendar = findCalendar(id);
    if (calendar)
        calendar.setDisabled(value)
}

function showCalendar(id)
{
    current_id = (current_calendar) ? current_calendar.id : null;
    hideCalendar();
    if (current_id != id)
    {
        current_calendar = findCalendar(id);
        if (current_calendar)
        {
            current_calendar.hideControls();
            current_calendar.parseDate();
            calendar_popup.showPanel(current_calendar);
            setTimeout('setEvents()', 1000);
        }
    }
}

function hideCalendar()
{
    if (current_calendar)
    {
        current_calendar.hideControls();
        current_calendar = null;
    }
    if (calendar_popup.visible)
    {
        window.onresize = null;
//        document.body.onclick = null;
        calendar_popup.hidePanel();
    }
}

function setEvents()
{
    if (calendar_popup.visible)
    {
        window.onresize = hideCalendar;
//        document.body.onclick = hideCalendar;
    }
}

/* ----------------------------------------------------------------------------- */

