var Datepicker = function(params){
    for (var i in params){
        if (typeof i != "function"){
            this[i] = params[i];
        }
    }
    this.prefix = "smarty_";
    this.borderName = this.prefix + this.name + "Border";
    this.dayName = this.prefix + this.name + "Day";
    this.monthName = this.prefix + this.name + "Month";
    this.yearName = this.prefix + this.name + "Year";
    this.buttonName = this.prefix + this.name + "Button";
    this.calendarName = this.prefix + this.name + "Calendar";
    this.headerName = this.prefix + this.name + "Header";
    this.monthLabelName = this.prefix + this.name + "MonthLabel";
    this.yearLabelName = this.prefix + this.name + "YearLabel";
    this.monthListName = this.prefix + this.name + "MonthList";
    this.yearListName = this.prefix + this.name + "YearList";
    this.cellName = this.prefix + this.name + "Cell";
    this.buttonFile = this.path + "/icon.gif";
    this.smallButtonFile = this.path + "/downarrow.gif";
    this.cssFile = this.path + "/style.css";
    this.assignFields(this.value);
    this.insertComponent();
    this.bindEvents();
}

Datepicker.create = function(params){
    Registry.objects[params.name] = new Datepicker(params);
    Popups.register(params.name);
}

Datepicker.prototype.bindEvents = function(){
    var instance = this;
    document.getElementById(this.buttonName).onclick = function(evt){
        instance.buttonClick(evt ? evt : event);
    }
    document.getElementById(this.dayName).onkeyup = function(evt){
        var keyCode = (evt ? evt : event).keyCode;
        if (keyCode == 38) {
            instance.nextDay(this.value);
        }
        else if (keyCode == 40){
            instance.prevDay(this.value);
        }
        instance.updateField();
    }
    document.getElementById(this.dayName).onchange = function(evt){
        instance.updateField();
    }
    document.getElementById(this.monthName).onkeyup = function(evt){
        var keyCode = (evt ? evt : event).keyCode;
        if (keyCode == 38) {
            instance.nextMonth(this.value);
        }
        else if (keyCode == 40){
            instance.prevMonth(this.value);
        }
        instance.updateField();
    }
    document.getElementById(this.monthName).onchange = function(evt){
        instance.updateField();
    }
    document.getElementById(this.yearName).onkeyup = function(evt){
        var keyCode = (evt ? evt : event).keyCode;
        if (keyCode == 38) {
            instance.nextYear(this.value);
        }
        else if (keyCode == 40){
            instance.prevYear(this.value);
        }
        instance.updateField();
    }
    document.getElementById(this.yearName).onchange = function(evt){
        instance.updateField();
    }
}

Datepicker.prototype.getMaxDay = function(){
    var year = parseInt(document.getElementById(this.yearName).value, 10);
    var month = parseInt(document.getElementById(this.monthName).value, 10);
    if (!isNaN(year) && !isNaN(month)) if (year >= this.minYear && year <= this.maxYear) if (month <= 12 && month >= 1){
        return 32 - new Date(year, month - 1, 32).getDate();
    }
    return 31;
}

Datepicker.prototype.prevDay = function(value){
    var day = parseInt(value, 10);
    var max = this.getMaxDay();
    var prevDay = isNaN(day) ? 1 : (day <= 1 ? 1 : (day > max ? max : day - 1));
    prevDay = prevDay < 10 ? "0" + prevDay : prevDay;
    document.getElementById(this.dayName).value = prevDay;
    document.getElementById(this.dayName).select();
}

Datepicker.prototype.nextDay = function(value){
    var day = parseInt(value, 10);
    var max = this.getMaxDay();
    var nextDay = isNaN(day) ? max : (day < 1 ? 1 : (day >= max ? max : day + 1));
    nextDay = nextDay < 10 ? "0" + nextDay : nextDay;
    document.getElementById(this.dayName).value = nextDay;
    document.getElementById(this.dayName).select();
}

Datepicker.prototype.prevMonth = function(value){
    var month = parseInt(value, 10);
    var prevMonth = isNaN(month) ? 1 : (month <= 1 ? 1 : (month > 12 ? 12 : month - 1));
    prevMonth = prevMonth < 10 ? "0" + prevMonth : prevMonth;
    document.getElementById(this.monthName).value = prevMonth;
    document.getElementById(this.monthName).select();
}

