/*
 *  Copyright Malyshev Alex, 2007
 *  Flexites Ltd.
 *  ------------------------------------------------------------------------------
 *  Ajax DHTML Calendar Module
 *  FCalendar object module
 *  flex-calendar.js
 *
 *  Properties list to FCalendar.setup()
 *  -----------------+------------------------------------------------------------
 *   name            |          descritption
 *  -----------------+------------------------------------------------------------
 *   date            | the date that the calendar will be initially displayed to
 *   eventName       | event that will trigger calendar (default: 'click')
 *   onSelect        | function that gets called when date selected
 *   DOMcontainer    | ID of the calendar container
 *   showOthers      | show days from another months (default: 'false')
 *  -----------------+------------------------------------------------------------
 *   ajaxCheck       | checking disabled dates with ajax request (default: false)
 *   ajaxRequest     | request string for the ajax request
 *  -----------------+------------------------------------------------------------
 *
 */

FCalendar = function(DOMcontainer, date, ajaxCheck, ajaxRequest) { 
    var self = this;
    // constructor
    this.DOMcontainer = DOMcontainer;
    this.date = new Date();
    this.today = new Date();
    if (date) { this.date.setTime(date); }
    this.trigerEventName = 'click';
    this.checkedDates = {};
    this.ajaxCheckType = null;
    this.disabled = false;
    // DOM elements
    this.DOMtable = null;
    this.DOMtitle = null;
    // constants
    this.MINYEAR = 1970;
    this.MAXYEAR = 2030;
    // Ajax request
    this.ajaxCheck = ajaxCheck;
    this.ajaxRequest = ajaxRequest;
    if (this.ajaxCheck) {
        this.getTransport();
        if ((!this.request)||(!this.ajaxRequest)) {
            this.ajaxCheck = false; 
        } else {
            this.requestUrl = ajaxRequest;
            this.requestParamString = '';
            if (this.requestUrl.match(/^(.*?)\?(.*)/)) {
                this.requestUrl = RegExp.$1;
                this.requestParamString = RegExp.$2;
            }
        }
    }
}

