import { Dom } from 'datatables.net';

/*! DateTime for DataTables.net
 * Copyright (c) SpryMedia Ltd - datatables.net/license
 */

declare class DateTime {
    /**
     * Use a specific compatible date library
     */
    static use(lib: any): void;
    /**
     * For generating unique namespaces
     */
    private static _instance;
    /**
     * To indicate to DataTables what type of library this is
     */
    static type: string;
    /**
     * Defaults for the date time picker
     */
    static defaults: Defaults;
    static version: string;
    /**
     * Destroy the control
     */
    destroy(): void;
    display(year: any, month: any): this | {
        month: number;
        year: number;
    };
    errorMsg(msg: any): this;
    hide(): this;
    max(date: any): this;
    min(date: any): this;
    /**
     * Check if an element belongs to this control
     *
     * @param  {node} node Element to check
     * @return {boolean}   true if owned by this control, false otherwise
     */
    owns(node: any): boolean;
    /**
     * Get the value
     */
    val(): Date;
    /**
     * Set the value
     *
     * @param set Value to set
     * @param write Flag to indicate if the formatted value
     *   should be written into the input element
     */
    val(set: string | Date, write?: boolean): any;
    /**
     * Similar to `val()` but uses a given date / time format
     *
     * @param format Format to get the data as (getter) or that is input
     *   (setter)
     * @param val Value to write (if undefined, used as a getter)
     * @returns
     */
    valFormat(format: any, val: any): any;
    private dom;
    private c;
    private s;
    constructor(input: any, opts: any);
    /**
     * Build the control and assign initial event handlers
     */
    private _init;
    /**
     * Compare the date part only of two dates - this is made super easy by the
     * toDateString method!
     *
     * @param a Date 1
     * @param b Date 2
     */
    private _compareDates;
    /**
     * Convert from one format to another
     *
     * @param val Value
     * @param from Format to convert from. If null a `Date` must be given
     * @param to Format to convert to. If null a `Date` will be returned
     * @returns Converted value
     */
    private _convert;
    /**
     * When changing month, take account of the fact that some months don't have
     * the same number of days. For example going from January to February you
     * can have the 31st of Jan selected and just add a month since the date
     * would still be 31, and thus drop you into March.
     *
     * @param date  Date - will be modified
     * @param month Month to set
     */
    private _correctMonth;
    /**
     * Get the number of days in a method. Based on
     * http://stackoverflow.com/a/4881951 by Matti Virkkunen
     *
     * @param  year  Year
     * @param  month Month (starting at 0)
     */
    private _daysInMonth;
    /**
     * Create a new date object which has the UTC values set to the local time.
     * This allows the local time to be used directly for the library which
     * always bases its calculations and display on UTC.
     *
     * @param  s Date to "convert"
     * @return Shifted date
     */
    private _dateToUtc;
    /**
     * Create a UTC ISO8601 date part from a date object
     *
     * @param  d Date to "convert"
     * @return ISO formatted date
     */
    private _dateToUtcString;
    /**
     * Hide the control and remove events related to its display
     *
     * @param destroy Flag to indicate that the instance is being destroyed
     */
    private _hide;
    /**
     * Convert a 24 hour value to a 12 hour value
     *
     * @param val 24 hour value
     * @return 12 hour value
     */
    private _hours24To12;
    /**
     * Generate the HTML for a single day in the calendar - this is basically
     * and HTML cell with a button that has data attributes so we know what was
     * clicked on (if it is clicked on) and a bunch of classes for styling.
     *
     * @param  {object} day Day object from the `_htmlMonth` method
     * @return {string}     HTML cell
     */
    private _htmlDay;
    /**
     * Create the HTML for a month to be displayed in the calendar table.
     *
     * Based upon the logic used in Pikaday - MIT licensed
     * Copyright (c) 2014 David Bushell
     * https://github.com/dbushell/Pikaday
     *
     * @param  year  Year
     * @param  month Month (starting at 0)
     * @return Calendar month HTML
     */
    private _htmlMonth;
    /**
     * Create the calendar table's header (week days)
     *
     * @return {string} HTML cells for the row
     */
    private _htmlMonthHead;
    /**
     * Create a cell that contains week of the year - ISO8601
     *
     * Based on https://stackoverflow.com/questions/6117814/ and
     * http://techblog.procurios.nl/k/n618/news/view/33796/14863/
     *
     * @param  d Day of month
     * @param  m Month of year (zero index)
     * @param  y Year
     * @return HTML string for a day
     */
    private _htmlWeekOfYear;
    /**
     * Determine if Luxon is being used
     *
     * @returns Flag for Luxon
     */
    private _isLuxon;
    /**
     * Determine if Moment is being used
     *
     * @returns Flag for Moment
     */
    private _isMoment;
    /**
     * Determine the first day of the week based on the current locale
     */
    private _localeFirstDay;
    /**
     * Check if the instance has a date object value - it might be null.
     * If is doesn't set one to now.
     * @returns A Date object
     */
    private _needValue;
    /**
     * Create option elements from a range in an array
     *
     * @param selector Class name unique to the select element to use
     * @param values   Array of values
     * @param labels Array of labels. If given must be the same length as the
     *   values parameter.
     */
    private _options;
    /**
     * Set an option and update the option's span pair (since the select element
     * has opacity 0 for styling)
     *
     * @param selector Class name unique to the select element to use
     * @param val      Value to set
     */
    private _optionSet;
    /**
     * Create time options list.
     *
     * @param unit Time unit - hours, minutes or seconds
     * @param count Count range - 12, 24 or 60
     * @param val Existing value for this unit
     * @param allowed Values allow for selection
     * @param range Override range
     */
    private _optionsTime;
    /**
     * Create the options for the month and year
     */
    private _optionsTitle;
    /**
     * Simple two digit pad
     *
     * @param  {integer} i      Value that might need padding
     * @return {string|integer} Padded value
     */
    private _pad;
    /**
     * Position the calendar to look attached to the input element
     */
    private _position;
    /**
     * Create a simple array with a range of values
     *
     * @param  start   Start value (inclusive)
     * @param  end     End value (inclusive)
     * @param  inc Increment value
     * @return Created array
     */
    private _range;
    /**
     * Redraw the calendar based on the display date - this is a destructive
     * operation
     */
    private _setCalander;
    /**
     * Set the month and year for the calendar based on the current display date
     */
    private _setTitle;
    /**
     * Set the time based on the current value of the widget
     */
    private _setTime;
    /**
     * Show the widget and add events to the document required only while it
     * is displayed
     *
     */
    private _show;
    /**
     * Write the formatted string to the input element this control is attached
     * to
     */
    private _writeOutput;
}