Datepicker.prototype.nextMonth = function(value){
    var month = parseInt(value, 10);
    var nextMonth = isNaN(month) ? 12 : (month < 1 ? 1 : (month >= 12 ? 12 : month + 1));
    nextMonth = nextMonth < 10 ? "0" + nextMonth : nextMonth;
    document.getElementById(this.monthName).value = nextMonth;
    document.getElementById(this.monthName).select();
}

Datepicker.prototype.prevYear = function(value){
    var year = parseInt(value, 10);
    var prevYear = isNaN(year) ? this.minYear : (year > this.maxYear ? this.maxYear : (year <= this.minYear ? this.minYear : year - 1));
    document.getElementById(this.yearName).value = prevYear;
    document.getElementById(this.yearName).select();
}

Datepicker.prototype.nextYear = function(value){
    var year = parseInt(value, 10);
    var nextYear = isNaN(year) ? this.maxYear : (year < this.minYear ? this.minYear : (year >= this.maxYear ? this.maxYear : year + 1));
    document.getElementById(this.yearName).value = nextYear;
    document.getElementById(this.yearName).select();
}

Datepicker.prototype.updateField = function(){
    var year = document.getElementById(this.yearName).value.replace("-", "");
    var month = document.getElementById(this.monthName).value.replace("-", "");
    var day = document.getElementById(this.dayName).value.replace("-", "");
    document.getElementById(this.name).value = year + "-" + month + "-" + day;
}

Datepicker.prototype.insertComponent = function(){
    var borderHtml = '<div id="' + this.borderName + '" style="z-index:1" class="datepicker">';
    var dayHtml = '<input type="text" maxlength="2" size="2" id="' + this.dayName + '" autocomplete="off" />';
    var monthHtml = '<input type="text" maxlength="2" size="2" id="' + this.monthName + '" autocomplete="off" />';
    var yearHtml = '<input type="text" maxlength="4" size="4" id="' + this.yearName + '" autocomplete="off" />';
    var fieldHtml = '<input type="hidden" name="' + this.name + '" id="' + this.name + '" />';
    var buttonHtml = '<img src="' + this.buttonFile + '" id="' + this.buttonName + '" />';
    var cssHtml = '<link rel="stylesheet" type="text/css" href="' + this.cssFile + '" />';
    var html = borderHtml + dayHtml + monthHtml + yearHtml + fieldHtml + buttonHtml + cssHtml + '</div>';
    document.write(html);
    document.getElementById(this.dayName).value = this.day;
    document.getElementById(this.monthName).value = this.month;
    document.getElementById(this.yearName).value = this.year;
    document.getElementById(this.buttonName).style.cursor = "pointer";
    document.getElementById(this.name).value = this.year + "-" + this.month + "-" + this.day;
    this.setVisualStyles();
}