FCalendar.prototype = {
    draw: function() {
        var self = this;
        var table = FCalendar.$new({tag: 'table', cellSpacing: 0}, this.DOMcontainer);
        if (table.addEventListener) {
            table.addEventListener('mousedown', cancelSelection, true);
        }
        var thead = FCalendar.$new({tag: 'thead'}, table);
        var titleRow = FCalendar.$new({tag: 'tr'}, thead);
        this.DOMtitle = FCalendar.$new({tag: 'td', className: 'title', colSpan: 7}, titleRow);
        this.updateTitle();
        tmpPrevMonth = function() { self.gotoDMonth(-1); }
        tmpNextMonth = function() { self.gotoDMonth(+1); }
        tmpPrevYear = function() { self.gotoDYear(-1); }
        tmpNextYear = function() { self.gotoDYear(+1); }
        var btnsRow = FCalendar.$new({tag: 'tr', className: 'headrow'}, thead);
        var pyb = FCalendar.$new({tag: 'td', className: 'nav button', title: FCalendar._STR["PREV_YEAR"],
                        onmouseover: setHover, onmouseout: unsetHover, onmousedown: setMouseDown,
                        onclick: tmpPrevYear,
                        text: FCalendar.$char(171)}, btnsRow);
        FCalendar.$attachEvent(pyb, 'mousedown', function() { self.timeoutPopupMenu('years', this, -1); });
        var pmb = FCalendar.$new({tag: 'td', className: 'nav button', title: FCalendar._STR["PREV_MONTH"],
                        onmouseover: setHover, onmouseout: unsetHover, onmousedown: setMouseDown,
                        onclick: tmpPrevMonth,
                        innerHTML: FCalendar.$char(8249)}, btnsRow);
        FCalendar.$attachEvent(pmb, 'mousedown', function() { self.timeoutPopupMenu('months', this); });
        FCalendar.$new({tag: 'td', className: 'button', title: FCalendar._STR["TO_TODAY"],
              onmouseover: setHover, onmouseout: unsetHover, onmousedown: setMouseDown,
              onclick: function() { self.gotoToday(); },
              text: FCalendar._STR['TODAY'], colSpan: 3}, btnsRow);

        var nmb= FCalendar.$new({tag: 'td', className: 'nav button', title: FCalendar._STR["NEXT_MONTH"],
                       onmouseover: setHover, onmouseout: unsetHover, onmousedown: setMouseDown,
                       onclick: tmpNextMonth,
                       text: FCalendar.$char(8250)}, btnsRow);
        FCalendar.$attachEvent(nmb, 'mousedown', function() { self.timeoutPopupMenu('months', this); });
        var nyb = FCalendar.$new({tag: 'td', className: 'nav button', title: FCalendar._STR["NEXT_YEAR"],
                        onmouseover: setHover, onmouseout: unsetHover, onmousedown: setMouseDown,
                        onclick: tmpNextYear,
                        text: FCalendar.$char(187)}, btnsRow);
        FCalendar.$attachEvent(nyb, 'mousedown', function() { self.timeoutPopupMenu('years', this, 1); });
        var dofRow = FCalendar.$new({tag: 'tr', className: 'daynames'}, thead);
        for (var i=1; i<=7; i++) {
            var dayCell = FCalendar.$new({tag: 'td', className: 'name', text: FCalendar._SDN[i]}, dofRow);
            if (i>5) { FCalendar.$addClass(dayCell, 'weekend'); }
        }
        this.DOMtable = FCalendar.$new({tag: 'tbody'}, table);
        if (!this.ajaxCheck) {
            this.redraw();
        } else {
            this.sendCheckRequest();
        }
    },
    drawDays: function() {
        var self = this;
        FCalendar.$clearDOM(this.DOMtable);
        this.selected = null;
        var days = this.date.getMonthDays();
        var firstDayDate = new Date(this.date.getTime());
        firstDayDate.setDate(0);
        var row = FCalendar.$new({tag: 'tr', onmouseover: setRowHover, onmouseout: unsetRowHover}, this.DOMtable);
        var cSpanFirstCol = firstDayDate.getDay();
        if (cSpanFirstCol) {
            if (this.showOtherDays) {
                this.drawOtherDays(-1, cSpanFirstCol, row);
            } else {
                FCalendar.$new({tag: 'td', colSpan: cSpanFirstCol}, row);
            }
        }
        var dof = cSpanFirstCol;
        var tmpSelectFunction = function() { self.select(this); }
        for (var day=1; day<=days; day++) {
            var drawDate = new Date(this.date.getTime());
            drawDate.setDate(day);
            var dayCell = FCalendar.$new({tag: 'td', className: 'day', day: day,
                                onmouseover: setHover, onmouseout: unsetHover, onmousedown: setMouseDown,
                                text: day}, row);
            if (dof>4) { FCalendar.$addClass(dayCell, 'weekend'); }
            if (day == this.date.getDate()) { FCalendar.$addClass(dayCell, 'selected'); this.selected = dayCell; }
            if (drawDate.equalsTo(this.today)) { FCalendar.$addClass(dayCell, 'today'); }
            var tmpDate = new Date(this.date.getTime());
            tmpDate.setDate(day);
            if ((this.ajaxCheckType != 'enable') ||
                ((this.ajaxCheckType == 'enable') && (this.checkedDates[FCalendar.print(tmpDate,'%Y-%m-%D')]))) {
                FCalendar.$attachEvent(dayCell, this.triggerEventName, tmpSelectFunction);
            } else {
                FCalendar.$addClass(dayCell, 'disabled');
            }
            dof++;
            if ((dof>6)&&(day<days)) {
                dof = 0;
                row = FCalendar.$new({tag: 'tr', onmouseover: setRowHover, onmouseout: unsetRowHover}, this.DOMtable);
            }
        }
        if (dof<=6) {
            if (this.showOtherDays) {
                this.drawOtherDays(1, 7-dof, row);
            } else {
                FCalendar.$new({tag: 'td', colSpan: 7-dof}, row);
            }
        }
    },
    drawOtherDays: function(delta, count, rowDOM) {
        var self = this;
        var tmpOtherClickFunction = function() { self.gotoDate(this.day, otherDate.getMonth(), otherDate.getFullYear()); };
        var otherDate = new Date(this.date.getTime());
        otherDate.setDate(1);
        var otherDateMonth = otherDate.getMonth()+delta;
        if (otherDateMonth<0) { otherDate.setFullYear(otherDate.getFullYear()-1); otherDateMonth=11; }
        if (otherDateMonth>11) { otherDate.setFullYear(otherDate.getFullYear()+1); otherDateMonth=0; }
        otherDate.setMonth(otherDateMonth);
        var fromDay = delta<0?otherDate.getMonthDays()-count+1:1;
        if ((otherDate.getFullYear()>=this.MINYEAR) && (otherDate.getFullYear()<=this.MAXYEAR)) {
            for (var day=fromDay; day<fromDay+count; day++){
                var dayCell = FCalendar.$new({tag: 'td', className: 'day other',
                                    day: day, month: otherDate.getMonth(), year: otherDate.getFullYear(),
                                    onmouseover: setHover, onmouseout: unsetHover, onmousedown: setMouseDown,
                                    text: day}, rowDOM);
                dayCell.onClick = tmpOtherClickFunction;
            }
        } else {
            FCalendar.$new({tag: 'td', colSpan: count}, rowDOM);
        }
    },
    updateTitle: function() {
        this.DOMtitle.innerHTML = FCalendar.print(this.date,'%M, %Y');
    },
    redraw: function() {
        this.updateTitle();
        this.drawDays();
    },
    select: function(cell) {
        if (this.selected) { FCalendar.$removeClass(this.selected, 'selected'); }
        this.selected = cell;
        this.date.setDate(cell.day);
        FCalendar.$addClass(this.selected, 'selected');
        if (typeof(this.onSelect) == 'function') {
            this.onSelect(this.date);
        }
    },
    timeoutPopupMenu: function(menuType, element, direction) {
        var self = this;
        this.waitingMenuType = menuType;
        this.waitingMenuElement = element;
        this.waitingMenuDirection = direction || 1;
        if (this.timeoutTimer) { window.clearTimeout(this.timeoutTimer); }
        this.timeoutTime = window.setTimeout(function() { self.showPopupMenu(); }, 500);
    },
    showPopupMenu: function() {
        var self = this;
        var element = this.waitingMenuElement;
        if ((element) && (element.className.match('active'))) {
            this.popupMenu = FCalendar.$new({className: 'combo'}, this.DOMcontainer);
            this.killMenuEventFunction = function() { self.killPopupMenu(); }
            FCalendar.$attachEvent(document.documentElement, 'mouseup', this.killMenuEventFunction, 'killPopupEvent');
            var elPosition = FCalendar.$position(element, this.DOMcontainer);
            this.popupMenu.style.left = elPosition.x+'px';
            this.popupMenu.style.top = (elPosition.y+element.offsetHeight)+'px';
            switch (this.waitingMenuType) {
                case 'months':
                    var tmpUpFunction = function() { self.gotoMonthYear(this.month); }
                    for (var i=0; i<12; i++) {
                        var mLabel = FCalendar.$new({className: 'label', text: FCalendar._SMN[i], month: i,
                                           onmouseover: setHover, onmouseout: unsetHover,
                                           onmouseup: tmpUpFunction}, this.popupMenu);
                        if (i == this.date.getMonth()) { FCalendar.$addClass(mLabel, 'active'); }
                    }
                    break;
                case 'years':
                    var tmpUpFunction = function() { self.gotoMonthYear(self.date.getMonth(), this.year); }
                    var curYear = this.date.getFullYear()
                    for (var year=curYear; ((Math.abs(year-curYear)<=12)&&(year>=this.MINYEAR)&&(year<=this.MAXYEAR)); year+=this.waitingMenuDirection) {
                        var mLabel = FCalendar.$new({className: 'label', text: year, year: year,
                                           onmouseover: setHover, onmouseout: unsetHover,
                                           onmouseup: tmpUpFunction}, this.popupMenu);
                    }
                    break;
            }
            this.popupMenu.style.display = 'block';
        }
        this.waitingMenuType = null;
        this.waitingElement = null;
    },
    killPopupMenu: function() {
        FCalendar.$detachEvent(document.documentElement, 'mouseup', 'killPopupEvent');
        if (this.popupMenu) { this.DOMcontainer.removeChild(this.popupMenu); this.popupMenu = null; }
    },
    gotoToday: function() {
        this.gotoDate(this.today.getDate(), this.today.getMonth(), this.today.getFullYear());
    },
    gotoDMonth: function(delta) {
        var curMonth = this.date.getMonth();
        var curYear = this.date.getFullYear();
        curMonth += delta;
        if (curMonth<0) { curMonth = 11; curYear--; }
        if (curMonth>11) { curMonth = 0; curYear++; }
        if (curYear<this.MINYEAR) { curYear = this.MINYEAR; }
        if (curYear>this.MAXYEAR) { curYear = this.MAXYEAR; }
        this.gotoMonthYear(curMonth, curYear);
    },
    gotoDYear: function(delta) {
        var curYear = this.date.getFullYear();
        curYear += delta;
        if (curYear<this.MINYEAR) { curYear = this.MINYEAR; }
        if (curYear>this.MAXYEAR) { curYear = this.MAXYEAR; }
        this.gotoMonthYear(this.date.getMonth(), curYear);
    },
    gotoMonthYear: function(month, year) {
        var curDay = this.date.getDate();
        if (year<this.MINYEAR) { year = this.MINYEAR; }
        if (year>this.MAXYEAR) { year = this.MAXYEAR; }
        this.date.setDate(1);
        if (year) { this.date.setYear(year); }
        this.date.setMonth(month);
        if (this.date.getMonthDays() < curDay) { curDay = this.date.getMonthDays(); }
        this.date.setDate(curDay);
        if (!this.ajaxCheck) {
            this.redraw();
        } else {
            this.sendCheckRequest();
        }
    },
    gotoDate: function(day, month, year) {
        this.date.setFullYear(year);
        this.date.setMonth(month);
        this.date.setDate(day);
        if (!this.ajaxCheck) {
            this.redraw();
        } else {
            this.sendCheckRequest();
        }
    },
    getTransport: function() {
        if (window.XMLHttpRequest) {
            this.request = new XMLHttpRequest();
        } else if (window.ActiveXObject) {
            try {
                this.request = new ActiveXObject('Msxml2.XMLHTTP');
            } catch(err) {
                this.request = new ActiveXObject('Microsoft.XMLHTTP');
            }
        }
    },
    sendCheckRequest: function() {
        if (!this.request) { this.redraw(); return; }
        this.getTransport();
        this.disableCalendar();
        this.request.open('POST', this.requestUrl, true);
        this.request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        var tmpDate = new Date(this.date.getTime());
        tmpDate.setDate(1);
        var fromDateString = FCalendar.print(tmpDate,'%Y-%m-%D');
        tmpDate.setDate(tmpDate.getMonthDays());
        var toDateString = FCalendar.print(tmpDate,'%Y-%m-%D');
        var paramString = '';
        if (this.requestParamString != '') {
            paramString = this.requestParamString + '&from_date='+fromDateString+'&to_date='+toDateString;
        } else {
            paramString = 'from_date='+fromDateString+'&to_date='+toDateString;
        }
        var self = this;
        this.request.onreadystatechange = function() {
            self.handleAjaxResponse();
        }
        this.request.send(paramString);
    },
    handleAjaxResponse: function() {
        if (this.request.readyState == 4) {
            this.checkedDates = {};
            if (this.request.responseXML) {
                var checkedXML = this.request.responseXML.getElementsByTagName('disable');
                if (checkedXML.length>0) {
                    this.ajaxCheckType = 'disable';
                } else {
                    checkedXML = this.request.responseXML.getElementsByTagName('enable');
                    if (checkedXML.length>0) {
                        this.ajaxCheckType = 'enable';
                    } else {
                        this.ajaxCheckType = this.ajaxDefaultCheckType;
                    }
                }
                for (var i=0; i<checkedXML.length; i++) {
                    if (checkedXML[i].getAttribute('date')) {
                        this.checkedDates[checkedXML[i].getAttribute('date')] = true;
                    }
                }
            }
            this.enableCalendar();
            this.redraw();
        }
    },
    enableCalendar: function() {
        if (this.disableLayer) { this.DOMcontainer.removeChild(this.disableLayer); this.disableLayer = null; }
        this.disabled = false;
    },
    disableCalendar: function() {
        if (!this.disabled) {
            this.disableLayer = FCalendar.$new({className: 'disable_layer'}, this.DOMcontainer);
            this.disableLayer.style.width = this.DOMcontainer.clientWidth+'px';
            this.disableLayer.style.height = this.DOMcontainer.clientHeight+'px';
            this.disabled = true;
        }
    }
};


