class Time {
    /**
     * @param time - Time string in format 'hh:mm:ss:ms am/pm'
     */
    constructor(time = '') {
        /**
         * Hour in 24-hour format
         */
        this.hour = 12;
        /**
         * Minute
         */
        this.minute = 0;
        /**
         * Second
         */
        this.second = 0;
        /**
         * Millisecond
         */
        this.millisecond = 0;
        /**
         * Time string in format 'hh:mm:ss:ms am/pm'
         */
        this._time = '';
        /**
         * Period of the day - am or pm
         */
        this._period = 'am';
        /**
         * State of the day - day or night
         */
        this._state = 'day';
        /**
         * Format of the time string
         *
         * t - 12-hour format
         * T - 24-hour format
         * tt - 12-hour format with seconds
         * TT - 24-hour format with seconds
         * ttt - 12-hour format with seconds and milliseconds
         * TTT - 24-hour format with seconds and milliseconds
         */
        this._format = 'TT';
        this._parseTime(time);
        this._parseState();
    }
    /**
     * Parse the time from string
     */
    _parseTime(time) {
        if (time == '') {
            return;
        }
        if (time == 'now') {
            const date = new Date();
            this.hour = date.getHours();
            this.minute = date.getMinutes();
            this.second = date.getSeconds();
            this.millisecond = date.getMilliseconds();
            time = `${this.hour}:${this.minute}:${this.second}:${this.millisecond}`;
        }
        this._time = time.toLowerCase();
        const phases = this._time.split(/[ :]/);
        const periodIndex = phases.findIndex(i => ['am', 'pm'].includes(i));
        if ((periodIndex == -1 && phases.length > 5)
            || (periodIndex != -1 && phases.length > 4)) {
            throw new Error('Invalid time format');
        }
        if (periodIndex != -1) {
            this._period = phases[periodIndex];
            phases.splice(periodIndex, 1);
        }
        else {
            this._period = 'am';
        }
        switch (phases.length) {
            case 4:
                this.millisecond = parseInt(phases[3]);
            case 3:
                this.second = parseInt(phases[2]);
            case 2:
                this.minute = parseInt(phases[1]);
            case 1:
                this.hour = parseInt(phases[0]);
                if (Number.isNaN(this.hour)) {
                    this.hour = 0;
                }
                if (this._period == 'pm' && this.hour < 12) {
                    this.hour += 12;
                }
            default:
                if (this.hour > 12) {
                    this._period = 'pm';
                }
        }
    }
    /**
     * Parse the state of the day
     */
    _parseState() {
        if (this.hour >= 6 && this.hour < 18) {
            this._state = 'day';
        }
        else {
            this._state = 'night';
        }
    }
    /**
     * Set the time output format
     */
    setFormat(format) {
        this._format = format;
        return this;
    }
    /**
     * Set the time period and hour of the day
     */
    setPeriodHour(hour, period = null) {
        if (Number.isNaN(hour)) {
            this.hour = NaN;
        }
        if (hour > 24 || hour < 0) {
            return this;
        }
        if (period == null && hour > 12) {
            period = 'pm';
        }
        this._period = period || this._period;
        this.hour = hour;
        if (this._period == 'pm' && this.hour < 12) {
            this.hour += 12;
        }
        this._parseState();
        return this;
    }
    /**
     * Set the time hour
     */
    setHour(hour) {
        this.hour = hour;
        this._parseState();
        return this;
    }
    /**
     * Set the time minute
     */
    setMinute(minute) {
        this.minute = minute;
        return this;
    }
    /**
     * Set the time seconds
     */
    setSecond(second) {
        this.second = second;
        return this;
    }
    /**
     * Set the time milliseconds
     */
    setMillisecond(millisecond) {
        this.millisecond = millisecond;
        return this;
    }
    /**
     * Get the time period hour
     */
    getPeriodHour() {
        const hour = this.hour % 12;
        return hour == 0 ? 12 : hour;
    }
    /**
     * Get the time period of the day
     */
    getPeriod() {
        return this._period;
    }
    /**
     * Get the time state of the day
     */
    getState() {
        return this._state;
    }
    /**
     * Return the fime formated in string
     */
    toString() {
        if ([this.hour, this.minute, this.second, this.millisecond].some(v => isNaN(v))) {
            return '';
        }
        switch (this._format) {
            case 't':
                return `${this.getPeriodHour().toString().padStart(2, '0')}:${this.minute.toString().padStart(2, '0')} ${this._period}`;
            case 'T':
                return `${this.hour.toString().padStart(2, '0')}:${this.minute.toString().padStart(2, '0')}`;
            case 'tt':
                return `${this.getPeriodHour().toString().padStart(2, '0')}:${this.minute.toString().padStart(2, '0')}:${this.second.toString().padStart(2, '0')} ${this._period}`;
            case 'TT':
                return `${this.hour.toString().padStart(2, '0')}:${this.minute.toString().padStart(2, '0')}:${this.second.toString().padStart(2, '0')}`;
            case 'ttt':
                return `${this.getPeriodHour().toString().padStart(2, '0')}:${this.minute.toString().padStart(2, '0')}:${this.second.toString().padStart(2, '0')}:${this.millisecond.toString().padStart(3, '0')} ${this._period}`;
            case 'TTT':
                return `${this.hour.toString().padStart(2, '0')}:${this.minute.toString().padStart(2, '0')}:${this.second.toString().padStart(2, '0')}:${this.millisecond.toString().padStart(3, '0')}`;
            default:
                return `${this.hour.toString().padStart(2, '0')}:${this.minute.toString().padStart(2, '0')}`;
        }
    }
    /**
     * Parse the time string
     */
    parse(time = '') {
        this._parseTime(time);
        this._parseState();
        return this;
    }
    /**
     * Get the current time
     */
    static now() {
        return new Time('now');
    }
    /**
     * Parse the time string
     */
    static parse(time) {
        return new Time(time);
    }
}
export default Time;