Datepicker.prototype.setVisualStyles = function(){
    var buttonWidth = 17;
    var buttonHeight = 16;
    var space = 4;
    var oneFourthWidth = Math.round((this.width - buttonWidth - space) / 4);
    /* The next checking of document.all is required since opera and ie doesn't follow css specification
       and include borders into width and height for input controls. */
    var leftCorrection = document.all ? -1 : 0;
    var inputHeight = document.all ? this.height : this.height - 2;
    document.getElementById(this.borderName).style.position = "relative";
    document.getElementById(this.borderName).style.width = this.width + "px";
    document.getElementById(this.borderName).style.height = this.height + "px";
    document.getElementById(this.dayName).style.textAlign = "center";
    document.getElementById(this.monthName).style.textAlign = "center";
    document.getElementById(this.yearName).style.textAlign = "center";
    document.getElementById(this.dayName).style.position = "absolute";
    document.getElementById(this.dayName).style.left = "0px";
    document.getElementById(this.dayName).style.top = "0px";
    document.getElementById(this.dayName).style.width = oneFourthWidth + "px";
    document.getElementById(this.dayName).style.height = inputHeight + "px";
    document.getElementById(this.dayName).style.padding = "0px";
    document.getElementById(this.dayName).style.margin = "0px";
    document.getElementById(this.dayName).style.border = "1px solid " + this.borderColor;
    document.getElementById(this.monthName).style.position = "absolute";
    document.getElementById(this.monthName).style.left = oneFourthWidth + leftCorrection + "px";
    document.getElementById(this.monthName).style.top = "0px";
    document.getElementById(this.monthName).style.width = oneFourthWidth + "px";
    document.getElementById(this.monthName).style.height = inputHeight + "px";
    document.getElementById(this.monthName).style.padding = "0px";
    document.getElementById(this.monthName).style.margin = "0px";
    document.getElementById(this.monthName).style.border = "1px solid " + this.borderColor;
    document.getElementById(this.yearName).style.position = "absolute";
    document.getElementById(this.yearName).style.left = 2 * oneFourthWidth + 2 * leftCorrection + "px";
    document.getElementById(this.yearName).style.top = "0px";
    document.getElementById(this.yearName).style.width = this.width - buttonWidth - space - 2 * oneFourthWidth + "px";
    document.getElementById(this.yearName).style.height = inputHeight + "px";
    document.getElementById(this.yearName).style.padding = "0px";
    document.getElementById(this.yearName).style.margin = "0px";
    document.getElementById(this.yearName).style.border = "1px solid " + this.borderColor;
    document.getElementById(this.buttonName).style.position = "absolute";
    document.getElementById(this.buttonName).style.left = 4 * oneFourthWidth + 4 * leftCorrection + space + "px";
    document.getElementById(this.buttonName).style.top = Math.round((this.height - buttonHeight) / 2) + "px";
    this.calendarLeft = 4 * oneFourthWidth + 5 * leftCorrection + space + 1;
    this.calendarTop = Math.round((this.height - buttonHeight) / 2) + buttonHeight;
}

Datepicker.prototype.assignFields = function(value){
    var parts = value.split("-");
    this.day = parts.length < 3 ? "" : parts[2];
    this.month = parts.length < 3 ? "" : parts[1];
    this.year = parts.length < 3 ? "" : parts[0];
}

Datepicker.prototype.buttonClick = function(evt){
    Popups.hideAllButNotThis(this.name);
    document.getElementById(this.calendarName) ? this.hideCalendar() : this.showCalendar();
    evt.cancelBubble = true;
}

Datepicker.prototype.showCalendar = function(){
    if (document.getElementById(this.calendarName)){
        return;
    }
    this.year = document.getElementById(this.yearName).value;
    this.month = document.getElementById(this.monthName).value;
    var calendar = document.createElement("div");
    var button = document.getElementById(this.buttonName);
    calendar.id = this.calendarName;
    calendar.style.left = this.calendarLeft + "px";
    calendar.style.top = this.calendarTop + "px";
    calendar.style.position = "absolute";
    calendar.className = this.prefix + "calendar";
    var instance = this;
    calendar.onclick = function(evt){
        instance.hideMonthList();
        instance.hideYearList();
        (evt ? evt : event).cancelBubble = true;
    }
    this.createHeader(calendar);
    this.createTable(calendar);
    Selects.hide();
    document.getElementById(this.borderName).style.zIndex = 5;
    button.offsetParent.appendChild(calendar);
    this.fill();
}

/* Wrapper for popup manager */
Datepicker.prototype.hide = function(){
    this.hideCalendar();
}

Datepicker.prototype.hideCalendar = function(){
    var calendar = document.getElementById(this.calendarName);
    if (calendar){
        Selects.show();
        document.getElementById(this.borderName).style.zIndex = 1;
        calendar.parentNode.removeChild(calendar);
    }
}

Datepicker.prototype.createHeader = function(calendar){
    var header = document.createElement("div");
    header.className = this.prefix + "calendar_header";
    header.id = this.headerName;
    this.createMonthSelect(header);
    this.createYearSelect(header);
    this.createCloseButton(header);
    calendar.appendChild(header);
}