// Setting calendar options n creating new calendar object
FCalendar.setup = function(params) {

    var startupDate = params['date'] || null;
    var eventName = params['eventName'] || 'click';
    var showOtherDays = params['showOthers'] || false;
    var ajaxCheck = params['ajaxCheck'] || false;
    var DOMcontainer = document.getElementById(params['DOMcontainer']);
    if (DOMcontainer) {
        FCalendar.$addClass(DOMcontainer, 'flex-calendar');
        var newCalendarObject = new FCalendar(DOMcontainer, params['date'], ajaxCheck, params['ajaxRequest']);
        newCalendarObject.triggerEventName = eventName;
        newCalendarObject.onSelect = params['onSelect'];
        newCalendarObject.showOtherDays = showOtherDays;
        newCalendarObject.ajaxDefaultCheckType = params['defaultCheckType'];
        newCalendarObject.draw();
    }
}


/*------------- strings -------------*/
FCalendar._DN = new Array ("Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье");
FCalendar._SDN = new Array("Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс");
FCalendar._MN = new Array("Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь");
FCalendar._SMN = new Array("Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек");

FCalendar._STR = {};
FCalendar._STR["PREV_YEAR"] = "Пред. год (удерживать для меню)";
FCalendar._STR["PREV_MONTH"] = "Пред. месяц (удерживать для меню)";
FCalendar._STR["TO_TODAY"] = "На сегодня";
FCalendar._STR["TODAY"] = "Сегодня";
FCalendar._STR["NEXT_MONTH"] = "След. месяц (удерживать для меню)";
FCalendar._STR["NEXT_YEAR"] = "След. год (удерживать для меню)";
FCalendar._STR["WK"] = "нд";


