import { Platform } from '@angular/cdk/platform';
import { CdkPortal } from '@angular/cdk/portal';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Inject, Input, LOCALE_ID, Output, ViewChild, } from '@angular/core';
import { Subject } from 'rxjs';
import { RCalendarTimeModelService, RDateService, } from '../../extra/calendar-kit';
import { range, rangeFromTo } from '../../extra/calendar-kit/helpers';
import { R_TIME_PICKER_CONFIG, } from './model';
/**
 * The TimePicker components itself.
 * Provides a proxy to `TimePicker` options as well as custom picker options.
 */
export class RTimePickerComponent {
    constructor(config, platformService, locale, cd, calendarTimeModelService, dateService) {
        this.config = config;
        this.platformService = platformService;
        this.cd = cd;
        this.calendarTimeModelService = calendarTimeModelService;
        this.dateService = dateService;
        this.blur$ = new Subject();
        this.dayPeriodColumnOptions = ["AM" /* AM */, "PM" /* PM */];
        this.isAM = true;
        /**
         * In timepicker value should be always true
         * In calendar-with-time.component  should set to false
         * @docs-private
         */
        this.showFooter = true;
        this.hoursText = 'Hr';
        this.minutesText = 'Min';
        this.secondsText = 'Sec';
        this.ampmText = 'Am/Pm';
        /**
         * Emits date when selected.
         * */
        this.onSelectTime = new EventEmitter();
        if (config) {
            this.twelveHoursFormat = config.twelveHoursFormat;
        }
        else {
            this.twelveHoursFormat = dateService.getLocaleTimeFormat().includes('h');
        }
    }
    /**
     * Emits when timepicker looses focus.
     */
    get blur() {
        return this.blur$.asObservable();
    }
    /**
     * Defines time format string.
     * */
    get timeFormat() {
        return this._timeFormat;
    }
    set timeFormat(timeFormat) {
        this._timeFormat = timeFormat;
    }
    /**
     * Defines 12 hours format .
     * */
    get twelveHoursFormat() {
        return this._twelveHoursFormat;
    }
    set twelveHoursFormat(value) {
        this._twelveHoursFormat = !!value;
    }
    /**
     * Show seconds in timepicker.
     * Ignored when singleColumn is true
     * */
    get withSeconds() {
        return this._withSeconds;
    }
    set withSeconds(value) {
        this._withSeconds = !!value;
    }
    /**
     * Show timepicker values in one column with 60 minutes step by default.
     * */
    get singleColumn() {
        return this._singleColumn;
    }
    set singleColumn(value) {
        this._singleColumn = !!value;
    }
    /**
     * Defines minutes offset for options, when timepicker is in single column mode.
     * By default it’s 60 minutes: '12:00, 13:00: 14:00, 15:00...'
     * */
    set step(step) {
        this._step = step;
    }
    get step() {
        return this._step;
    }
    /**
     * Date which will be rendered as selected.
     * */
    set date(date) {
        this._date = date;
        this.isAM = this.dateService.getDayPeriod(this.date) === "AM" /* AM */;
        this.buildColumnOptions();
        this.cd.markForCheck();
    }
    get date() {
        return this._date;
    }
    ngOnInit() {
        this.timeFormat = this.setupTimeFormat();
    }
    ngOnChanges({ step, twelveHoursFormat, withSeconds, singleColumn, }) {
        this.timeFormat = this.setupTimeFormat();
        const isConfigChanged = step || twelveHoursFormat || withSeconds || singleColumn;
        if (isConfigChanged || !this.fullTimeOptions) {
            this.buildColumnOptions();
        }
    }
    setHost(hostRef) {
        this.hostRef = hostRef;
    }
    attach(hostRef) {
        this.hostRef = hostRef;
    }
    setCurrentTime() {
        this.date = this.dateService.today();
        this.onSelectTime.emit({
            time: this.date,
            save: true,
        });
    }
    setHour(value) {
        this.updateValue(this.dateService.setHours(this.date, value));
    }
    setMinute(value) {
        this.updateValue(this.dateService.setMinutes(this.date, value));
    }
    setSecond(value) {
        this.updateValue(this.dateService.setSeconds(this.date, value));
    }
    selectFullTime(value) {
        this.updateValue(value);
    }
    changeDayPeriod(dayPeriodToSet) {
        if (this.dateService.getDayPeriod(this.date) === dayPeriodToSet) {
            return;
        }
        // Subtract hours when switching to AM (before midday, 0-11 in 24-hour) from PM (after midday, 12-24 in 24-hour),
        // otherwise add hours because switching to PM from AM.
        const direction = dayPeriodToSet === "AM" /* AM */ ? -1 : 1;
        const increment = direction * this.dateService.HOURS_IN_DAY_PERIOD;
        this.updateValue(this.dateService.addHours(this.date, increment));
    }
    updateValue(date) {
        this.onSelectTime.emit({ time: date });
    }
    saveValue() {
        this.onSelectTime.emit({
            time: this.date,
            save: true,
        });
    }
    trackByTimeValues(index, item) {
        return item.value;
    }
    trackBySingleColumnValue(index, item) {
        return this.dateService.valueOf(item);
    }
    trackByDayPeriod(index, item) {
        return item;
    }
    showSeconds() {
        return this.withSeconds && !this.singleColumn;
    }
    isSelectedHour(val) {
        if (this.date) {
            return this.dateService.getHours(this.date) === val;
        }
        return false;
    }
    isSelectedMinute(val) {
        if (this.date) {
            return this.dateService.getMinutes(this.date) === val;
        }
        return false;
    }
    isSelectedSecond(val) {
        if (this.date) {
            return this.dateService.getSeconds(this.date) === val;
        }
        return false;
    }
    isSelectedDayPeriod(dayPeriod) {
        if (this.date) {
            return dayPeriod === this.dateService.getDayPeriod(this.date);
        }
        return false;
    }
    getFullTimeString(item) {
        return this.dateService.format(item, this.timeFormat).toUpperCase();
    }
    isSelectedFullTimeValue(value) {
        if (this.date) {
            return this.dateService.isSameHourAndMinute(value, this.date);
        }
        return false;
    }
    buildColumnOptions() {
        this.timeFormat = this.setupTimeFormat();
        this.fullTimeOptions = this.singleColumn
            ? this.calendarTimeModelService.getHoursRange(this.step)
            : [];
        this.hoursColumnOptions = this.generateHours();
        this.minutesColumnOptions = this.generateMinutesOrSeconds();
        this.secondsColumnOptions = this.withSeconds
            ? this.generateMinutesOrSeconds()
            : [];
    }
    /**
     * @docs-private
     */
    isFirefox() {
        return this.platformService.FIREFOX;
    }
    generateHours() {
        if (!this.twelveHoursFormat) {
            return range(24, (v) => {
                return {
                    value: v,
                    text: this.calendarTimeModelService.paddToTwoSymbols(v),
                };
            });
        }
        if (this.isAM) {
            return range(12, (v) => {
                const text = v === 0 ? 12 : v;
                return {
                    value: v,
                    text: this.calendarTimeModelService.paddToTwoSymbols(text),
                };
            });
        }
        return rangeFromTo(12, 24, (v) => {
            const text = v === 12 ? 12 : v - 12;
            return {
                value: v,
                text: this.calendarTimeModelService.paddToTwoSymbols(text),
            };
        });
    }
    generateMinutesOrSeconds() {
        return range(60, (v) => {
            return {
                value: v,
                text: this.calendarTimeModelService.paddToTwoSymbols(v),
            };
        });
    }
    setupTimeFormat() {
        if (!this.timeFormat) {
            return this.config.format || this.buildTimeFormat();
        }
        return this.timeFormat;
    }
    /**
     * @docs-private
     */
    buildTimeFormat() {
        if (this.twelveHoursFormat) {
            return `${this.withSeconds && !this.singleColumn
                ? this.dateService.getTwelveHoursFormatWithSeconds()
                : this.dateService.getTwelveHoursFormat()}`;
        }
        else {
            return `${this.withSeconds && !this.singleColumn
                ? this.dateService.getTwentyFourHoursFormatWithSeconds()
                : this.dateService.getTwentyFourHoursFormat()}`;
        }
    }
}
RTimePickerComponent.decorators = [
    { type: Component, args: [{
                selector: 'r-timepicker',
                template: "<r-card *cdkPortal [class.supports-scrollbar-theming]=\"!isFirefox()\" class=\"r-timepicker-container\">\r\n  <r-card-header class=\"column-header\">\r\n    <ng-container *ngIf=\"singleColumn; else fullTimeHeadersBlock\">\r\n      <div class=\"header-cell\">Time</div>\r\n    </ng-container>\r\n    <ng-template #fullTimeHeadersBlock>\r\n      <div class=\"header-cell\">{{ hoursText }}</div>\r\n      <div class=\"header-cell\">{{ minutesText }}</div>\r\n      <div *ngIf=\"withSeconds\" class=\"header-cell\">{{ secondsText }}</div>\r\n      <div *ngIf=\"twelveHoursFormat\" class=\"header-cell\">{{ ampmText }}</div>\r\n    </ng-template>\r\n  </r-card-header>\r\n\r\n  <div class=\"picker-body\">\r\n    <ng-container *ngIf=\"singleColumn; else fullTimeColumnBlock\">\r\n      <r-list class=\"values-list\">\r\n        <r-list-item class=\"list-item\" [class.selected]=\"isSelectedFullTimeValue(item)\"\r\n          *ngFor=\"let item of fullTimeOptions; trackBy: trackBySingleColumnValue.bind(this)\">\r\n          <r-timepicker-cell [value]=\"getFullTimeString(item)\" [selected]=\"isSelectedFullTimeValue(item)\"\r\n            (select)=\"selectFullTime(item)\">\r\n          </r-timepicker-cell>\r\n        </r-list-item>\r\n      </r-list>\r\n    </ng-container>\r\n\r\n    <ng-template #fullTimeColumnBlock>\r\n      <r-list class=\"values-list\">\r\n        <r-list-item class=\"list-item\" [class.selected]=\"isSelectedHour(item.value)\"\r\n          *ngFor=\"let item of hoursColumnOptions; trackBy: trackByTimeValues\">\r\n          <r-timepicker-cell [value]=\"item.text\" [selected]=\"isSelectedHour(item.value)\" (select)=\"setHour(item.value)\">\r\n          </r-timepicker-cell>\r\n        </r-list-item>\r\n      </r-list>\r\n      <r-list class=\"values-list\">\r\n        <r-list-item class=\"list-item\" [class.selected]=\"isSelectedMinute(item.value)\"\r\n          *ngFor=\"let item of minutesColumnOptions; trackBy: trackByTimeValues\">\r\n          <r-timepicker-cell [value]=\"item.text\" [selected]=\"isSelectedMinute(item.value)\"\r\n            (select)=\"setMinute(item.value)\">\r\n          </r-timepicker-cell>\r\n        </r-list-item>\r\n      </r-list>\r\n      <r-list *ngIf=\"showSeconds()\" class=\"values-list\">\r\n        <r-list-item class=\"list-item\" [class.selected]=\"isSelectedSecond(item.value)\"\r\n          *ngFor=\"let item of secondsColumnOptions; trackBy: trackByTimeValues\">\r\n          <r-timepicker-cell [value]=\"item.text\" [selected]=\"isSelectedSecond(item.value)\"\r\n            (select)=\"setSecond(item.value)\">\r\n          </r-timepicker-cell>\r\n        </r-list-item>\r\n      </r-list>\r\n      <r-list *ngIf=\"twelveHoursFormat\" class=\"values-list\">\r\n        <r-list-item class=\"list-item am-pm-item\" [class.selected]=\"isSelectedDayPeriod(dayPeriod)\"\r\n          *ngFor=\"let dayPeriod of dayPeriodColumnOptions; trackBy: trackByDayPeriod\">\r\n          <r-timepicker-cell [value]=\"dayPeriod\" [selected]=\"isSelectedDayPeriod(dayPeriod)\"\r\n            (select)=\"changeDayPeriod(dayPeriod)\">\r\n          </r-timepicker-cell>\r\n        </r-list-item>\r\n      </r-list>\r\n    </ng-template>\r\n  </div>\r\n\r\n  <r-card-footer *ngIf=\"showFooter\" class=\"actions-footer\">\r\n    <r-calendar-actions [applyButtonText]=\"applyButtonText\" [currentTimeButtonText]=\"currentTimeButtonText\"\r\n      (setCurrentTime)=\"setCurrentTime()\" (saveValue)=\"saveValue()\"></r-calendar-actions>\r\n  </r-card-footer>\r\n</r-card>",
                exportAs: 'rTimepicker',
                changeDetection: ChangeDetectionStrategy.OnPush,
                styles: [".r-timepicker-container{overflow:hidden;margin-bottom:0}.values-list{width:100%;overflow:hidden;-ms-scroll-snap-type:y proximity;scroll-snap-type:y proximity}.values-list:hover{overflow-y:auto}.list-item{border:0;padding:0;cursor:pointer}.picker-body{display:flex;width:100%;flex:1 0 0;overflow:hidden}.column-header{width:100%;display:flex;justify-content:space-between;padding:0}.header-cell{width:100%;display:flex;align-items:center;justify-content:center}.actions-footer{width:100%}r-card-footer,r-card-header{flex:0 0 auto}"]
            },] }
];
RTimePickerComponent.ctorParameters = () => [
    { type: undefined, decorators: [{ type: Inject, args: [R_TIME_PICKER_CONFIG,] }] },
    { type: Platform },
    { type: String, decorators: [{ type: Inject, args: [LOCALE_ID,] }] },
    { type: ChangeDetectorRef },
    { type: RCalendarTimeModelService },
    { type: RDateService }
];
RTimePickerComponent.propDecorators = {
    timeFormat: [{ type: Input }],
    twelveHoursFormat: [{ type: Input }],
    withSeconds: [{ type: Input }],
    singleColumn: [{ type: Input }],
    step: [{ type: Input }],
    date: [{ type: Input }],
    showFooter: [{ type: Input }],
    applyButtonText: [{ type: Input }],
    hoursText: [{ type: Input }],
    minutesText: [{ type: Input }],
    secondsText: [{ type: Input }],
    ampmText: [{ type: Input }],
    currentTimeButtonText: [{ type: Input }],
    onSelectTime: [{ type: Output }],
    portal: [{ type: ViewChild, args: [CdkPortal, { static: true },] }]
};
//# sourceMappingURL=timepicker.component.js.map