Datepicker.prototype.createMonthSelect = function(header){
    var select = document.createElement("div");
    select.id = this.monthLabelName;
    select.className = this.prefix + "calendar_month";
    select.style.position = "absolute";
    select.innerHTML = this.months[this.getCalendarMonth()];
    header.appendChild(select);
    var button = document.createElement("img");
    button.src = this.smallButtonFile;
    button.style.position = "absolute";
    button.className = this.prefix + "calendar_month_button";
    var instance = this;
    button.onclick = function(evt){
        instance.monthButtonClick(evt ? evt : event);
    }
    header.appendChild(button);
}

Datepicker.prototype.monthButtonClick = function(evt){
    this.hideYearList();
    document.getElementById(this.monthListName) ? this.hideMonthList() : this.showMonthList();
    evt.cancelBubble = true;
}

Datepicker.prototype.showMonthList = function(){
    if (document.getElementById(this.monthListName)){
        return;
    }
    var list = document.createElement("div");
    list.id = this.monthListName;
    list.className = this.prefix + "calendar_month_list";
    var instance = this;
    for (var i = 0; i < 12; i ++){
        var item = document.createElement("div");
        item.innerHTML = this.months[i];
        item.key = i;
        item.onmouseover = function(){
            this.className = "over";
        }
        item.onmouseout = function(){
            this.className = "";
        }
        item.onclick = function(){
            instance.month = this.key + 1;
            instance.year = instance.getCalendarYear();
            instance.hideMonthList();
            instance.fill();
        }
        list.appendChild(item);
    }
    document.getElementById(this.headerName).appendChild(list);
}

Datepicker.prototype.hideMonthList = function(){
    var list = document.getElementById(this.monthListName);
    if (list){
        list.parentNode.removeChild(list);
    }
}

Datepicker.prototype.createYearSelect = function(header){
    var select = document.createElement("div");
    select.id = this.yearLabelName;
    select.className = this.prefix + "calendar_year";
    select.style.position = "absolute";
    select.innerHTML = this.getCalendarYear();
    header.appendChild(select);
    var button = document.createElement("img");
    button.src = this.smallButtonFile;
    button.style.position = "absolute";
    button.className = this.prefix + "calendar_year_button";
    var instance = this;
    button.onclick = function(evt){
        instance.yearButtonClick(evt ? evt : event);
    }
    header.appendChild(button);
}

Datepicker.prototype.yearButtonClick = function(evt){
    this.hideMonthList();
    document.getElementById(this.yearListName) ? this.hideYearList() : this.showYearList();
    evt.cancelBubble = true;
}

Datepicker.prototype.showYearList = function(){
    if (document.getElementById(this.yearListName)){
        return;
    }
    var list = document.createElement("div");
    list.id = this.yearListName;
    list.className = this.prefix + "calendar_year_list";
    var instance = this;
    for (var i = this.minYear; i <= this.maxYear; i ++){
        var item = document.createElement("div");
        item.innerHTML = i;
        item.key = i;
        item.onmouseover = function(){
            this.className = "over";
        }
        item.onmouseout = function(){
            this.className = "";
        }
        item.onclick = function(){
            instance.year = this.key;
            instance.month = instance.getCalendarMonth() + 1;
            instance.hideYearList();
            instance.fill();
        }
        list.appendChild(item);
    }
    document.getElementById(this.headerName).appendChild(list);
}

Datepicker.prototype.hideYearList = function(){
    var list = document.getElementById(this.yearListName);
    if (list){
        list.parentNode.removeChild(list);
    }
}

Datepicker.prototype.createCloseButton = function(header){
    var close = document.createElement("div");
    close.className = this.prefix + "calendar_close";
    close.style.cursor = "pointer";
    close.innerHTML = "[x]";
    var instance = this;
    close.onclick = function(){
        instance.hideCalendar();
    }
    header.appendChild(close);
}

Datepicker.prototype.createTable = function(calendar){
    var table = document.createElement("table");
    table.cellSpacing = 0;
    var tbody = document.createElement("tbody");
    var tr = document.createElement("tr");
    for (var i = 0; i < 7; i ++){
        var th = document.createElement("th");
        th.innerHTML = this.days[(i + this.first) % 7];
        tr.appendChild(th);
    }
    tbody.appendChild(tr);
    for (var i = 0; i < 6; i ++){
        tr = document.createElement("tr");
        for (var j = 0; j < 7; j ++){
            var td = document.createElement("td");
            td.id = this.cellName + (j + 7 * i);
            td.innerHTML = "&nbsp;";
            td.onmouseover = function(){
                this.className = "over";
            }
            td.onmouseout = function(){
                this.className = "";
            }
            tr.appendChild(td);
        }
        tbody.appendChild(tr);
    }
    table.appendChild(tbody);
    calendar.appendChild(table);
}

