/*!
	ranegPicker v1.0
	(c) 2013 Yair Even Or

	MIT-style license.
*/

; (function ($) {
    "use strict";

    var $doc = $(document),
		RangePicker,
		lastValue,
		// DOM structure
        Template = $('<div class="rangePicker"> \
        				<div class="wrap"> \
							<div class="preset"></div> \
							<div class="custom"> \
								<div class="calendar from"><strong></strong></div> \
								<div class="calendar to"></div> \
								<footer> \
									<button type="button" class="confirm btn btn-primary"></button> \
									<button type="button" class="cancel btn"></button> \
								</footer> \
							</div> \
						</div> \
					</div>');

    RangePicker = function (obj, settings, callback) {
        this.settings = settings;
        this.picker = Template.clone();
        this.obj = $(obj);
        this.callback = typeof callback == 'function' ? callback : null;
        this.result; // the chosen date

        // set direction mode
        if (this.settings.RTL)
            this.picker.addClass('RTL');
        // inject picker
        this.picker.insertAfter(this.obj);

        // for positioning
        this.tether = new Tether({
            element: this.picker,
            target: this.obj,
            attachment: this.settings.RTL ? 'top right' : 'top left',
            targetAttachment: this.settings.RTL ? 'bottom right' : 'bottom left',
            constraints: [{
                to: 'window',
                attachment: 'together'
            }]
        })
    };

    RangePicker.prototype = {
        // prepare the DOM for a new picker
        init: function () {
            var i, len;

            // prevent bubbling of clicking inside the picker to the outside
            this.picker.add(this.obj).on('mousedown', function (e) { e.stopPropagation() });

            var that = this,
                presetWrap = this.picker.find('.preset'),
                presetDefault = null,
                years = '',
                months = '',
                startYear = this.settings.minDate[1],
                endYear = this.settings.maxDate[1],
                totalYears = endYear - startYear,
                month, button, i;

            // add the "custom" preset to the array of presets
            //	this.settings.presets.push({ buttonText:'custom', value:'custom' });

            // presets
            for (i = this.settings.presets.length; i--;) {
                presetWrap.prepend("<button type='button' value='" + this.settings.presets[i].value + "'>" + this.settings.presets[i].buttonText + "</button>");
            }
            this.presets = presetWrap.find('button');

            // add indexes to match them for the right place in the this.result array
            this.calendar = {
                from: this.picker.find('.calendar.from'),
                to: this.picker.find('.calendar.to')
            }

            //2017-04-24init btn text
            this.picker.find('.confirm.btn.btn-primary').html(this.settings.ConfirmBtnText);
            this.picker.find('.cancel.btn').html(this.settings.CancelBtnText);

            // years
            for (i = totalYears + 1; i--;) {
                years += '<option value="' + (endYear - i) + '">' + (endYear - i) + '</option>';
            }

            // months
            for (i = 0, len = this.settings.months.length; i < len; i++) {
                month = '<button>' + this.settings.months[i] + '</button>';
                months += month;
            }

            // generate "custom" markup for years and months
            this.calendar.from.append(
                $('<select>').html(years),  // years.replace(/%%/g,'From - ')
                $('<div>').addClass('months').html(months)
            );

            this.calendar.to.append(this.calendar.from.html());


            this.yearSelectors = this.picker.find('select');
            this.yearSelectors.addClass('form-control');
            // pre-select the last year for the END picker
            // link each <select> to the other one for validation purposes
            this.yearSelectors[0].selectedIndex = this.yearSelectors[1].selectedIndex = totalYears;

            this.bind();
            // preselect years:
            this.yearSelectors.trigger('change');

            if (this.settings.setDate)
                this.update(this.settings.setDate);
        },

        bind: function () {
            var that = this;
            // when clicking the input object bound to this picker, show the picker
            this.obj.on('click', function () { that.show.apply(that) });

            this.picker
                .on('click', '.preset > button', that.presetClick.bind(that))
                .on('click.dp', '.months > button', that.monthClick.bind(that))
                .on('change', 'select', that.changeYear.bind(that))
                .on('click', '.confirm', that.applyDate.bind(that))
                .on('click', '.cancel', that.cancel.bind(that))
        },

        destroy: function () {
            this.picker.remove();
            this.obj.removeData('_ranegPicker');
        },

        show: function () {
            var that = this;

            // hide all other pickers, if present on the page
            $('.rangePicker.show').removeClass('show');

            if (this.picker.hasClass('show')) {
                this.hide();
                return;
            }

            this.picker.addClass('show');
            // close picker when clicking outside
            setTimeout(function () {
                $doc.on('mousedown._rp', function () { that.cancel.apply(that); });
            }, 100);

            this.tether.position();
            this.obj.trigger('datePicker.show');

            //2017-04-24增加,直接进入自定义期间选择
            if (this.settings.onlyCustom) {
                this.changePreset('custom');
            }
        },

        hide: function () {
            this.picker.removeClass('show');
            $doc.off('mousedown._rp');
        },

        cancel: function () {
            // reverse changes
            if(this.obj[0].value) this.update(lastValue);
            this.hide();
        },

        monthClick: function (e) {
            var calendarIdx = $(e.target).parents('.calendar').index(),
                monthIdx = $(e.target).index();

            this.changeMonth(calendarIdx, monthIdx);
        },

        // when clicking the "apply" button
        applyDate: function () {
            this.update();

            if (this.settings.closeOnSelect)
                this.hide();

            this.obj.trigger('datePicker.done', [this.result]);
        },

        presetClick: function (e) {
            this.changePreset(e.target.value);
        },

        // change selected preset and remove the selection from the custom area
        changePreset: function (val) {
            var presetWrap = this.presets.parent();
            this.summary();

            if (val) {
                this.presets.removeClass('selected').filter('[value=' + val + ']').addClass('selected');
                // set the result
                presetWrap.addClass('set');
                // remove the custom range selections

                if (val == 'custom') {
                    this.picker.addClass('custom');
                    this.applyBtnState();
                }
                else {
                    this.result = val;
                    this.picker.find('.months').find('.selected').removeClass('selected');
                    this.picker.removeClass('custom');
                    this.applyDate();
                }
            }
        },

        // make sure the all options for the END year will be valid, relative to the chosen START year
        valideEndYear: function () {
            var index = this.yearSelectors[0].selectedIndex;

            // hide irrelevant options in the END year selector
            this.yearSelectors.eq(1).find('option').hide().slice(index).show();

            if (this.yearSelectors[1].selectedIndex < index) {
                this.yearSelectors[1].selectedIndex = index;
                this.result[1][1] = this.result[0][1]
            }
        },

        // disable irrelevant months
        validMonthsInYear: function (reset) {
            var that = this, monthsElements;

            // both month pickers must be validated because they are "linked" to each-other.
            this.yearSelectors.each(function () {
                monthsElements = $(this).next('.months').find('button');
                // reset all months
                if (reset)
                    monthsElements.prop('disabled', false);
                // for FIRST year
                if (this.selectedIndex == 0)
                    monthsElements.slice(0, that.settings.minDate[0] - 1).prop('disabled', true);

                // for LAST year
                if (this.selectedIndex == (this.length - 1))
                    monthsElements.slice(that.settings.maxDate[0]).prop('disabled', true);

            });
        },

        changeYear: function (e) {
            var that = this,
                calendarIdx = this.yearSelectors.index(e.target); // FROM or TO range

            this.changePreset();

            this.validMonthsInYear(true);

            if (calendarIdx == 0)
                this.valideEndYear();

            if (typeof this.result != 'object')
                this.result = [[], []];

            // on year change, reset last selected month
            $(e.target).next('.months').find('.selected').removeAttr('class');
            this.result[calendarIdx][0] = undefined;

            // set the result
            this.result[calendarIdx][1] = e.target.value | 0;

            // disable the dates of the "TO" calendar which are in the relative past
            if (calendarIdx == 1)
                this.picker.find('.calendar.from').find('.selected').trigger('click.dp');

            this.summary();
            this.applyBtnState();
        },

        // validate months in one picker, relative to the other, to prevent "illegal" time-frame selections
        changeMonth: function (calendarIdx, monthIdx) {
            var that = this,
                monthBtn = this.picker.find('.calendar').eq(calendarIdx).find('button').eq(monthIdx);

            monthBtn.addClass('selected').siblings().removeClass('selected');

            // it can also be a "string" when a preset was previously selected,so the result object needs to be reset
            if (typeof this.result != 'object') {
                this.result = [[undefined, this.yearSelectors[0].value | 0], [undefined, this.yearSelectors[1].value | 0]];
            }

            this.result[calendarIdx][0] = monthIdx + 1;

            this.changePreset();

            // if both month pickers are currently at the same year, disable the END month which are in the "relative" past
            // & only the START month picker should affect the END picker and disable its "past" buttons
            if (this.result[0][1] == this.result[1][1] && calendarIdx == 0) {
                this.picker.find('.calendar.to').find('button').prop('disabled', false).slice(0, monthIdx).prop('disabled', true).removeClass('selected');

                // update the result if the "TO" value is now invalid because it's in the relative PAST to the "FROM" value
                if (this.result[0][0] > this.result[1][0])
                    this.result[1][0] = '';

                // if is also the last available year
                if (this.result[0][1] == this.settings.maxDate[1])
                    this.validMonthsInYear(false);
            }

            // set the year (should happen here as well)
            this.result[0][1] = this.yearSelectors[0].value;
            this.result[1][1] = this.yearSelectors[1].value;

            this.applyBtnState(!this.validateResult());
        },

        // update the state (disabled/enabled) of the control buttons (apply)
        applyBtnState: function (state) {
            if (state !== false)
                state = (typeof this.result == 'string') || !this.validateResult();

            this.picker.find('.confirm').prop('disabled', state);
        },

        // validate the result object
        // disable the "apply" button if validation fails
        validateResult: function (result) {
            result = result || this.result;

            if (typeof this.result == 'object') {
                if (result[0].length < 2 || result[1].length < 2
                    || !result[0][0] || !result[1][0]  // if there is no value
                    || result[0][1] < this.settings.minDate[1] || result[0][1] > this.settings.maxDate[1] // if START year is in the range
                    || result[1][1] < this.settings.minDate[1] || result[1][1] > this.settings.maxDate[1] // if END year is in the range
                    || result[0][1] > result[1][1]  // if START year is bigger than END year
                    || result[0][0] < 0 || result[0][0] > 12 || result[1][0] < 0 || result[1][0] > 12
                    || (result[0][1] == result[1][1] && result[0][0] > result[1][0])  // if START year == END year, then START month should be before the END month in the timeframe
                )
                    return false;
            }

            return true;
        },

        changeCalendar: function (result) {
            if (!this.validateResult(result))
                return false;

            var that = this;

            // Years
            this.yearSelectors[0].value = +result[0][1];
            this.yearSelectors[1].value = +result[1][1];
            this.valideEndYear();


            // Months
            this.validMonthsInYear(true);
            this.picker.find('.months').each(function (i) {
                that.changeMonth(i, result[i][0] - 1);
            });

            this.summary();
            return this;
        },

        summary: function (calendarIdx) {
            if (!this.result)
                return this;

            var from = '',
                to = '';

            if (typeof this.result != 'string') {
                if (this.result[0][0] && this.result[0][1])
                    from = '<span>' + this.displayValue('%S') + '</span>';
                if (this.result[1][0] && this.result[1][1])
                    to = '<span>' + this.displayValue('%E') + '</span>';
            }

            this.calendar.from.find('strong').html(from);
            this.calendar.to.find('strong').html(to);
        },

        // human-readable format for custom date
        displayValue: function (format) {
            format = format || '%S - %E';

            format = format.replace('%S', this.result[0][1] + '-' + this.settings.months[this.result[0][0] - 1]);
            format = format.replace('%E', this.result[1][1] + '-' + this.settings.months[this.result[1][0] - 1]);

            return format;
        },

        update: function (result) {
            var displayValue = '';

            if (result) {
                this.result = result;
                // if it's a preset
                if (typeof result == 'string') {
                    this.changePreset(result);
                    return this;
                }

                if (!this.changeCalendar(result))
                    return this;

                this.changePreset('custom');
            }

            result = result || this.result || this.settings.presets[0].value;

            // update the object which had triggered rangePicker
            if (typeof result == 'string') {
                for (var i = this.settings.presets.length; i--;) {
                    if (this.settings.presets[i].value == result) {
                        displayValue = this.settings.presets[i].displayText;
                        break;
                    }
                }
            }
            else { // parse it
                displayValue = this.displayValue();

                // normalize result type to "Number"
                result[0][1] = +result[0][1];
                result[1][1] = +result[1][1];
            }


            if (displayValue != undefined)
                this.obj[0].value = displayValue;

            lastValue = (typeof result == 'string') ? result : $.extend(true, {}, result);

            this.result = result;

            return this;
        }
    };


    ////////////////////////////////////
    // jQuery plugin intitilization

    $.fn.rangePicker = function (settings, callback) {
        return this.each(function () {
            var $obj = $(this),
				$settings,
				rangePicker;

            if ($obj.data('_ranegPicker')) {
                rangePicker = $obj.data('_ranegPicker');

                if (settings.setDate)
                    rangePicker.update(settings.setDate);

                return this;
            }
            else
                $settings = $.extend(true, {}, $.fn.rangePicker.defaults, settings || {});

            // when calling rangePicker without any settings, only callback
            if (typeof settings == 'function')
                callback = settings;

            rangePicker = new RangePicker($obj, $settings, callback);
            rangePicker.init();

            // save this instance on the element it's bound to
            $obj.data('_ranegPicker', rangePicker);
        });
    };

    ////////////////////////////////////
    // Defaults

    $.fn.rangePicker.defaults = {
        RTL: false,
        closeOnSelect: true,
        //2017-04-24 删除,因为不需要左边的预设,原版请参照https://github.com/yairEO/dateRangePicker/tree/gh-pages
        //presets: [{
        //    buttonText: '1 month',
        //    displayText: 'one month',
        //    value: '1m'
        //}, {
        //    buttonText: '3 months',
        //    displayText: 'three months',
        //    value: '3m'
        //}, {
        //    buttonText: '6 months',
        //    displayText: 'six months',
        //    value: '6m'
        //}, {
        //    buttonText: '12 months',
        //    displayText: 'twelve months',
        //    value: '12m',
        //}, {
        //    buttonText: 'Custom',
        //    displayText: 'twelve months',
        //    value: 'custom'
        //}],
        presets: [],
        months: ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'],
        minDate: [5, 2006],
        maxDate: [8, 2013],
        setDate: null,
        //2017-04-24 增设是否只有自定义,直接在打开时执行一次自定义选择事件
        onlyCustom: false,
        ConfirmBtnText: 'Apply',
        CancelBtnText: 'Cancel'
    };

})(window.jQuery);