/* -- pathes for Date prototype --- */
Date._MD = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
Date.SECOND = 1000;
Date.MINUTE = 60 * Date.SECOND;
Date.HOUR   = 60 * Date.MINUTE;
Date.DAY    = 24 * Date.HOUR;
Date.WEEK   =  7 * Date.DAY;

Date.prototype.getMonthDays = function(month) {
    var year = this.getFullYear();
    if (typeof month == "undefined") { month = this.getMonth(); }
    if (((0 == (year%4)) && ((0 != (year%100)) || (0 == (year%400)))) && month == 1) {
        return 29;
    } else {
        return Date._MD[month];
    }
};

Date.prototype.getDayOfYear = function() {
    var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
    var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
    var time = now - then;
    return Math.floor(time / Date.DAY);
};

Date.prototype.getWeekNumber = function() {
    var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
    var DoW = d.getDay();
    d.setDate(d.getDate() - (DoW + 6) % 7 + 3);
    var ms = d.valueOf();
    d.setMonth(0);
    d.setDate(4);
    return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
};

Date.prototype.equalsTo = function(date) {
    return ((this.getFullYear() == date.getFullYear()) &&
        (this.getMonth() == date.getMonth()) &&
        (this.getDate() == date.getDate()));
};

FCalendar.print = function (date,str) {
    var m = date.getMonth();
    var d = date.getDate();
    var y = date.getFullYear();
    var wn = date.getWeekNumber();
    var w = date.getDay();
    var s = {};
    var dy = date.getDayOfYear();
    s["%dof"] = FCalendar._SDN[w];
    s["%DOF"] = FCalendar._DN[w];
    s["%m"] = FCalendar._SMN[m];
    s["%M"] = FCalendar._MN[m];
    s["%D"] = (d < 10) ? ("0" + d) : d;
    s["%d"] = d;
    s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy;
    s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m);
    s["%w"] = w + 1;
    s["%y"] = ('' + y).substr(2, 2);
    s["%Y"] = y;
    s["%%"] = "%";
    for (var subst in s) {
        str = str.replace(subst, s[subst]);
    }
    return str;
};


