/******************************************************************************
 * Kalendarz Amin.pl                                                          *
 *                                                                            *
 * Wersja 2.0, Wymaga: Prototype                2008-11-14 © InSee Sp. z o.o. *
 ******************************************************************************/

/**
 * "Przesunięcie" aktualnie wyświetlanego miesiąca
 */
var currentMonth = 0;

var Calendar = {
    /**
     * Funkcja dodająca kalendarz do pola formularza
     * @param {Object} element obiekt pola formularza
     */
    add : function(element) {
        this._addDiv(element);
        this.setPosition(element);
        this._addCalendarObservers(element);
    },
    
    /**
     * Funkcja ustawiająca pozycję kalendarza względem elementu do którego jest przypisany (wywoływać przy zdarzeniu Focus)
     * @param {Object} element
     */
    setPosition : function(element) {
        var calDiv = $(element.name + '_calendar_div');
        if (!calDiv) {
            this.add(element);
            return;
        }
        calDiv.className = 'calendar_div';
        if (!Prototype.Browser.IE) {
            var posX = element.offsetLeft;
            var posY = Number(element.offsetTop + element.offsetHeight + 2);
            calDiv.style.top = posY + 'px';
            calDiv.style.left = posX + 'px';
        }
    },
    
    /**
     * Funkcja dodająca kontenery dla kalendarzy
     * @param {Object} element input do którego dodajemy kalendarz
     */
    _addDiv : function(element) {
        var calDiv = document.createElement('div');
        
        calDiv.id = element.name + '_calendar_div';
        calDiv.style.display = 'none';
        element.up('label').insert({after: calDiv});
        
        calDiv.innerHTML = '<div id="' + element.name + '_calendar_month1" class="calendar_left_div"></div>'
                               + '<div id="' + element.name + '_calendar_month2" class="calendar_right_div"></div>'
                               + '<p class="calendar_close">zamknij</p>';
        delete(calDiv);
    },
    
    _updateCalendars : function(element, scroll) {
        this.setPosition(element);
        var calDivLeft = $(element.name + '_calendar_month1');
        var calDivRight = $(element.name + '_calendar_month2');
        if (scroll) {
            calDivLeft.innerHTML = this._generateCalendar(calDivLeft, this._strToDate(element.value), false, scroll);
            calDivRight.innerHTML = this._generateCalendar(calDivRight, this._strToDate(element.value), true, scroll);
        } else {
            calDivLeft.innerHTML = this._generateCalendar(calDivLeft, this._strToDate(element.value));
            calDivRight.innerHTML = this._generateCalendar(calDivRight, this._strToDate(element.value), true);
        }
        this._addDaysObservers(element, calDivLeft.id);
        this._addDaysObservers(element, calDivRight.id);
    },
    
    /**
     * Generuje kod XHTML kalendarza w podanym elemencie w zależnosci od podanej daty
     * @param {Object} element kontener kalendarza
     * @param {Object} date obiekt Date z zaznaczoną datą
     * @param {boolean} next czy generowany jest następny miesiąc (tzn. "prawy")
     * @param {Int} scroll o ile miesięcy przesunąć
     */
    _generateCalendar : function(element, date, next, scroll) {
        var xhtml = '';
        var currentDate = new Date(date);
        date.setDate(1);
        date.setHours(0);
        date.setMinutes(0);
        date.setSeconds(0);
        date.setMilliseconds(0);
        
        if (next) {
            date.setMonth(date.getMonth() + 1);
            currentDate = new Date(date);
        }
        
        if (scroll) {
            date.setMonth(date.getMonth() + scroll);
            currentDate = new Date(date);
        }
        
        (next) ? xhtml += this._addCalendarHeading(element.id, date, true) : xhtml += this._addCalendarHeading(element.id, date);
        if (scroll) {
            if (scroll != 0) {
                (next) ? xhtml += this._addCalendarBody(element.id, date, currentDate, true, scroll) : xhtml += this._addCalendarBody(element.id, date, currentDate, false, scroll);
            } else {
                (next) ? xhtml += this._addCalendarBody(element.id, date, currentDate, true) : xhtml += this._addCalendarBody(element.id, date, currentDate);
            }
        } else {
            (next) ? xhtml += this._addCalendarBody(element.id, date, currentDate, true) : xhtml += this._addCalendarBody(element.id, date, currentDate);
        }
        
        return xhtml; 
    },
    
    _addCalendarHeading : function(name, date, next) {
        var tableStart = '<table><thead><tr><th class="calendar_weekday">Pn</th><th class="calendar_weekday">Wt</th><th class="calendar_weekday">Śr</th><th class="calendar_weekday">Cz</th><th class="calendar_weekday">Pt</th><th class="calendar_weekday">So</th><th class="calendar_weekday">Nd</th></tr></thead>';
        if (next) {
            return '<p class="calendar_month">' + this._months[date.getMonth()] + ' ' + date.getFullYear() + '<img class="calendar_next" src="' + basePath + '/images/next.gif" alt="Następny" id="' + name + '_next"/></p>' + tableStart;
        } else {
            var today = new Date();
            var m = today.getMonth() + 1;
            if (Math.floor(m/10) == 0) {
                m = '0' + m;
            }
            var tmy = today.getFullYear() + '' + m;
            m = date.getMonth() + 1;
            if (Math.floor(m/10) == 0) {
                m = '0' + m;
            }
            var dmy = date.getFullYear() + '' + m;
            if (parseInt(tmy) < parseInt(dmy)) {
                return '<p class="calendar_month"><img class="calendar_previous" src="' + basePath + '/images/previous.gif" alt="Poprzedni" id="' + name + '_previous"/>' + this._months[date.getMonth()] + ' ' + date.getFullYear() + '</p>' + tableStart;
            } else {
                return '<p class="calendar_month">' + this._months[date.getMonth()] + ' ' + date.getFullYear() + '</p>' + tableStart;
            }
        }
    },
    
    /**
     * Dodaje dni do kalendarza
     * @param {string} name nazwa kontenera kalendarza
     * @param {Object} date data wpisana w polu input
     * @param {Object} current aktualna da
     * @param {boolean} next czy miesiąc "po prawej"
     * @param {int} scroll względny miesiąc (2: dwa miesiące w przód, -2: dwa miesiące wstecz)
     */
    _addCalendarBody : function(name, date, current, next, scroll) {
        var xhtml = '<tbody>';
        var today = new Date();
        
        if (date.getDay() != 1) {
            if (!next) {
                xhtml += this._addPreviousMonthDays(date);
            } else {
                xhtml += this._addPreviousMonthDays(date, true);
            }
        }
        
        var minDate = this._getMinDate(name);

        while (date.getMonth() == current.getMonth()) {
            if (date.getDay() == 1) {
                xhtml += '<tr>';
            }
            
            var className = '';
            var title = this._dateToStr(date);
            
            if (date < minDate) {
                title = '';
                className += 'calendar_inactive';
            } else if (date.getDate() == current.getDate() && date.getMonth() == current.getMonth() && date.getFullYear() == current.getFullYear() && !next && !scroll) {
                className += ' calendar_selected';
            } else {
                if (date.getDay() == 0) {
                    className += ' calendar_active_sunday'; 
                } else {
                    className += ' calendar_active';
                }
            }
            
            xhtml += '<td title="' + title + '" class="' + className + '">' + date.getDate() + '</td>';
            
            if (date.getDay() == 0) {
                xhtml += '</tr>';
            }
            
            date.setDate(date.getDate() + 1);
        }
        
        date.setDate(date.getDate() - 1);
        if (date.getDay() != 0) {
            if (next) {
                xhtml += this._addNextMonthDays(date);
            } else {
                xhtml += this._addNextMonthDays(date, true);
            }
        }
        
        return xhtml + '</tbody></table>';
    },
    
    /**
     * Dodaje "szare" dni z poprzedniego miesiąca
     * @param {Object} date
     * @param {Object} empty
     */
    _addPreviousMonthDays : function (date, empty) {
        var firstDay = 7 - ((7 - date.getDay()) % 7);
        var xhtml = '<tr>';
        
        for (i = 1; i < firstDay; i++) {
            if (empty) {
                xhtml += '<td />';
            } else {
                tmpDate = new Date(date);
                tmpDate.setDate(tmpDate.getDate() - firstDay + i);
                xhtml += '<td class="calendar_other_month">' + tmpDate.getDate() + '</td>';
            }
        }
        
        return xhtml;
    },
    
    /**
     * Dodaje "szare" dni z następnego miesiąca
     * @param {Object} date
     * @param {Object} empty
     */
    _addNextMonthDays : function (date, empty) {
        var lastDay = 7 - ((7 - date.getDay()) % 7);
        var xhtml = '';
        
        c = 1;
        for (i = lastDay + 1; i <= 7; i++) {
            if (empty) {
                xhtml += '<td />';
            } else {
                tmpDate = new Date(date);
                tmpDate.setDate(tmpDate.getDate() + c);
                xhtml += '<td class="calendar_other_month">' + tmpDate.getDate() + '</td>';
            }
            c++;
        }
        
        return xhtml + '</tr>';
    },
    
    /**
     * Zwraca minimalną datę dla danego pola, która może zostać w nim wybrana
     * @param {Object} id
     */
    _getMinDate : function(id) {
        var name = id.substring(0, 11);
        
        var r1 = $(this._r1);
        var d1 = $(this._d1);
        var d2 = $(this._d2);
        var d3 = $(this._d3);
        
        var minDate;
        
        switch (name) {
            case this._d1 : minDate = new Date(); break;
            case this._d2 : minDate = this._strToDate(d1.value); break;
            case this._d3 : minDate = this._strToDate(d2.value); break;
            case this._d4 : minDate = this._strToDate(d3.value); break;
            case this._r1 : minDate = this._strToDate(d1.value);
        }
        minDate.setHours(0);
        minDate.setMinutes(0);
        minDate.setSeconds(0);
        minDate.setMilliseconds(0);
        
        return minDate;
    },
    
    /**
     * Sprawdza datę w danym polu i w zależności od zawartości zmienia ją w wybranym i innych polach 
     * @param {Object} input pole daty
     */
    _validateAndUpdate : function(input) {
        var name = input.id;
        var today = new Date();
        var todayString = this._dateToStr(today);
        
        if (input.value.length == 10) {
            var inputDate = this._strToDate(input.value);
        } else {            
            input.value = todayString;
        }
        
        if (!inputDate || isNaN(inputDate) || inputDate == 'Invalid Date') {
            input.value = todayString;
            inputDate = new Date(today);
        }
        
        var r1 = $(this._r1);
        var d1 = $(this._d1);
        var d2 = $(this._d2);
        var d3 = $(this._d3);
        var d4 = $(this._d4);
        
        if (inputDate < today)
            input.value = todayString;
        var inputString = this._dateToStr(inputDate);
        
        switch (name) {
            case 'departing_1' :
                if (r1) 
                    if (this._strToDate(r1.value) < inputDate)
                        r1.value = inputString;
                if (d2) 
                    if (this._strToDate(d2.value) < inputDate)
                        d2.value = inputString;
                if (d3) 
                    if (this._strToDate(d3.value) < inputDate) 
                        d3.value = inputString;
                if (d4) 
                    if (this._strToDate(d4.value) < inputDate) 
                        d4.value = inputString;
                break;
            case 'departing_2' :
                if (d2) 
                    if (inputDate < this._strToDate(d1.value)) 
                        d2.value = d1.value;
                if (d3) 
                    if (this._strToDate(d3.value) < inputDate) 
                        d3.value = inputString;
                if (d4) 
                    if (this._strToDate(d4.value) < inputDate) 
                        d4.value = inputString;
                break;
            case 'departing_3' :
                if (d3) 
                    if (inputDate < this._strToDate(d2.value)) 
                        d3.value = d2.value;
                if (d4) 
                    if (this._strToDate(d4.value) < inputDate) 
                        d4.value = inputString;
                break;
            case 'departing_4' :
                if (d4) 
                    if (inputDate < this._strToDate(d3.value)) 
                        d4.value = d3.value;
                break;
            case 'returning_1' :
                if (r1) 
                    if (inputDate < this._strToDate(d1.value)) 
                        r1.value = d1.value;
                break;
        }
    },
    
    /**
     * Dodaje obserwatory dla dni miesiąca
     * @param {Object} element komórka tabeli reprezentująca dzień miesiąca
     */
    _addDaysObservers : function(element, id) {
        var calDiv = $(element.id + '_calendar_div');
        var prevBtn = $(id + '_previous');
        var nextBtn = $(id + '_next');
        if (prevBtn) {
            Event.observe(prevBtn, 'click', function(event) {
                currentMonth--;
                Calendar._updateCalendars(element, currentMonth);
            });
        }
        if (nextBtn) {
            Event.observe(nextBtn, 'click', function(event){
                currentMonth++;
                Calendar._updateCalendars(element, currentMonth);
            });
        }
        calDiv.descendants('td[title]').each(function(elem) {
            if (elem.title) {
                Event.observe(elem, 'click', function(event) {
                    element.value = elem.title;
                    Calendar._hideElement(calDiv);
                    Calendar._validateAndUpdate(element);
                });            
            }
        });
    },
    
    /**
     * Dodaje obserwatory dla całego kalendarza i inputa (focus, blur, change itp.)
     */
    _addCalendarObservers : function(element) {
        var calDiv = $(element.name + '_calendar_div');
        
        if (calDiv) {
            Event.observe(element, 'focus', function(event) {
                element.activate();
                Calendar._hideAllCalendars();
                Calendar._showElement(calDiv);
                Calendar._updateCalendars(element);
                currentMonth = 0;
            });
            
            Event.observe(element, 'blur', function(event) {
                Calendar._validateAndUpdate(element);
                Calendar._hideElement(calDiv);
            });
            
            Event.observe(element, 'change', function(event) {
                Calendar._validateAndUpdate(element);
            });
            
            Event.observe(element.name + '_calendar_icon', 'click', function(event) {
                if (calDiv.hasClassName('puste') || calDiv.style.display == 'none') {
                    Calendar._hideAllCalendars();
                    Calendar._showElement(calDiv);
                    Calendar._updateCalendars(element);
                    currentMonth = 0;
                } else {
                    Calendar._hideElement(calDiv);
                }
            });
            
            Event.observe(calDiv.down('p[class="calendar_close"]'), 'click', function(event) {
                Calendar._hideElement(calDiv);
            });
            
            Event.observe(calDiv, 'mouseover', function(event) {
                element.stopObserving('blur');
            });
            Event.observe(calDiv, 'mouseout', function(event) {
                Event.observe(element, 'blur', function(event) {
                    Calendar._validateAndUpdate(element);
                    Calendar._hideElement(calDiv);
                });
            });
        }
    },
    
    /**
     * Ukrywa wszystkie widoczne kalendarze
     */
    _hideAllCalendars : function() {
        $$('div[id$="_calendar_div"]').each(function(element) {
            Calendar._hideElement(element.id);
        });
    },
    
    /**
     * Pokazuje element
     * @param {String} id
     */
    _showElement : function(id) {
        var element = $(id);
        if (element) {
            element.removeClassName('puste');
            element.show();
        }
    },
    
    /**
     * Ukrywa element
     * @param {Object} element
     */
    _hideElement : function(id) {
        var element = $(id);
        if (element) {
            element.addClassName('puste');
            element.hide();
        }
    },
    
    /**
     * Konwertuje stringa do obiektu Date, w przypadku gdy jest nieprawidłowy zwraca aktualną datę
     * @param {String} string łańcuch postaci dd/mm/rrrr
     * @return {Object} Date
     */
    _strToDate : function(string) {
        var date = new Date();

        if (string.length == 10) {
            var day = Number(string.substr(0, 2));
            var month = Number(string.substr(3, 2));
            var year = Number(string.substr(6, 4));
            
            try {
                date.setFullYear(year);
                date.setMonth(month - 1);
                date.setDate(day);
                date.setHours(0);
                date.setMinutes(0);
                date.setSeconds(0);
                date.setMilliseconds(0);
            } catch (e) {
                return new Date();
            }
        }
        return date;
    },
    
    /**
     * Konwertuje obiekt Date do stringa
     * @param {Object} date
     * @return {String}
     */
    _dateToStr : function(date) {
        var day = date.getDate() + '';
        
        var string;
        
        (day.length == 1) ? string = '0' + day : string = day;
        
        string += '/';
        
        var month = Number(date.getMonth() + 1) + '';
        
        (month.length == 1) ? string += '0' + month : string += month;
        
        string += '/' + date.getFullYear();
        
        return string;
    },
    
    /**
     * @var {array} Dni tygodnia odpowiadające wartościom 1-Pn, 7-Nd
     */
    _days : ['', 'Pn', 'Wt', 'Śr', 'Cz', 'Pt', 'So', 'Nd'],
    
    /**
     * @var {array} Nazwy miesięcy odpowiadające cyfrom obiektu Date
     */
    _months : ['Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec',
              'Lipiec', 'Sierpień', 'Wrzesień', 'Październik', 'Listopad', 'Grudzień'],

    /**
     * @var {String} nazwa inputa z datą wylotu - lot 1
     */
    _d1 : 'departing_1',
    
    /**
     * @var {String} nazwa inputa z datą wylotu - lot 2
     */
    _d2 : 'departing_2',
    
    /**
     * @var {String} nazwa inputa z datą wylotu - lot 3
     */
    _d3 : 'departing_3',
    
    /**
     * @var {String} nazwa inputa z datą wylotu - lot 4
     */
    _d4 : 'departing_4',
    
    /**
     * @var {String} nazwa inputa z datą powrotu - lot 1
     */
    _r1 : 'returning_1',
    
    _currentMonth : 0
}