Datepicker.prototype.fill = function(){
    var year = this.getCalendarYear();
    var month = this.getCalendarMonth();
    document.getElementById(this.monthLabelName).innerHTML = this.months[month];
    document.getElementById(this.yearLabelName).innerHTML = year;
    var first = new Date(year, month, 1).getDay();
    var days = 32 - new Date(year, month, 32).getDate();
    var diff = (first - this.first) % 7;
    diff = diff == -1 ? 6 : diff;
    var instance = this;
    for (var i = 0; i < diff; i ++){
        while (document.getElementById(this.cellName + i).firstChild){
            document.getElementById(this.cellName + i).removeChild(document.getElementById(this.cellName + i).firstChild);
        }
        document.getElementById(this.cellName + i).style.cursor = "default";
        document.getElementById(this.cellName + i).onclick = null;
    }
    var day = 1;
    for (var i = diff; i < diff + days; i ++){
        while (document.getElementById(this.cellName + i).firstChild){
            document.getElementById(this.cellName + i).removeChild(document.getElementById(this.cellName + i).firstChild);
        }
        document.getElementById(this.cellName + i).appendChild(document.createTextNode(day));
        document.getElementById(this.cellName + i).style.cursor = "pointer";
        day ++;
        document.getElementById(this.cellName + i).onclick = function(){
            instance.selectDate(parseInt(this.innerHTML, 10));
        }
    }
    for (var i = diff + days; i < 42; i ++){
        while (document.getElementById(this.cellName + i).firstChild){
            document.getElementById(this.cellName + i).removeChild(document.getElementById(this.cellName + i).firstChild);
        }
        document.getElementById(this.cellName + i).style.cursor = "default";
        document.getElementById(this.cellName + i).onclick = null;
    }
}

Datepicker.prototype.getCalendarMonth = function(){
    var todayMonth = new Date().getMonth();
    var month = parseInt(this.month, 10);
    return isNaN(month) ? todayMonth : (month < 1 || month > 12 ? todayMonth : month - 1);
}

Datepicker.prototype.getCalendarYear = function(){
    var todayYear = new Date().getFullYear();
    var year = parseInt(this.year, 10);
    return isNaN(year) ? todayYear : (year < this.minYear || year > this.maxYear ? todayYear : year);
}

Datepicker.prototype.selectDate = function(day){
    var year = this.getCalendarYear();
    document.getElementById(this.yearName).value = this.getCalendarYear();
    var month = this.getCalendarMonth() + 1;
    month = month < 10 ? "0" + month : month;
    document.getElementById(this.monthName).value = month;
    day = day < 10 ? "0" + day : day;
    document.getElementById(this.dayName).value = day;
    document.getElementById(this.name).value = year + "-" + month + "-" + day;
    this.hideCalendar();
}

Datepicker.prototype.leftCorrections = function(instance){
    var marginLeft = !window.opera && document.all ? instance.offsetParent.currentStyle.marginLeft : 0;
    var borderLeft = !window.opera && document.all ? instance.offsetParent.currentStyle.borderLeftWidth : document.defaultView.getComputedStyle(instance.offsetParent, null).getPropertyValue("border-left-width");
    marginLeft = "0" + marginLeft;
    borderLeft = "0" + borderLeft;
    return parseInt(marginLeft, 10) + parseInt(borderLeft, 10);
}

Datepicker.prototype.topCorrections = function(instance){
    var marginTop = !window.opera && document.all ? instance.offsetParent.currentStyle.marginTop : 0;
    var borderTop = !window.opera && document.all ? instance.offsetParent.currentStyle.borderTopWidth : document.defaultView.getComputedStyle(instance.offsetParent, null).getPropertyValue("border-top-width");
    marginTop = "0" + marginTop;
    borderTop = "0" + borderTop;
    return parseInt(marginTop, 10) + parseInt(borderTop, 10);
}