Date.prototype.___msh_oldSetFullYear = Date.prototype.setFullYear;
Date.prototype.setFullYear = function(y) {
    var d = new Date(this);
    d.___msh_oldSetFullYear(y);
    if (d.getMonth() != this.getMonth())
        this.setDate(28);
    this.___msh_oldSetFullYear(y);
};


/* DOM Utils*/
FCalendar.$ = function(element) {
    if (arguments.length > 1) {
        for (var i = 0, elements = [], length = arguments.length; i < length; i++)
            elements.push(FCalendar.$(arguments[i]));
        return elements;
    } else {
        return document.getElementById(element);
    }
}

FCalendar.$new = function(params,parent) {
    var tag = params['tag'] || 'div';
    var newEl = document.createElement(tag);
    for (var paramName in params) {
        if ((paramName != 'tag') && (paramName != 'text') && (!paramName.match(/^on\w+/))) { newEl[paramName] = params[paramName]; }
        if (paramName.match(/^on(\w+)/)) {
            var eventName = RegExp.$1;
            FCalendar.$attachEvent(newEl, eventName, params[paramName]);
        }
    }
    if (params['text'] != null) { newEl.appendChild(FCalendar.$text(params['text'])); }
    if (parent!=null) { parent.appendChild(newEl); }
    return newEl;
}

