var Calendar = Class.create();
Calendar.prototype = {
    _uniqueID: 0,
    _day: 86400000,
    initialize: function() {
        var init = arguments[0];
        if (! init) return;
        if (! (init instanceof Array)) init = new Array(init);
        var self = this;
        for (var i = 0;i < init.length; i++) {
            var calendar = init[i];
            var id = calendar.id ? calendar.id : this._getUniqueID();
            this.calendars[id] = {show: $(calendar.show[0]),
                                 top: $(calendar.show[0]).offsetTop,
                                 renderAlign: calendar.renderAlign,
                                 date: new Date(calendar.date),
                                 minDate: calendar.minDate ? calendar.minDate : null,
                                 maxDate: calendar.maxDate ? calendar.maxDate : null,
                                 print: calendar.print ? calendar.print : null,
                                 subscribers: []};
            this.calendars[id].updateDate = this._updateCalendarDate.bindAsEventListener(this, this.calendars[id]);

            if (parseInt(init[i].parent) >= 0) {
                this.calendars[id].parent = this.calendars[calendar.parent];
            }
            this.calendars[id].fields = this._renderOutput(calendar.output, calendar.form);

            this.current = this.calendars[id];
            this._updateDate(this.calendars[id].date.getFullYear(),
                             this.calendars[id].date.getMonth() + 1,
                             this.calendars[id].date.getDate());

            calendar.show.each(function(el){
                $(el).observe('click', self.showCalendar.bindAsEventListener(self, self.calendars[id]));
            });
            
        }
        // subscribe ro update
        for (i in this.calendars) {
            var cal = this.calendars[i];
            $H({min:cal.minDate, max:cal.maxDate}).each(function(el){
                if (! el[1] || el[1] instanceof Date) return;
                var type = el[0];
                var values = el[1];
 
                if (! (values instanceof Array)) values = new Array(values);
                values.each(function(value){
                    var id, data;
                    if (value instanceof String) {
                        id = value;
                        data = {id: i, shift: 0, type: type};
                    } else if (value instanceof Object){
                        id = value.id;
                        data = {id: i, shift: (value.shift ? value.shift : 0), type: type}
                    }
                    this.calendars[id].subscribers.push(data);
                }.bind(this));
/*                var item = this.calendars[cal.minDate];
                if (! (item instanceof Array)) item = new Array(item);
                item.each(function(el){
                    this.calendars[cal.minDate].subscribers.push({type: 'min', id: i});
                }.bind(this))
                if (cal.maxDate && ! (cal.maxDate instanceof Date) && this.calendars[cal.maxDate])
                    this.calendars[cal.maxDate].subscribers.push({type: 'max', id: i});*/
            }.bind(this));
        };
    },
    _getUniqueID: function(){
        return 'c' + (this._uniqueID++);
    },
    getShortMonth: function(i){
        return this.shortMonth[i];
    },
    getLongMonth: function(i){
        return this.longMonth[i];
    },
    _renderOutput: function(fields, form){
        var output = {};
        fields.each(function(field) {
            if (! $(field.id)) {
                var el = new Element('input', {id: field.id, name: field.name, type: 'hidden'});
                $(form).appendChild(el);
            }
            output[field.id] = $(field.id);
            output[field.id].format = field.format;
        });
        return output;
    },
    _getMinDate: function(){
        if (this.current.minDate instanceof Date) {
            return this.current.minDate;
        } else {
            for (i in this.calendars) {
                var cal = this.calendars[i];
                if (i == this.current.minDate.id.toString()) {
                    return cal.date;
                    break;
                }
            }
        }
    },
    _updateCalendarDate: function(date, obj){
        //this - same calendar from this.calendars
        var cur = this.current;
        this.current = obj;
        this._updateDateJS(date);
        this.current = cur;
    },
    _updateDateJS: function(date){
        this._updateDate(date.getFullYear(), date.getMonth() + 1, date.getDate());
    },
    /**
     * @param year
     * @param month
     * @param day
     */
    _updateDate: function(y, m, d){
        this.current.date = new Date(y, m - 1, d);
        if (this.current.print instanceof Function) this.current.print(y, m, d);
        Object.values(this.current.fields).each(function(el){
            var res = el.format;
            res = res.replace(/D/, d.toString().length > 1 ? d: '0'+  d)
                     .replace(/M/, m.toString().length > 1 ? m: '0'+  m)
                     .replace(/m/, m)
                     .replace(/d/, d)
                     .replace(/Y/, y)
                     .replace(/y/, y.toString().substr(-2));
            el.value = res;
        });
        this.current.subscribers.each(function(el) {
            var cal = this.calendars[el.id];
            if ((el.type == 'min' &&
                cal.date.getTime() < this.current.date.getTime() + el.shift*this._day)
                || (el.type == 'max' &&
                cal.date.getTime() > this.current.date.getTime() - el.shift*this._day))
                    this._shiftUpdate(cal, el.shift);
            
        }.bind(this));
    },
    _shiftUpdate: function(cal, s, d) {
        var d = d || this.current.date;
        var s = (s = parseInt(s || 0)) ? s : 0;
        var date = new Date(d.getTime() + s*this._day);
        cal.updateDate(date);
    }
};

Calendar.shortMonth = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
Calendar.longMonth = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];



var yahooCalendar = function(){
    var g = new Class.create(Calendar, Object.extend(yahooCalendar.proto, {calendars: {}}))
    return new g(arguments[0]);
}

yahooCalendar.proto = {
    calendarId: 'calendarDiv',
    initialize: function($super){
	    if (! $('calendarDiv')) {
	        document.body.appendChild(new Element('div', {id: this.calendarId}).addClassName('yui-skin-sam')
	                                  .setStyle({display:'none'}));
	        this.calendar = new YAHOO.widget.Calendar(this.calendarId);
	        $(this.calendarId).calendar = this.calendar;
	        this.calendar.render();
	    } else {
	        this.calendar = $(this.calendarId).calendar;
	    }
	    $super(arguments[1]);
    },
    showCalendar: function(event, c){
        var _offset = c.show.cumulativeOffset();
        this.current = c;
        $(this.calendarId).setStyle({left: _offset[0] + (c.renderAlign == 'right' ? 1 : -1)* c.show.getWidth() + 'px',
                                     top: _offset[1] + 'px'});
        if (this.calendar.selectEvent.subscribers.length > 0) {
            this.calendar.selectEvent.unsubscribeAll();
        }
        var mindate = this._getMinDate();
        this.calendar.cfg.setProperty('mindate', mindate)
        var over = mindate > c.date ? true : false;
        this.calendar.setMonth(over ? mindate.getMonth() : c.date.getMonth());
        this.calendar.setYear(over ? mindate.getFullYear() : c.date.getFullYear());
        this.calendar.render();
        this.calendar.selectCell(this.calendar.getCellIndex(over ? mindate : c.date));


        this.calendar.selectEvent.subscribe(function(e, v){
            var date = v.first().first();
            this._updateDate(date[0], date[1], date[2]);
            this.calendar.hide();
        }.bind(this));

        this.calendar.show();
    }
};

