'use strict';

const translations = require('./translations-6b7628ed.js');

class DatePickerService {
    constructor(locale, language, timezone, format) {
        this.locale = locale;
        this.language = language;
        this.timezone = timezone;
        this.format = format;
        if (!this.locale) {
            this.locale = 'en-US';
        }
        this.locale = safeLocale(this.locale);
        if (!this.format) {
            this.format = (translations.STANDARD_LOCALES[this.locale]) ? translations.STANDARD_LOCALES[this.locale] : 'dd/MM/yyyy';
        }
        if (!this.language) {
            this.language = this.locale.split('-')[0];
        }
        this.timezone = timezone;
    }
    // Timezone-override aware date conversion
    convertToDate(input) {
        if (!input || !this.newDateFromValue(input)) {
            return null;
        }
        if (!this.timezone) {
            return new Date(input);
        }
        const localDateString = new Date(input).toLocaleDateString();
        const tzTime = new Date(localDateString).toLocaleString(undefined, { timeZone: this.timezone });
        const localDate = Number(new Date(input));
        const tzDate = Number(new Date(tzTime));
        let convertedDate;
        if (localDate >= tzDate) {
            const variance = localDate - tzDate;
            convertedDate = new Date(localDate + variance);
        }
        else {
            const variance = tzDate - localDate;
            convertedDate = new Date(localDate - variance);
        }
        return convertedDate;
    }
    dayOfFirst(year, month) {
        return new Date(year, month, 1).getDay();
    }
    daysInMonth(year, month) {
        return new Date(year, month + 1, 0).getDate();
    }
    isDisabled(evalDate, dateRangeParams) {
        if (!dateRangeParams) {
            return false;
        }
        const dayIsBeforeMinDate = (dateRangeParams.minDate) ? evalDate < dateRangeParams.minDate : false;
        const dayIsAfterMaxDate = (dateRangeParams.maxDate) ? evalDate > dateRangeParams.maxDate : false;
        return dayIsBeforeMinDate || dayIsAfterMaxDate;
    }
    getCalendarDate(value, rangeParams) {
        if (rangeParams && rangeParams.minDate
            && (!value || isNaN(value.valueOf()) || value.valueOf() < rangeParams.minDate.valueOf())) {
            value = this.newDateFromValue(rangeParams.minDate);
        }
        else if (rangeParams && rangeParams.maxDate
            && (!value || isNaN(value.valueOf()) || value.valueOf() > rangeParams.maxDate.valueOf())) {
            value = this.newDateFromValue(rangeParams.maxDate);
        }
        else if (!value || isNaN(value.valueOf())) {
            value = this.newDateFromValue();
        }
        return value;
    }
    getMonthInfo(year, month) {
        return new Date(year, month, 15);
    }
    month(date) {
        return date.getMonth();
    }
    newDateFromArray(year, month, day) {
        return new Date(year, month, day);
    }
    newDateFromValue(value) {
        const newValue = (value) ? new Date(value) : new Date();
        return (newValue.toString() === 'Invalid Date') ? null : newValue;
    }
    prepHeaderDate(date) {
        return localize(this.locale, date, { weekday: 'short', month: 'short', day: 'numeric' });
    }
    prepHeaderYear(date) {
        return localize(this.locale, date, { year: 'numeric' });
    }
    sameDay(_calendarDay, _comparator) {
        return _calendarDay.day === _comparator.getDate()
            && _calendarDay.month === _comparator.getMonth()
            && _calendarDay.year === _comparator.getFullYear();
    }
    year(date) {
        return date.getFullYear();
    }
    weekdays() {
        return getWeekdays(this.language);
    }
    months() {
        return getMonths(this.language);
    }
    localize(date) {
        return new Date(date).toLocaleDateString(this.locale, { month: '2-digit', day: '2-digit', year: 'numeric' });
    }
    prepDateStringOutput(input) {
        if (!input) {
            return null;
        }
        else if (typeof input === 'string') {
            return input;
        }
        else if (this.timezone) {
            // Timezone-override aware formatting
            const tzTime = new Date(input).toLocaleString(undefined, { timeZone: this.timezone });
            return this.localize(new Date(tzTime));
        }
        else {
            return this.localize(input);
        }
    }
    processDateInput(input) {
        if (!input) {
            return null;
        }
        if (typeof input === 'string') {
            // Remove any time notation by splitting on spaces or commas
            const regexSplit = input.split(/[ ,]+/g).filter(Boolean);
            const dateSegments = parseInput(regexSplit[0], this.format);
            if (dateSegments && Array.isArray(dateSegments.splitDate) && dateSegments.splitDate.length === 3 && dateSegments.year) {
                return new Date(parseInt(dateSegments.year, 10), parseInt(dateSegments.month, 10) - 1, parseInt(dateSegments.day, 10));
            }
            else {
                return new Date(input);
            }
        }
        else {
            return input;
        }
    }
}
function getWeekdays(locale) {
    const weekdays = [];
    for (let i = 0; i < 7; i++) {
        const date = new Date();
        const testDate = date.setDate(date.getDate() - date.getDay() + i);
        weekdays.push(localize(locale, new Date(testDate), { weekday: 'short' }));
    }
    return weekdays;
}
function getMonths(locale) {
    const months = [];
    for (let i = 0; i < 12; i++) {
        const testDate = new Date().setMonth(i);
        months.push(localize(locale, new Date(testDate), { month: 'short' }));
    }
    return months;
}
function localize(locale = 'en-US', date, options) {
    return new Intl.DateTimeFormat(locale, options).format(date);
}
/* Currently only support shortDate strings (with non-alphanumeric separators) of:
    {
        Month-Day-Year: if included in locale STANDARD_LOCALES,
        Year-Month-Day: if included in locale STANDARD_LOCALES,
        Day-Month-Year: for all locales outside of locale STANDARD_LOCALES
    }
 */
