/**
  * mCalendar 0.5.5
  * Copyright 2009-2010 by Maciej "Macku" Adamczak
  * http://maciejadamczak.net/
  */

// TODO:
// Work on prevMonthDays, nextMonthDays (ex. see February 2010)
// Work on weeks
// Check new mootools more version. Some errors with diff.
// Some parts needs rewrite.

var mCalendar = new Class({
	Implements: [Options, Events],

	container: null,
	now: new Date(),
	date: null,

	disabled: {},
	enabled:  {},
	booked:   {},

	marked:   [],
	selected: [],

	inSelect: null,

	options: {
		lang:          false,
		mode:         'single',
		className:    'mCalendar',
		wheel:         true,
		showToday:     true,
		startDate:     null,
		noPast:        true,
		limit:         [null, null],
		disabled:      [],
		months:        1,
		prevMonthDays: false,
		nextMonthDays: false,
		disableAll:    false,
		renderOnStart: true
	},

	initialize: function(calednarContainer, options) {
		if (!calednarContainer) { return false; }

		this.setOptions(options);

		switch (this.options.mode) {
			case 'single':
			case 'multi':
			case 'range':
			break;

			default:
				alert('mCalendar: Unknown calednar mode "' + this.options.mode + '".');
				return false;
			break;
		}

		// Set lang
		if (this.options.lang) {
			MooTools.lang.setLanguage(this.options.lang);
		}

		// Set date parser
		Date.defineParser('%d\.%m\.%Y');

		// Set dates
		this.now.set({hr: 0, ms: 0, sec: 0, min: 0});
		this.date = this.options.startDate ? new Date().parse(this.options.startDate) : this.now.clone();

		// Limits
		if (this.options.limit[0]) {
			this.options.limit[0] = new Date().parse(this.options.limit[0]);
		}
		if (this.options.limit[1]) {
			this.options.limit[1] = new Date().parse(this.options.limit[1]);
		}

		// Disabled days
		if (this.options.disabled.length) {
			this.disabled = this.options.disabled.map(function(date) {
				return new Date().parse(date);
			});
		}

		// Check past
		if (this.options.noPast && this.now.diff(this.date, 'month') < 0) {
			this.date = this.now;
		}

		// Check calednar container
		if ($type(calednarContainer) == 'string') {
			calednarContainer = document.id(calednarContainer);
		}

		// Inject calednar
		this.container = new Element('div', {
			'class': this.options.className
		}).inject(calednarContainer);

		// Don't allow to select text inside calednar box
		this.container.addEvent(Browser.Engine.trident ? 'selectstart' : 'mousedown', function(e) {
			e.preventDefault();
		});

		// Set enabled/disabled days storage
		this.clearDates();

		// Change month after mouse wheel
		if (this.options.wheel) {
			this.container.addEvents({
				mousewheel: function(e) {
					e.preventDefault();

					e.wheel < 0
						? this.nextMonth(new Event(e))
						: this.prevMonth(new Event(e));
				}.bindWithEvent(this)
			});
		}

		if (this.options.renderOnStart) {
			this.render();
		}
	},

	clearDates: function() {
		this.enabled  = {};
		this.disabled = {};
		this.booked   = {};

		this.selected = [];
		this.marked   = [];

		// Clear enabled/disabled days storage
		var year = this.now.get('year') -5;
		var year_limit = year + 10;

		while (year < year_limit) {
			this.enabled[year]  = {};
			this.disabled[year] = {};
			this.booked[year]   = {};

			for (var month = 1; month <= 12; month++) {
				this.enabled[year][month]  = [];
				this.disabled[year][month] = [];
				this.booked[year][month]   = [];
			}

			year++;
		}
	},

	addDisabledDay: function(date) {
		switch ($type(date)) {
			case 'array':
				var dates = date.map(function(date) {
					if (date instanceof Date) {
						return date.get('date');
					}

					return new Date().parse(date).get('date');
				});
				this.disabled.extend(dates);
			break;

			case 'string':
				this.disabled.push(new Date().parse(date).get('date'));
			break;

			case 'object':
				if (date instanceof Date) {
					this.disabled.push(date.get('date'));
				}
			break;
		}

		this.render();
	},

	prevMonth: function(e) {
		e.preventDefault();

		if (this.options.noPast && this.now.diff(this.date, 'month') <= 0) {
			return;
		}
		else if (this.options.limit[0] && this.options.limit[0].diff(this.date, 'month') <= 0)
		{
			return;
		}

		this.date.decrement('month');
		this.render();
	},

	nextMonth: function(e) {
		e.preventDefault();

		var date = this.date.clone();
		if(this.options.months > 1) {
			date.increment('month', this.options.months -1);
		}

		if (this.options.limit[1] && this.options.limit[1].diff(date, 'month') >= 0)
		{
			return;
		}

		this.date.increment('month');
		this.render();
	},

	selectDay: function(dayEl, dayDate) {
		var prevSelection = this.container.getElement('.selected');
		if (prevSelection) {
			prevSelection.removeClass('selected');
		}

		if ($type(dayEl) == 'date') {
			dayDate = dayEl;
			this.selected = [dayDate];
			return;
		}

		dayEl.addClass('selected');

		this.selected = [dayDate];

		this.fireEvent('select', dayDate);
	},

	toggleSelectDay: function(dayEl, dayDate) {
		dayEl.toggleClass('selected');

		// Select
		if (dayEl.hasClass('selected')) {
			this.selected.push(dayDate);
		}
		// Deselect
		else {
			this.selected.erase(dayDate);
		}

		if (this.selected.length) {
			this.fireEvent('select', [this.selected]);
		}
	},

	markDayRange: function(fromDate, toDate, options, noRender) {
		fromDate = fromDate instanceof Date ? fromDate : new Date().parse(fromDate);
		toDate = toDate instanceof Date ? toDate : new Date().parse(toDate);

		// Add booked dates
		var dayDate = fromDate.clone();
		var endDate = toDate.clone();

		if (options.halfDisabled) {
			dayDate.increment('day');
			endDate.decrement('day');
		}

		do {
			// Store disabled days
			var month = dayDate.get('month') +1;
			var year  = dayDate.get('year');
			var date  = dayDate.get('date');

			if (!this.booked[year][month].contains(date)) {
				this.booked[year][month].push(date);
			}

			dayDate.increment('day');
		}
		while (dayDate <= endDate);

		// Save marked
		this.marked.push({
			fromDate: fromDate,
			toDate:   toDate,
			options:  options
		});

		if (!noRender) {
			this.render();
		}
	},

	startSelectRange: function(e) {
		var dayEl   = e.target,
			dayDate = dayEl.retrieve('date');

		if (this.inSelect) {
			return;
		}

		this.inSelect = true;
		window.addEvent('mouseup', this.stopSelectRange.bind(this));

		// Remove previous selection
		this.container.getElements('.selected').each(function(dayEl) {
			dayEl.toggleClass('selected');
		});

		// Set selected day
		this.selected[0] = dayDate.clone();
		this.selected[1] = null;

		// Set cursor
		this.container.getElements('.disabled').each(function(dayEl) {
			dayEl.setStyle('cursor', 'not-allowed');
		});

		dayEl.addClass('selected');

		this.fireEvent('start', this.selected[0]);
	},

	onSelectRange: function(e) {
		var dayEl   = e.target,
			dayDate = dayEl.retrieve('date');

		if (!this.inSelect) {
			return;
		}

		// Selected day is disabled
		if (dayEl.hasClass('disabled')) {
			//this.stopSelectRange(new Event(e), dayEl, dayDate); // TODO: consider about it
			return;
		}

		// Order dates
		var startDate = this.selected[0].get('date');
		var endDate   = dayDate.get('date');

		// Get selected days range
		if (this.options.months > 1) {
			var months = Math.abs(this.selected[0].diff(dayDate, 'month'));
			var month  = 0;
			var daysRange = [];

			if (this.selected[0].diff(dayDate) > 0) {
				var date = this.selected[0].clone();

				do {
					daysRange.extend(this.container.getElements(date.format('.year_%Y .month_%m .day')));
					date.increment('month');
					month++;
				}
				while (month <= months);

				daysRange = daysRange.slice(startDate -1, daysRange.indexOf(dayEl) +1);
			}
			else {
				var date = dayDate.clone();

				do {
					daysRange.extend(this.container.getElements(date.format('.year_%Y .month_%m .day')));
					date.increment('month');
					month++;
				}
				while (month <= months);

				date.decrement('month');

				var startEl = this.container.getElement(this.selected[0].format('.year_%Y .month_%m .day_%d'));
				daysRange = daysRange.slice(daysRange.indexOf(dayEl), daysRange.indexOf(startEl) +1);
			}
		}
		else {
			var daysRange = this.container.getElements(dayDate.format('.year_%Y .month_%m .day_%d'));
			daysRange = daysRange.slice((startDate > endDate ? endDate : startDate) -1, startDate < endDate ? endDate : startDate);
		}

		// Check if days contains disabled day
		var hasDisabledDay = daysRange.filter(function(dayEl) {
			return dayEl.hasClass('disabled');
		});
		if (hasDisabledDay.length) {
			return;
		}

		// Check if range has any half disabled day
		var hasHalfDisabledDays = daysRange.some(function(dayEl) {
			return dayEl.hasClass('halfDisabled');
		});

		// Check half disabled days
		if (hasHalfDisabledDays) {
			var firstDayEl = daysRange[0].hasClass('halfDisabled');
			var lastDayEl  = daysRange.getLast().hasClass('halfDisabled');

			var hasHalfDisabledDay = false;
			if (firstDayEl && lastDayEl) {
				hasHalfDisabledDay = daysRange.slice(1, -1).some(function(dayEl) {
					return dayEl.hasClass('halfDisabled');
				});
			}
			else if (firstDayEl) {
				hasHalfDisabledDay = daysRange.slice(1, 0).some(function(dayEl) {
					return dayEl.hasClass('halfDisabled');
				});
			}
			else if (lastDayEl) {
				hasHalfDisabledDay = daysRange.slice(0, -1).some(function(dayEl) {
					return dayEl.hasClass('halfDisabled');
				});
			}

			if (hasHalfDisabledDay) {
				return;
			}
		}

		// Set selected day
		this.selected[1] = dayDate;

		// Remove previous selection
		this.container.getElements('.selected').each(function(dayEl) {
			dayEl.removeClass('selected');
		});

		// Set cursor
		this.container.getElements('.selectable').each(function(dayEl) {
			dayEl.setStyle('cursor', Browser.Engine.gecko ? '-moz-cell' : 'move');
		});

		// Set new selection
		daysRange.each(function(dayEl) {
			dayEl.addClass('selected');
		});

		if (this.selected[0].diff(this.selected[1]) > 0) {
			this.fireEvent('change', [this.selected[0], this.selected[1]]);
		}
		else {
			this.fireEvent('change', [this.selected[1], this.selected[0]]);
		}
	},

	stopSelectRange: function() {
		if (!this.inSelect) {
			return;
		}

		this.inSelect = false;
		window.removeEvents('mouseup');

		// Remove cursor
		this.container.getElements('.day').each(function(dayEl) {
			dayEl.setStyle('cursor', '');
		});

		// Start day is end day
		if (!this.selected[1]) {
			this.selected[1] = this.selected[0].clone();
		}

		// Set event type
		var eventType = $defined(this.$events.change) && !$defined(this.$events.select) ? 'change' : 'select';

		if (this.selected[0].diff(this.selected[1]) <= 0) {
			var temp = this.selected[1];
			this.selected[1] = this.selected[0];
			this.selected[0] = temp;
		}

		this.fireEvent(eventType, [this.selected[0], this.selected[1]]);
	},

	render: function(calednarDate) {
		if (!calednarDate) {
			calednarDate = this.date;
		}

		// Check past
		if (this.options.noPast && this.now.diff(calednarDate) < 0 ) {
			calednarDate = this.now;
		}

		// Clean container
		this.container.empty();

		// Set top bar
		var top = new Element('p', {
			'class': 'bar'
		}).inject(this.container);

		var months = new Element('span', {
			'class': 'months'
		}).inject(top);

		// Month names
		var month = 0;
		while (month < this.options.months) {
			new Element('span', {
				'class': 'month',
				text: calednarDate.clone().increment('month', month).format('%B %Y'),
				styles: {
					width: 160
				}
			}).inject(months);

			month++;
		}

		// NAVIGATION
		var prev = new Element('span', {
			text: '\253 ',
			title: Date.getMsg('prev'),
			'class': 'nav prevMonth',
			events: {
				mousedown: this.prevMonth.bind(this)
			}
		});
		// NoPast and min limitation
		if ((!this.options.noPast || this.now.diff(calednarDate, 'month') > 0)
			&& (!this.options.limit[0] || this.options.limit[0].diff(calednarDate, 'month') > 0)) {
			prev.inject(top, 'top');
		}
		else {
			prev.clone().addClass('disabled').inject(top, 'top');
		}
		// Next navigation
		var next = new Element('span', {
			text: '\273',
			title: Date.getMsg('next'),
			'class': 'nav nextMonth',
			events: {
				mousedown: this.nextMonth.bind(this)
			}
		});
		// Max limitation
		var date = calednarDate.clone();
		if(this.options.months > 1) {
			date.increment('month', this.options.months -1);
		}
		if (!this.options.limit[1] || this.options.limit[1].diff(date, 'month') < 0)
		{
			next.inject(top, 'bottom');
		}
		else {
			next.clone().addClass('disabled').inject(top, 'bottom');
		}

		this.renderCalendar(calednarDate);

		if (this.options.months > 1 ) {
			var month = 1;
			while (month < this.options.months) {
				this.renderCalendar(calednarDate.clone().increment('month', month), 'nextMonth');
				month++;
			}
		}
	},

	renderCalendar: function(calednarDate, tableClassName) {
		if (!calednarDate) {
			calednarDate = this.date;
		}

		// Calendar table
		var table = new Element('table').inject(this.container);

		if ($defined(tableClassName)) {
			table.addClass(tableClassName);
		}

		// Set year
		table.addClass('year_'+calednarDate.format('%Y'));

		// HEADERS
		// Set table head - week day names
		var thead = new Element('thead').inject(table);
		var row = new Element('tr').inject(thead);
		for (var i = 1; i < 7; i++) {
			new Element('th', {
				text: Date.getMsg('days')[i].substr(0, 2)
			}).inject(row);
		}

		// Sunday
		new Element('th', {
			text: Date.getMsg('days')[0].substr(0, 2)
		}).inject(row);

		// MOTH LIST
		var tbody = new Element('tbody', {
			'class': 'month_'+calednarDate.format('%m')
		}).inject(table);

		// Set first day of month vars
		var firstMonthDay = calednarDate.clone().decrement('day', calednarDate.get('date') -1);
		var firstMonthWeekDay = Date.getMsg('days').indexOf(firstMonthDay.format('%A'));

		// Sunday, bloody Sunday
		if (firstMonthWeekDay == 0) {
			firstMonthWeekDay = 7;
		}

		// Set first row
		row = row.clone().empty().inject(tbody);
		var weeks = 0;
		//var week = firstMonthDay.get('week');
		//row = row.clone().addClass('week_'+week).empty().inject(tbody);

		// Prev month days
		if (this.options.prevMonthDays) {
			var lastMonthDay = calednarDate.clone().decrement('month').get('lastdayofmonth');
			var monthDay = lastMonthDay - firstMonthWeekDay +1;

			while (monthDay < lastMonthDay) {
				monthDay++;

				var td = new Element('td').inject(row);
				new Element('span', {
					text: monthDay,
					'class': 'prevMonthDay disabled'
				}).inject(td);

			}
		}
		else {
			// Empty days before first month day
			new Element('td', {
				'colspan': firstMonthWeekDay -1
			}).inject(row);
		}

		// List days of month
		var monthDay = 1;
		var lastMonthDay = calednarDate.get('lastdayofmonth');
		var weekStarts = firstMonthWeekDay;
		while (monthDay <= lastMonthDay) {
			weeks++;

			for (var weekDay = weekStarts; weekDay < 8 && monthDay <= lastMonthDay; weekDay++) {
				var td = new Element('td').inject(row);

				// Create day date and element
				var dayDate = calednarDate.clone().set('date', monthDay);
				var dayEl = new Element('span', {
					text: monthDay,
					'class': 'day selectable day_'+dayDate.format('%d')
				}).inject(td);
				dayEl.store('day', monthDay);
				dayEl.store('date', dayDate);

				// Events
				switch (this.options.mode) {
					case 'single':
						if (this.isDayDisabled(dayDate)) {
							dayEl.removeClass('selectable');
							dayEl.addClass('disabled');
						}
						else {
							dayEl.addEvent('mousedown', this.selectDay.bind(this, [dayEl, dayDate]));
						}
					break;

					case 'multi':
						if (this.isDayDisabled(dayDate)) {
							dayEl.removeClass('selectable');
							dayEl.addClass('disabled');
						}
						else {
							dayEl.addEvent('mousedown', this.toggleSelectDay.bind(this, [dayEl, dayDate]));
						}
					break;

					case 'range':
						if (this.isDayDisabled(dayDate)) {
							dayEl.removeClass('selectable');
							dayEl.addClass('disabled');
						}
						else {
							dayEl.addEvents({
								mousedown:  this.startSelectRange.bind(this),
								mouseup:    this.stopSelectRange.bind(this),
								mouseenter: this.onSelectRange.bind(this)
							});
						}
					break;
				}

				// Set today
				if (this.options.showToday && this.now.diff(dayDate) == 0) {
					dayEl.addClass('today');
				}

				monthDay++;
			}

			// Reset weekStarts
			weekStarts = 1;
			//week++;

			// Set next week row
			if (monthDay <= lastMonthDay) {
				//row = row.clone().set('class', 'week_'+week).empty().inject(tbody);
				row = row.clone().empty().inject(tbody);
			}
		}

		// Next month days
		if (this.options.nextMonthDays) {
			var monthDay = 1

			while (weeks < 7 ) {
				for (; weekDay < 8; monthDay++, weekDay++)
				{
					var td = new Element('td').inject(row);
					new Element('span', {
						text: monthDay,
						'class': 'nextMonthDay disabled'
					}).inject(td);
				}

				weekDay = 1;
				weeks++;

				if (weeks < 7) {
					row = row.clone().empty().inject(tbody);
				}
			}
		}

		// Render marked days
		this.marked.each(function(data) {
			this.renderMarkRange(calednarDate, data.fromDate, data.toDate, data.options);
		}, this);

		// Render selected days
		if (this.selected.length) {
			switch (this.options.mode) {
				case 'single':
					var dayDate = this.selected[0];
					var dayEl = this.container.getElement(
						dayDate.format('.year_%Y .month_%m .day_%d')
					);
					if (dayEl) {
						dayEl.addClass('selected');
					}
				break;

				case 'multi':
					this.selected.each(function(dayDate) {
						var dayEl = this.container.getElement(
							dayDate.format('.year_%Y .month_%m .day_%d')
						);
						if (dayEl) {
							dayEl.addClass('selected');
						}
					});
				break;

				case 'range':
					var fromDate = this.selected[0];
					var toDate   = this.selected[1];

					this.renderMarkRange(calednarDate, fromDate, toDate, {
						className:   'selected',
						disabled:     false,
						halfDisabled: false
					});
				break;
			}
		}
	},

	renderMarkRange: function(calednarDate, fromDate, toDate, options) {
		var startFromDate  = fromDate.clone();
		var startFromMonth = fromDate.diff(calednarDate, 'month');

		var endToDate = toDate.clone();
		var endToMonth = toDate.diff(calednarDate, 'month');

		// Check from date
		if (startFromMonth > 0 && endToMonth > 0) { // End date is in Past
			return;
		}
		if (startFromMonth < 0) { // End date is in Future
			return;
		}
		else if (startFromMonth > 0 && endToMonth <= 0) { // Start date is in Past
			startFromDate.set({
				date: 1,
				month: calednarDate.get('month')
			});
		}

		// Check end date
		if (endToMonth < 0) { // Future
			endToDate.set({
				month: calednarDate.get('month'),
				date:  calednarDate.get('lastdayofmonth')
			});
		}

		// Get elements from calendar
		var daysRange = this.container.getElements(calednarDate.format('.year_%Y .month_%m .day'));
		daysRange = daysRange.slice(startFromDate.get('date') -1, endToDate.get('date'));

		// None days
		if (!daysRange.length) {
			return;
		}

		// Options
		if (!$defined(options)) {
			options = {};
		}

		if (!$defined(options.disabled)) {
			options.disabled = true;
		}

		if (!$defined(options.halfDisabled)) {
			options.halfDisabled = true;
		}

		// Use half disabled days
		if (options.halfDisabled && options.className) {
			// Mark first and last day or range as half disabled
			var firstDayEl = daysRange[0];
			if (!firstDayEl.hasClass('disabled')) {
				firstDayEl.addClass(options.className+'_half halfDisabled');
			}

			var lastDayEl = daysRange.getLast();
			if (!lastDayEl.hasClass('disabled')) {
				lastDayEl.addClass(options.className+'_half halfDisabled');
			}

			// Unmark first day and last day of month
			var halfDisabledDays = daysRange.filter(function(dayEl) {
				var day = dayEl.retrieve('day');
				var dayDate = dayEl.retrieve('date');
				if (day == dayEl.retrieve('date').get('lastdayofmonth') && dayDate.diff(fromDate) < 0) {
					return true;
				}
				else if (day == 1 && dayDate.diff(toDate)) {
					return true;
				}

				return false;
			});

			halfDisabledDays.each(function(dayEl) {
				dayEl.removeClass(options.className+'_half halfDisabled');
			});

			// Remove half disabled days
			daysRange = daysRange.filter(function(dayEl) {
				return (dayEl.hasClass('halfDisabled') || dayEl.hasClass('disabled')) ? false : true;
			});
		}
		// Remove disabled days
		else {
			daysRange = daysRange.filter(function(dayEl) {
				return dayEl.hasClass('disabled') ? false : true;
			});
		}

		// Mark range
		daysRange.each(function(dayEl) {
			// Set styles
			if  ($defined(options.styles)) {
				dayEl.setStyles(styles);
			}

			// Set class name
			if ($defined(options.className)) {
				dayEl.addClass(options.className);
			}

			// Disable day
			if (options.disabled) {
				var monthDay = dayEl.retrieve('day');
				this.disableDay(calednarDate.clone().set('date', monthDay), false);
			}
		}, this);

	},

	disableDay: function(dayDate, noRender) {
		dayDate = dayDate instanceof Date ? dayDate : new Date().parse(dayDate);

		// Render
		if (!noRender) {
			// Get day element
			var dayEl = this.container.getElement(dayDate.format('.year_%Y .month_%m .day_%d'));

			if (dayEl && !dayEl.hasClass('disabled')) {
				dayEl.removeClass('selectable');
				dayEl.addClass('disabled');

				// Disable day
				dayEl.removeEvents();
			}
		}

		// Store disabled days
		var month = dayDate.get('month') +1;
		var year  = dayDate.get('year');
		var date  = dayDate.get('date');

		if (!this.disabled[year][month].contains(date)) {
			this.disabled[year][month].push(date);
			this.enabled[year][month].erase(date);
		}
	},

	enableDay: function(dayDate, noRender) {
		dayDate = dayDate instanceof Date ? dayDate : new Date().parse(dayDate);

		// Render
		if (!noRender) {
			// Get day element
			var dayEl = this.container.getElement(dayDate.format('.year_%Y .month_%m .day_%d'));

			if (dayEl && !dayEl.hasClass('selectable')) {
				dayEl.removeClass('disabled');
				dayEl.addClass('selectable');

				// Enable day
				switch (this.options.mode) {
					case 'single':
						dayEl.addEvent('mousedown', this.selectDay.bind(this, [dayEl, dayDate]));
					break;

					case 'multi':
						dayEl.addEvent('mousedown', this.toggleSelectDay.bind(this, [dayEl, dayDate]));
					break;

					case 'range':
						dayEl.addEvents({
							mousedown:  this.startSelectRange.bind(this),
							mouseup:    this.stopSelectRange.bind(this),
							mouseenter: this.onSelectRange.bind(this)
						});
					break;
				}
			}
		}

		// Store enabled day
		var month = dayDate.get('month') +1;
		var year  = dayDate.get('year');
		var date  = dayDate.get('date');

		if (!this.enabled[year][month].contains(date)) {
			this.enabled[year][month].push(date);
			this.disabled[year][month].erase(date);
		}
	},

	disableDaysRange: function(fromDate, toDate, noRender) {
		fromDate = fromDate instanceof Date ? fromDate : new Date().parse(fromDate);
		toDate   = toDate   instanceof Date ? toDate   : new Date().parse(toDate);


		do {
			this.disableDay(fromDate.clone(), noRender);
			fromDate.increment('day');
		}
		while (fromDate <= toDate);

		if (!noRender) {
			this.render();
		}
	},

	enableDaysRange: function(fromDate, toDate, noRender) {
		fromDate = fromDate instanceof Date ? fromDate : new Date().parse(fromDate);
		toDate   = toDate   instanceof Date ? toDate   : new Date().parse(toDate);


		do {
			this.enableDay(fromDate.clone(), noRender);
			fromDate.increment('day');
		}
		while (fromDate <= toDate);

		if (!noRender) {
			this.render();
		}
	},

	isDayBooked: function(dayDate) {
		// Check if date is in past
		if (this.options.noPast && this.now.diff(dayDate) < 0 ) {
			return true;
		}
		// Check if date is bigger then min limit
		else if (this.options.limit[0] && this.options.limit[0].diff(dayDate) < 0) {
			return true;
		}
		// Check if date is higher then max limit
		else if (this.options.limit[1] && this.options.limit[1].diff(dayDate) > 0) {
			return true;
		}

		// Dates
		var month = dayDate.get('month') +1;
		var year  = dayDate.get('year');
		var date  = dayDate.get('date');

		// Check if date is in booked days
		var monthDays = this.booked[year][month];
		if (monthDays.length && monthDays.indexOf(date) != -1) {
			 return true;
		}

		// Check if date is in enabled days
		var monthDays = this.enabled[year][month];
		if (monthDays.length && monthDays.indexOf(date) != -1) {
			 return false;
		}

		return true;
	},

	isDayDisabled: function(dayDate) {
		// Check if date is in past
		if (this.options.noPast && this.now.diff(dayDate) < 0 ) {
			return true;
		}
		// Check if date is bigger then min limit
		else if (this.options.limit[0] && this.options.limit[0].diff(dayDate) < 0) {
			return true;
		}
		// Check if date is higher then max limit
		else if (this.options.limit[1] && this.options.limit[1].diff(dayDate) > 0) {
			return true;
		}

		// Dates
		var month = dayDate.get('month') +1;
		var year  = dayDate.get('year');
		var date  = dayDate.get('date');

		// Check if date is in booked days
		var monthDays = this.booked[year][month];
		if (monthDays.length && monthDays.indexOf(date) != -1) {
			 return false;
		}
		// Check if date is in enabled days
		var monthDays = this.enabled[year][month];
		if (monthDays.length && monthDays.indexOf(date) != -1) {
			 return false;
		}

		// All days should be disabled
		if (this.options.disableAll) {
			return true;
		}

		// Check if date is in disabled days
		var monthDays = this.disabled[year][month];
		monthDays.indexOf(date) == -1 ? false : true;
	}
});
