jQuery.extend(jQuery.fn, {
    rateCalendar: function(options) {
        if (!this.length) {
            return this;
        }

        var calendar = jQuery.data(this[0], 'calendar');
        if (calendar) {
            return calendar;
        }

        options = options || {};
        calendar = new jQuery.rateCalendar(this[0], options);
        jQuery.data(this[0], 'calendar', calendar);

        return calendar;
    }
});

jQuery.rateCalendar = function(calendar, options) {
    this.calendar = calendar;
    this.settings = jQuery.extend({}, jQuery.rateCalendar.defaults, options);
    this.init();
};

jQuery.extend(jQuery.rateCalendar, {
    defaults: {
        updateURL: '',
        linkToURL: '',
        backClass: '.back',
        forwardClass: '.forward',
        rangeStart: Date.today().addMonths(-1)
    },

    prototype: {
        init: function() {
            var $cal = jQuery(this.calendar);

            this.updateURL = this.settings.updateURL;
            this.linkToURL = this.settings.linkToURL;
            this.backButton = $cal.find(this.settings.backClass);
            this.forwardButton = $cal.find(this.settings.forwardClass);
            this.rangeStart = this.settings.rangeStart;

            this.bind();

            jQuery.getJSON(this.updateURL+'/'+this.rangeStart.toString('yyyy-MM'), function(data){
                $cal.data('calendarData', data);
            });
        },

        bind: function() {
            var $this = this;
            var STEP_BACK = false, STEP_FORWARD = true;

            this.backButton.unbind('click').click(function(){
                $this.update(STEP_BACK);
                return false;
            });

            this.forwardButton.unbind('click').click(function(){
                $this.update(STEP_FORWARD);
                return false;
            });
        },

        update: function(forward) {
            this.backButton.unbind('click').click(function(){
                return false;
            });

            this.forwardButton.unbind('click').click(function(){
                return false;
            });

            this.backButton.css('cursor', 'wait');
            this.forwardButton.css('cursor', 'wait');

            var $cal = jQuery(this.calendar);
            var data = $cal.data('calendarData');
            var offset = !!forward ? 2 : 0;

            this.rangeStart.addMonths(offset ? 1 : -1);

            var prevMonth = new Date(this.rangeStart);
            var nextMonth = new Date(this.rangeStart);

            prevMonth.addMonths(-1);
            nextMonth.addMonths(2);

            if (this.rangeStart.isBefore(Date.today())) {
                this.backButton.hide();
            } else {
                this.backButton.find('span').text(prevMonth.toString('MMM'));
                this.backButton.show();
            }

            this.forwardButton.find('span').text(nextMonth.toString('MMM'));

            for (var i = 0, j = offset; i <= 1 && j <= offset+1; i++, j++) {
                var cal = jQuery($cal.find('.calendar').get(i));
                var month = data.months[j];
                var rates = data.rates[j];

                cal.find('.month th').text(month);
                cal.find('td').children().remove();

                for (var k = 0; k < rates.length; k++) {
                    if (rates[k].day) {
                        var day = $(cal.find('td').get(k));

                        day.append(
                            jQuery('<div></div>').addClass('day').text(rates[k].day)
                        );

                        if (rates[k].price) {
                            day.append(
                                jQuery('<div></div>').addClass('price').append(
                                    $('<a></a>').attr('href', this.linkToURL+'/'+rates[k].id).text('$'+rates[k].price)
                                )
                            );
                        }
                    }
                }
            }

            var $this = this;

            jQuery.getJSON(this.updateURL+'/'+this.rangeStart.toString('yyyy-MM'), function(data){
                $cal.data('calendarData', data);
                $this.bind();
                $this.backButton.css('cursor', 'pointer');
                $this.forwardButton.css('cursor', 'pointer');
            });
        }
    }
});