function parseInput(input, format) {
    // Split string on any non-alphanumeric characters, not including spaces
    const splitDate = input.split(/[^\w\s]+/g).filter(Boolean);
    if (splitDate.length <= 1 && input.length <= 8) {
        // Using best guess at a digit-only string evaluation
        return parseDigitOnlyDate(input, format);
    }
    else {
        // Using regex provided segments (or simply pass-through of ISO string)
        const dateSegments = {
            splitDate,
            year: '',
            month: '',
            day: ''
        };
        const splitDateCp = splitDate.slice(0);
        // Set year
        const { derivedYear, assumedDay } = setYearSegment(splitDateCp);
        dateSegments.year = derivedYear;
        // Set Day and Month
        Object.assign(dateSegments, setMonthAndDaySegments(splitDateCp, format, assumedDay));
        return dateSegments;
    }
}
function parseDigitOnlyDate(input, format) {
    const dateCreateTests = [];
    const testsFeeder = [];
    // Manipulate string to have the year at the beginning
    const s2DigYear = (format === 'yyyy/M/d') ? input : input.slice(input.length - 2).concat(input.slice(0, input.length - 2));
    const s4DigYear = (format === 'yyyy/M/d') ? input : input.slice(input.length - 4).concat(input.slice(0, input.length - 4));
    // Separate the Year from the Day/Month(dm)
    if (input.length === 8) {
        // YYYYxxxx, xxxxYYYY
        testsFeeder.push({ year: s4DigYear.slice(0, 4), dm: [s4DigYear.slice(4, 6), s4DigYear.slice(6)] });
    }
    else if (input.length === 7) {
        // YYYYxxx, xxxYYYY
        testsFeeder.push({ year: s4DigYear.slice(0, 4), dm: [s4DigYear.slice(4, 6), s4DigYear.slice(6)] });
        testsFeeder.push({ year: s4DigYear.slice(0, 4), dm: [s4DigYear.slice(4, 5), s4DigYear.slice(5)] });
    }
    else if (input.length === 6) {
        // YYYYxx, xxYYYY
        testsFeeder.push({ year: s4DigYear.slice(0, 4), dm: [s4DigYear.slice(4, 5), s4DigYear.slice(5)] });
        // YYxxxx, YYxxxx
        testsFeeder.push({ year: `20${s2DigYear.slice(0, 2)}`, dm: [s2DigYear.slice(2, 4), s2DigYear.slice(4)] });
    }
    else if (input.length === 5) {
        // YYxxx, xxxYY
        testsFeeder.push({ year: `20${s2DigYear.slice(0, 2)}`, dm: [s2DigYear.slice(2, 3), s2DigYear.slice(3)] });
        testsFeeder.push({ year: `20${s2DigYear.slice(0, 2)}`, dm: [s2DigYear.slice(2, 4), s2DigYear.slice(4)] });
    }
    else if (input.length === 4) {
        // YYxx, xxYY
        testsFeeder.push({ year: `20${s2DigYear.slice(0, 2)}`, dm: [s2DigYear.slice(2, 3), s2DigYear.slice(3)] });
    }
    // Intelligently guess which is day/month from dm
    testsFeeder.forEach(set => {
        if (format === 'dd/MM/yyyy') {
            dateCreateTests.push({ year: set.year, month: set.dm[1], day: set.dm[0] });
        }
        else {
            // 'yyyy/M/d', 'M/d/yyyy'
            dateCreateTests.push({ year: set.year, month: set.dm[0], day: set.dm[1] });
        }
    });
    // Filter out unlikely dates
    const unlikelyFilter = t => t.day <= 31 && t.month <= 11 && (t.year > 1900 && t.year < 2200);
    const segments = dateCreateTests.filter(unlikelyFilter)[0];
    if (segments) {
        switch (format) {
            case 'yyyy/M/d':
                segments.splitDate = [segments.year, segments.month, segments.day];
                break;
            case 'dd/MM/yyyy':
                segments.splitDate = [segments.month, segments.day, segments.year];
                break;
            case 'M/d/yyyy':
                segments.splitDate = [segments.month, segments.day, segments.year];
                break;
        }
    }
    return segments;
}
function setYearSegment(splitDateArray) {
    // Find year
    const year = splitDateArray.find(segment => segment.length === 4);
    // Remove year from working array
    const yearIndex = splitDateArray.indexOf(year);
    splitDateArray.splice(yearIndex, 1);
    // If first segment is year, we can safely assume that it was a YYYY-MM-DD format, grab last segment as assumedDay
    const assumedDay = (yearIndex === 0) ? splitDateArray[splitDateArray.length - 1] : undefined;
    return {
        derivedYear: year,
        assumedDay
    };
}
function setMonthAndDaySegments(splitDateArray, format, assumedDay) {
    const segments = {
        day: '',
        month: ''
    };
    // See if we can determine which segment is the days segment
    assumedDay = assumedDay || splitDateArray.find(segment => parseInt(segment, 10) > 12);
    if (assumedDay) {
        segments.day = assumedDay;
        const dayIndex = splitDateArray.indexOf(assumedDay);
        splitDateArray.splice(dayIndex, 1);
        segments.month = splitDateArray[0];
        // Otherwise, make a reasonable guess
    }
    else {
        switch (format) {
            case 'M/d/yyyy':
            case 'yyyy/M/d':
                segments.month = splitDateArray[0];
                segments.day = splitDateArray[1];
                break;
            // Assume 'dd/MM/yyyy' for anything else
            default:
                segments.month = splitDateArray[1];
                segments.day = splitDateArray[0];
                break;
        }
    }
    return segments;
}
function safeLocale(locale) {
    const shortLocale = locale.split(/-|_/)[0];
    const overrides = {
        no: 'nb'
    };
    return (overrides[shortLocale]) ? overrides[shortLocale] : locale;
}

exports.DatePickerService = DatePickerService;
