// Global variables
var ZCounter = 100;


function MonthObj(adate, dateTime) {
    this.picked = adate ? adate : new Date();
    this.weekStartsWith = 1;
    this.firstDate = null;
    this.firstWeekDay = null;
    this.yearValue = null;
    this.monthIndex = null;
    this.monthName = null;
    this.fullName = null;
    this.dayCount = null;
    this.today = new Date();

    this.setFirstDate = function(date) {
        this.firstDate = new Date(date.getFullYear(), date.getMonth(), 1);
        this.firstWeekDay = this.firstDate.getDay();
        this.yearValue = this.firstDate.getFullYear();
        this.monthIndex = this.firstDate.getMonth();
        this.monthName = dateTime.i18n.monthNames[this.monthIndex];
        this.fullName = this.monthName + ' ' + this.yearValue;
        this.dayCount = dateTime.getDayCount(this.yearValue, this.monthIndex);
    };

    this.setPicked = function(adate) {
        this.picked = adate ? adate : new Date();
        this.setFirstDate(this.picked);
    };

    this.previous = function() {
        this.setFirstDate(new Date(this.firstDate.getFullYear(), this.firstDate.getMonth() - 1, 1));
    };

    this.next = function() {
        this.setFirstDate(new Date(this.firstDate.getFullYear(), this.firstDate.getMonth() + 1, 1));
    };

    this.setFirstDate(adate);
}


