import { get } from '../moment/get-set'; import hasOwnProp from '../utils/has-own-prop'; import { addFormatToken } from '../format/format'; import { addUnitAlias } from './aliases'; import { addUnitPriority } from './priorities'; import { addRegexToken, match1to2, match2, matchWord, regexEscape } from '../parse/regex'; import { addParseToken } from '../parse/token'; import { hooks } from '../utils/hooks'; import { MONTH } from './constants'; import toInt from '../utils/to-int'; import isArray from '../utils/is-array'; import isNumber from '../utils/is-number'; import indexOf from '../utils/index-of'; import { createUTC } from '../create/utc'; import getParsingFlags from '../create/parsing-flags';

export function daysInMonth(year, month) {

return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();

}

// FORMATTING

addFormatToken('M', ['MM', 2], 'Mo', function () {

return this.month() + 1;

});

addFormatToken('MMM', 0, 0, function (format) {

return this.localeData().monthsShort(this, format);

});

addFormatToken('MMMM', 0, 0, function (format) {

return this.localeData().months(this, format);

});

// ALIASES

addUnitAlias('month', 'M');

// PRIORITY

addUnitPriority('month', 8);

// PARSING

addRegexToken('M', match1to2); addRegexToken('MM', match1to2, match2); addRegexToken('MMM', function (isStrict, locale) {

return locale.monthsShortRegex(isStrict);

}); addRegexToken('MMMM', function (isStrict, locale) {

return locale.monthsRegex(isStrict);

});

addParseToken(['M', 'MM'], function (input, array) {

array[MONTH] = toInt(input) - 1;

});

addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {

var month = config._locale.monthsParse(input, token, config._strict);
// if we didn't find a month name, mark the date as invalid.
if (month != null) {
    array[MONTH] = month;
} else {
    getParsingFlags(config).invalidMonth = input;
}

});

// LOCALES

var MONTHS_IN_FORMAT = /D?([[^[]]*]|s)+MMMM?/; export var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'); export function localeMonths (m, format) {

if (!m) {
    return isArray(this._months) ? this._months :
        this._months['standalone'];
}
return isArray(this._months) ? this._months[m.month()] :
    this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];

}

export var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'); export function localeMonthsShort (m, format) {

if (!m) {
    return isArray(this._monthsShort) ? this._monthsShort :
        this._monthsShort['standalone'];
}
return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
    this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];

}

function handleStrictParse(monthName, format, strict) {

var i, ii, mom, llc = monthName.toLocaleLowerCase();
if (!this._monthsParse) {
    // this is not used
    this._monthsParse = [];
    this._longMonthsParse = [];
    this._shortMonthsParse = [];
    for (i = 0; i < 12; ++i) {
        mom = createUTC([2000, i]);
        this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
        this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
    }
}

if (strict) {
    if (format === 'MMM') {
        ii = indexOf.call(this._shortMonthsParse, llc);
        return ii !== -1 ? ii : null;
    } else {
        ii = indexOf.call(this._longMonthsParse, llc);
        return ii !== -1 ? ii : null;
    }
} else {
    if (format === 'MMM') {
        ii = indexOf.call(this._shortMonthsParse, llc);
        if (ii !== -1) {
            return ii;
        }
        ii = indexOf.call(this._longMonthsParse, llc);
        return ii !== -1 ? ii : null;
    } else {
        ii = indexOf.call(this._longMonthsParse, llc);
        if (ii !== -1) {
            return ii;
        }
        ii = indexOf.call(this._shortMonthsParse, llc);
        return ii !== -1 ? ii : null;
    }
}

}

export function localeMonthsParse (monthName, format, strict) {

var i, mom, regex;

if (this._monthsParseExact) {
    return handleStrictParse.call(this, monthName, format, strict);
}

if (!this._monthsParse) {
    this._monthsParse = [];
    this._longMonthsParse = [];
    this._shortMonthsParse = [];
}

// TODO: add sorting
// Sorting makes sure if one month (or abbr) is a prefix of another
// see sorting in computeMonthsParse
for (i = 0; i < 12; i++) {
    // make the regex if we don't have it already
    mom = createUTC([2000, i]);
    if (strict && !this._longMonthsParse[i]) {
        this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
        this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
    }
    if (!strict && !this._monthsParse[i]) {
        regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
        this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
    }
    // test the regex
    if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
        return i;
    } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
        return i;
    } else if (!strict && this._monthsParse[i].test(monthName)) {
        return i;
    }
}

}

// MOMENTS

export function setMonth (mom, value) {

var dayOfMonth;

if (!mom.isValid()) {
    // No op
    return mom;
}

if (typeof value === 'string') {
    if (/^\d+$/.test(value)) {
        value = toInt(value);
    } else {
        value = mom.localeData().monthsParse(value);
        // TODO: Another silent failure?
        if (!isNumber(value)) {
            return mom;
        }
    }
}

dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
return mom;

}

export function getSetMonth (value) {

if (value != null) {
    setMonth(this, value);
    hooks.updateOffset(this, true);
    return this;
} else {
    return get(this, 'Month');
}

}

export function getDaysInMonth () {

return daysInMonth(this.year(), this.month());

}

var defaultMonthsShortRegex = matchWord; export function monthsShortRegex (isStrict) {

if (this._monthsParseExact) {
    if (!hasOwnProp(this, '_monthsRegex')) {
        computeMonthsParse.call(this);
    }
    if (isStrict) {
        return this._monthsShortStrictRegex;
    } else {
        return this._monthsShortRegex;
    }
} else {
    if (!hasOwnProp(this, '_monthsShortRegex')) {
        this._monthsShortRegex = defaultMonthsShortRegex;
    }
    return this._monthsShortStrictRegex && isStrict ?
        this._monthsShortStrictRegex : this._monthsShortRegex;
}

}

var defaultMonthsRegex = matchWord; export function monthsRegex (isStrict) {

if (this._monthsParseExact) {
    if (!hasOwnProp(this, '_monthsRegex')) {
        computeMonthsParse.call(this);
    }
    if (isStrict) {
        return this._monthsStrictRegex;
    } else {
        return this._monthsRegex;
    }
} else {
    if (!hasOwnProp(this, '_monthsRegex')) {
        this._monthsRegex = defaultMonthsRegex;
    }
    return this._monthsStrictRegex && isStrict ?
        this._monthsStrictRegex : this._monthsRegex;
}

}

function computeMonthsParse () {

function cmpLenRev(a, b) {
    return b.length - a.length;
}

var shortPieces = [], longPieces = [], mixedPieces = [],
    i, mom;
for (i = 0; i < 12; i++) {
    // make the regex if we don't have it already
    mom = createUTC([2000, i]);
    shortPieces.push(this.monthsShort(mom, ''));
    longPieces.push(this.months(mom, ''));
    mixedPieces.push(this.months(mom, ''));
    mixedPieces.push(this.monthsShort(mom, ''));
}
// Sorting makes sure if one month (or abbr) is a prefix of another it
// will match the longer piece.
shortPieces.sort(cmpLenRev);
longPieces.sort(cmpLenRev);
mixedPieces.sort(cmpLenRev);
for (i = 0; i < 12; i++) {
    shortPieces[i] = regexEscape(shortPieces[i]);
    longPieces[i] = regexEscape(longPieces[i]);
}
for (i = 0; i < 24; i++) {
    mixedPieces[i] = regexEscape(mixedPieces[i]);
}

this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
this._monthsShortRegex = this._monthsRegex;
this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');

}