type DeepPartial<T> = T extends object ? {
    [P in keyof T]?: DeepPartial<T[P]>;
} : T;
interface Defaults {
    /** Makes the date picker always display. */
    alwaysVisible: boolean;
    /**
     * If the picker element should be inserted next to the `<input>` or to the
     * `<body>`.
     */
    attachTo: 'body' | 'input';
    /** Display control buttons */
    buttons: {
        /** Enable button to clear the value */
        clear: boolean;
        /** Enable button move the current value into view */
        selected: boolean;
        /** Enable button move "today" into view */
        today: boolean;
    };
    classPrefix: string;
    /** Specify days that cannot be selected. */
    disableDays: number[] | null | ((day: Date) => boolean);
    /** Initial picker month / year to show. `null` will default to current */
    display: {
        year: number;
        month: number;
    } | null;
    /**
     * First day of the week. (0: Sunday, 1: Monday, etc). If `null` then
     * automatic detection will be used based on the user's locale.
     */
    firstDay: number | null;
    /** The format of the date data. */
    format: string;
    /** Sets which hours are selectable. */
    hoursAvailable: number[] | null;
    /** Language strings for DateTime */
    i18n: DTLanguage;
    /** Set the maximum date that can be selected and displayed. */
    maxDate: Date | null;
    /** Set the minimum date that can be selected and displayed. */
    minDate: Date | null;
    /** Sets which minutes are selectable. */
    minutesAvailable: number[] | null;
    /** strict parameter passed to Luxon or Moment */
    strict: boolean;
    /** locale parameter passed to Luxon or Moment */
    locale: string;
    /**
     * Function that is called whenever the value selected for DateTime changes.
     *
     * @param value New text value
     * @param date Date value
     * @param el The input host
     */
    onChange: (value: string, date: Date, el: HTMLElement) => void;
    /** Sets which seconds are selectable. */
    secondsAvailable: number[] | null;
    /**
     * Show the ISO week number at the head of the row
     */
    showWeekNumber: boolean;
    /**
     * The range of years provided for selection. Note that this option can be
     * overruled by max / min date.
     */
    yearRange: number;
    /** @deprecated */
    minutesIncrement: number;
    /** @deprecated */
    secondsIncrement: number;
}
interface Options extends DeepPartial<Defaults> {
}

declare module 'datatables.net' {
    interface DataTablesStatic {
        DateTime: typeof DateTime;
    }
    interface Language {
        datetime: DTLanguage;
    }
}
interface DTLanguage {
    clear: string;
    previous: string;
    next: string;
    months: string[];
    weekdays: string[];
    amPm: string[];
    hours: string;
    minutes: string;
    seconds: string;
    today: string;
    selected: string;
    unknown: string;
}
interface Settings {
    d: Date | null;
    display: Date | null;
    minutesRange: number | null;
    secondsRange: number | null;
    namespace: string;
    parts: {
        date: boolean;
        time: boolean;
        seconds: boolean;
        hours12: boolean;
    };
    showTo: null | ReturnType<typeof setTimeout>;
}
interface DomInternal {
    container: Dom;
    date: Dom;
    title: Dom;
    calendar: Dom;
    time: Dom;
    error: Dom;
    buttons: Dom;
    clear: Dom;
    today: Dom;
    selected: Dom;
    previous: Dom;
    next: Dom;
    input: Dom<HTMLInputElement>;
}

export { DateTime as default };
export type { DTLanguage, Defaults, DomInternal, Options, Settings };