function CalendarObj(readFieldId, readFieldPattern, writeFieldId, writeFieldPattern, dummySpan) {
    // Parameter
    this.dateTime = DateTime;
    this.weekStartsWith = 1;
    this.hideTimeout = 3500;

  // Created Elements
    this.calendarSpan = null;
    this.monthNameTd = null;
    this.daysSpan = null;
    this.prevTd = null;
    this.nextTd = null;

    var dayStyleClasses = ['su', 'mo', 'tu', 'we', 'th', 'fr', 'sa'];

    this.timer = null;

    this.initMonth = function() {
        var input = $(readFieldId).value;
        var date = this.dateTime.parseDate(readFieldPattern, input);

        this.month = new MonthObj(new Date(), this.dateTime);
        this.month.weekStartsWith = this.weekStartsWith;
        this.month.setPicked(date);
        this.update();
    };

    this.previous = function() {
        this.month.previous();
        this.update();
        this.resetTimer();
    };

    this.next = function() {
        this.month.next();
        this.update();
        this.resetTimer();
    };

    this.update = function() {
        if (this.monthNameTd) {
            this.monthNameTd.update(this.dateTime.formatDate("MMMM yyyy", this.month.firstDate));
        }

        if (this.daysSpan) {
            this.daysSpan.update(this.buildDays());
        }
    };

    this.hide = function() {
        if (this.calendarSpan) {
            this.calendarSpan.parentNode.removeChild(this.calendarSpan);
            this.calendarSpan = null;
        }

        if (this.onHide) {
            this.onHide();
        }

        this.stopTimer();
    };

    this.datePicked = function() {
        var output = $(writeFieldId);
        if (output) {
            output.value = this.dateTime.formatDate(writeFieldPattern, this.month.picked);
        }

        this.hide();
    };

    this.pickDay = function(day) {
        this.month.setPicked(new Date(this.month.firstDate.getFullYear(), this.month.firstDate.getMonth(), day));
        this.datePicked();
    };

    this.resetTimer = function() {
        this.stopTimer();
        this.timer = setTimeout(this.hide.bind(this), this.hideTimeout);
    };

    this.stopTimer = function() {
        if (this.timer) {
            clearTimeout(this.timer);
        }
    };


    this.buildHead = function() {

        this.calendarSpan = ElementCommon.addChild(null, 'span',
                ['class', 'calendar']);

        var headTable = this.calendarSpan.addChild('table',
                ['class', 'head', 'cellpadding', 0, 'cellspacing', 0]);

        var navTable = headTable.addChild('tr', ['class', 'nav']).
                addChild('td', ['colspan', 7]).
                addChild('table', ['cellpadding', 0, 'cellspacing', 0]);

        var navRow = navTable.addChild('tr');

        this.prevTd = navRow.addChild('td', ['class', 'nav-prev']).update('&lt;');
        this.prevTd.onclick = this.previous.bind(this);
        this.prevTd.onmouseover = this.resetTimer.bind(this);

        this.monthNameTd = navRow.addChild('td');
        this.monthNameTd.onmouseover = this.resetTimer.bind(this);

        this.nextTd = navRow.addChild('td', ['class', 'nav-next']).update('&gt;');
        this.nextTd.onclick = this.next.bind(this);
        this.nextTd.onmouseover = this.resetTimer.bind(this);

        var weekElem = headTable.addChild('tr', ['class', 'weekdays']);

        for (var w = 0; w < 7; w++) {
            var dayIndex = (w + this.weekStartsWith) % 7;

            var dayElem = weekElem.addChild('td', ['class',
                dayStyleClasses[dayIndex]]).update(this.dateTime.i18n.weekDaysOne[dayIndex]);
            dayElem.onmouseover = this.resetTimer.bind(this);
        }

        this.daysSpan = this.calendarSpan.addChild('span', ['class', 'days']);

        var dummy = $(dummySpan);
        if (dummy) {
            dummy.appendChild(this.calendarSpan);
        }
    };


    this.buildDays = function () {

        var daysInFirstRow = 7 - (7 + this.month.firstWeekDay - this.weekStartsWith) % 7;

        daysInFirstRow = daysInFirstRow === 0 ? 7 : daysInFirstRow;

        var rows = 1 + Math.ceil((this.month.dayCount - daysInFirstRow) / 7);

        var tableElem = document.createElement('table');
        tableElem.setAttribute('cellspacing', 0);
        tableElem.setAttribute('cellpadding', 0);

        var Day = daysInFirstRow - 7;

        for (var j = 0; j < rows; j++) {
            var trElem = document.createElement('tr');
            tableElem.appendChild(trElem);

            var weekdayClass = null;

            for (var i = 1; i <= 7; i++) {
                Day++;

                weekdayClass = dayStyleClasses[(this.weekStartsWith + i - 1) % 7];

                var tdElem = document.createElement('td');
                trElem.appendChild(tdElem);

                var dayClass = '';

                if ((Day >= 1) && (Day <= this.month.dayCount)) {
                    if ((this.month.yearValue == this.month.picked.getFullYear()) &&
                        (this.month.monthIndex == this.month.picked.getMonth()) &&
                        (Day == this.month.picked.getDate())) {
                        dayClass += ' picked';
                    }

                    if ((this.month.yearValue == this.month.today.getFullYear()) &&
                        (this.month.monthIndex == this.month.today.getMonth()) &&
                        (Day == this.month.today.getDate())) {
                        dayClass += ' today';
                    }

                    tdElem.setAttribute('class', weekdayClass + ' input' + dayClass);
                    tdElem.onclick = function(e) {
                        var elem = Event.element(e);
                        this.pickDay(elem.textContent);
                    }.bind(this);

                    tdElem.onmouseover = this.resetTimer.bind(this);

                    tdElem.appendChild(document.createTextNode(Day));
                } else {
                    tdElem.setAttribute('class', weekdayClass + ' blank');
                    tdElem.onclick = this.hide.bind(this);
                    tdElem.appendChild(document.createTextNode('\u00a0'));
                }
            }
        }
        return tableElem;
    };


    this.show = function() {
        this.initMonth();
        this.buildHead();
        this.update();

        if (this.calendarSpan) {
            // this.fixSelects(true);
            this.calendarSpan.style.zIndex = ++ZCounter;
            this.calendarSpan.style.visibility = 'visible';
            this.resetTimer();
        }
    };
}

var calendarSingleton = null;

function createCalendar(fieldid, datepattern, dummySpan) {
    if (calendarSingleton) {
        return;
    }

    var calendar = new CalendarObj(fieldid, datepattern, fieldid, datepattern, dummySpan);
    calendarSingleton = calendar;

    calendar.onHide = function() {
        calendarSingleton = null;
    };

    calendar.show();
}