!function ($) {
	"use strict";

	$.RangePickerClasses = {
		DAYS:						'range-picker__days',
		DAY:						'range-picker__day',
		DAY_STATE_IN_RANGE:			'range-picker__day_state_in-range'
	}

	var RangePicker = function (elem, options) {
		this.options = $.extend({
			range: {
				start: null,
				end: null
			},
			onRangeSelect: null
		}, options);

		this.dayDateRange = {
			start: this.options.range.start,
			end: this.options.range.end
		};

		this.$elem = $(elem);
		this.initDatepicker();
	}

	$.extend(RangePicker.prototype, {
		initDatepicker: function (e) {

			this.changeRange();
			this.highlightRange();

			$(document).on({
				'mousedown.rangepicker' : $.proxy(this.dayMouseDown, this),
				'mouseup.rangepicker'   : $.proxy(this.dayMouseUp, this)
			}, '.' + $.RangePickerClasses.DAY );
		},

		dayMouseOver: function (e) {
			this.continueRangeSelect(e.currentTarget);

			return false;
		},

		dayMouseDown: function (e) {
			this.startRangeSelect(e.currentTarget);

			return false;
		},

		dayMouseUp: function (e) {
			this.stopRangeSelect();

			return false;
		},

		pickerMouseLeave: function (e) {
			this.stopRangeSelect();

			return false;
		},

		getDate: function(elem) {
			return "" + $(elem).data('year') + $(elem).data('month') + $(elem).data('day');
		},

		inRange: function(dayDate) {
			var dayDateRange = [this.dayDateRange.start, this.dayDateRange.end].sort();

			return dayDate == dayDateRange[0] || dayDate == dayDateRange[1] || (dayDate > dayDateRange[0] && dayDate < dayDateRange[1]);
		},

		setDayDateRange: function(dayDateRange) {
			$.extend(this.dayDateRange, dayDateRange);
		},

		startRangeSelect: function(dayElem) {
			var dayDate = this.getDate(dayElem);

			if(this.inRange(dayDate)) {
				// deselect
				this.setDayDateRange({
					start: null,
					end: null
				});
			} else {
				this.$elem.find('.' + $.RangePickerClasses.DAYS).on('mouseleave.rangepicker', $.proxy(this.pickerMouseLeave, this));
				this.$elem.find('.' + $.RangePickerClasses.DAY).on('mouseover.rangepicker', $.proxy(this.dayMouseOver, this));

				this.setDayDateRange({
					start: dayDate,
					end: null
				});
			}

			this.highlightRange();
		},

		continueRangeSelect: function(dayElem) {
			this.setDayDateRange({
				end: this.getDate(dayElem)
			});

			this.highlightRange();
		},

		stopRangeSelect: function(dayElem) {
			this.$elem.find('.' + $.RangePickerClasses.DAYS).off('mouseleave.rangepicker');
			this.$elem.find('.' + $.RangePickerClasses.DAY).off('mouseover.rangepicker');

			this.changeRange();
			this.$elem.parents('form').submit();
		},

		changeRange: function() {
			if(typeof this.options.onRangeSelect == 'function') {
				var dayDateRange = [this.dayDateRange.start, this.dayDateRange.end].sort();
				this.options.onRangeSelect({
					start: dayDateRange[0],
					end: dayDateRange[1]
				});
			}
		},

		highlightRange: function() {
			var RP = this;

			this.$elem.find('.' + $.RangePickerClasses.DAY)
				.removeClass($.RangePickerClasses.DAY_STATE_IN_RANGE)
				.each(function(){
					var $this = $(this);
					var dayDate = RP.getDate(this);

					if (RP.inRange(dayDate))
						$this.addClass( $.RangePickerClasses.DAY_STATE_IN_RANGE );
				});
		}
	});

	$.fn.rangePicker = function (options) {
		return this.each(function () {
			var $this = $(this),
				data = $this.data('range-picker');

			if (!data)
				$this.data('range-picker', (data = new RangePicker(this, options)));
		})
	}
}(window.jQuery)