FCalendar.$text = function(string) {
    return document.createTextNode(string);
}
FCalendar.$char = function(num) {
    return String.fromCharCode(num);
}

FCalendar.$clearDOM = function(el) {
    while (el.childNodes.length>0) { el.removeChild(el.firstChild); }
}

FCalendar.$addClass = function(node, className) {
    FCalendar.$removeClass(node, className);
    node.className += ' '+className;
}

FCalendar.$removeClass = function(node, className) {
    var classes = node.className.split(' ');
    for (var i=0; i<classes.length; i++) {
        if (classes[i] == className) {
            classes.splice(i, 1);
        }
    }
    node.className = classes.join(' ');
}

FCalendar.$point = function(x, y) { this.x = x; this.y = y; }
FCalendar.$position = function(node, toNode) {
    var el = node;
    var x = 0; var y = 0;
    while ((el)&&(el!=toNode)) {
        if (el.offsetLeft) { x += el.offsetLeft; }
        if (el.offsetTop) { y += el.offsetTop; }
        el = el.offsetParent;
    }
    return new FCalendar.$point(x, y);
}

FCalendar.$attachEvent = function(object, event, method, methodId) {
    if (!methodId) methodId = '';
    object['event_'+event+methodId] = function(event) { method.apply(object, [event]); };
    if (typeof(object['addEventListener']) == 'function') { 
        object.addEventListener(event, object['event_'+event+methodId], false);
    } else {
        object.attachEvent('on'+event, object['event_'+event+methodId]);
    }
}

FCalendar.$detachEvent = function(object, event, methodId) {
    if (!methodId) { methodId = ''; }
    if (typeof(object['removeEventListener']) == 'function') {
        object.removeEventListener(event, object['event_'+event+methodId], false);
    } else {
        object.detachEvent('on'+event, object['event_'+event+methodId]);
    }
}


/* -- sysutils -- */
function setHover() { FCalendar.$addClass(this, 'hilite'); }
function unsetHover() { FCalendar.$removeClass(this, 'hilite'); }
function setRowHover() { FCalendar.$addClass(this, 'rowhilite'); }
function unsetRowHover() { FCalendar.$removeClass(this, 'rowhilite'); }

function setMouseDown() {
    var self = this;
    FCalendar.$addClass(this, 'active');
    var tmpUnsetFunc = function(event) {
        var e = event || window.event;
        var el = e.target || e.srcElement;
        FCalendar.$removeClass(self, 'active'); 
        FCalendar.$detachEvent(document.documentElement, 'mouseup', 'unsetActive');
        if ((el == self)&&(typeof(self.onClick) == 'function')) { self.onClick(event); }
    }
    FCalendar.$attachEvent(document.documentElement, 'mouseup', tmpUnsetFunc, 'unsetActive');
}
function cancelSelection(e) {
    var event = e?e:window.event;
    var element = event.target?event.target:event.srcElement;
    event.preventDefault(); return false;
}

/*------------ Calendar ------------- */
function sendDate(date) {
    var y = date.getFullYear();
    var m = date.getMonth()+1;
    var d = date.getDate();
    FCalendar.$('news-date-form').dd.value=y+'-'+m+'-'+d;
    FCalendar.$('news-date-form').submit();
}

function setupNewsCalendar(date) {
    if (!date) { 
        if (FCalendar.$('news-date-form').dd.value.match(/(\d+)\-(\d+)\-(\d+)/)) {
            var tmpDate = new Date();
            tmpDate.setDate(RegExp.$3);
            tmpDate.setMonth(RegExp.$2-1);
            tmpDate.setYear(RegExp.$1);
            date = tmpDate.getTime();
        }
    }
    FCalendar.setup({
        date: date,
        onSelect: sendDate,
        showOthers: true,
        ajaxCheck: true,
        defaultCheckType: 'enable',
        ajaxRequest: '/xml/?get=calendar',
        DOMcontainer: 'news-calendar'
    });
}