import { Attribute, ChangeDetectorRef, Directive, ElementRef, forwardRef, Inject, Input, isDevMode, Renderer2, } from '@angular/core';
import { filter, map, takeUntil } from 'rxjs/operators';
import { fromEvent, merge, Subject } from 'rxjs';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { DOCUMENT } from '@angular/common';
import { Overlay } from '@angular/cdk/overlay';
import { RCalendarTimeModelService, RDateService, } from '../../extra/calendar-kit';
import { RTrigger, RTriggerStrategyBuilderService } from '../../../cdk/overlay/overlay-trigger';
import { RAdjustment, RPosition, RPositionBuilderService } from '../../../cdk/overlay/overlay-position';
import { RTimePickerComponent } from './timepicker.component';
export class RTimePickerDirective {
    constructor(document, positionBuilder, hostRef, triggerStrategyBuilder, overlay, cd, calendarTimeModelService, dateService, renderer, placeholder) {
        this.document = document;
        this.positionBuilder = positionBuilder;
        this.hostRef = hostRef;
        this.triggerStrategyBuilder = triggerStrategyBuilder;
        this.overlay = overlay;
        this.cd = cd;
        this.calendarTimeModelService = calendarTimeModelService;
        this.dateService = dateService;
        this.renderer = renderer;
        this.placeholder = placeholder;
        /**
         * Time picker overlay offset.
         * */
        this.overlayOffset = 8;
        this.destroy$ = new Subject();
        this.onChange = () => { };
        this.onTouched = () => { };
    }
    /**
     * Provides timepicker component.
     * */
    get timepicker() {
        return this._timePickerComponent;
    }
    set timepicker(timePicker) {
        this._timePickerComponent = timePicker;
    }
    /**
     * Returns html input element.
     * @docs-private
     * */
    get input() {
        return this.hostRef.nativeElement;
    }
    /**
     * Determines is timepicker overlay opened.
     * @docs-private
     * */
    get isOpen() {
        return this.overlayRef && this.overlayRef.hasAttached();
    }
    /**
     * Determines is timepicker overlay closed.
     * @docs-private
     * */
    get isClosed() {
        return !this.isOpen;
    }
    /**
     * Returns host input value.
     * @docs-private
     * */
    get inputValue() {
        return this.input.value;
    }
    set inputValue(value) {
        this.input.value = value;
    }
    ngAfterViewInit() {
        this.subscribeOnInputChange();
        if (!this.placeholder) {
            this.renderer.setProperty(this.input, 'placeholder', this.timepicker.timeFormat);
        }
        this.triggerStrategy = this.createTriggerStrategy();
        this.subscribeOnTriggers();
        this.subscribeToBlur();
    }
    show() {
        if (this.isClosed) {
            this.attachToOverlay();
        }
    }
    hide() {
        if (this.isOpen) {
            this.overlayRef.detach();
            this.overlayRef.dispose();
            this.cd.markForCheck();
        }
    }
    /**
     * Attaches picker to the timepicker portal.
     * @docs-private
     * */
    attachToOverlay() {
        if (!this.overlayRef) {
            this.setupTimepicker();
            this.initOverlay();
        }
        console.log(this.timepicker);
        this.overlayRef.attach(this.timepicker.portal);
    }
    setupTimepicker() {
        if (this.dateService.getId() === 'native' && isDevMode()) {
            console.warn('Date.parse noes not support parsing time with custom format.' +
                ' See details here https://akveo.github.io/nebular/docs/components/datepicker/overview#native-parse-issue');
        }
        this.timepicker.setHost(this.hostRef);
        if (this.inputValue) {
            const val = this.dateService.getId() === 'native'
                ? this.parseNativeDateString(this.inputValue)
                : this.inputValue;
            this.timepicker.date = this.dateService.parse(val, this.timepicker.timeFormat);
        }
        else {
            this.timepicker.date = this.calendarTimeModelService.getResetTime();
        }
    }
    initOverlay() {
        this.positionStrategy = this.createPositionStrategy();
        this.subscribeOnApplyClick();
        this.createOverlay();
    }
    subscribeOnApplyClick() {
        this.timepicker.onSelectTime
            .pipe(takeUntil(this.destroy$))
            .subscribe((value) => {
            const time = this.dateService
                .format(value.time, this.timepicker.timeFormat)
                .toUpperCase();
            this.inputValue = time;
            this.timepicker.date = value.time;
            this.onChange(value.time);
            if (value.save) {
                this.lastInputValue = time;
                this.hide();
            }
        });
    }
    createOverlay() {
        const scrollStrategy = this.createScrollStrategy();
        this.overlayRef = this.overlay.create({
            positionStrategy: this.positionStrategy,
            scrollStrategy,
        });
    }
    subscribeOnTriggers() {
        this.triggerStrategy.show$
            .pipe(filter(() => this.isClosed))
            .subscribe(() => this.show());
        this.triggerStrategy.hide$.pipe(filter(() => this.isOpen)).subscribe(() => {
            this.inputValue = this.lastInputValue || '';
            this.hide();
        });
    }
    createTriggerStrategy() {
        return this.triggerStrategyBuilder
            .trigger(RTrigger.FOCUS)
            .host(this.hostRef.nativeElement)
            .container(() => this.getContainer())
            .build();
    }
    createPositionStrategy() {
        return this.positionBuilder
            .connectedTo(this.hostRef)
            .position(RPosition.BOTTOM)
            .offset(this.overlayOffset)
            .adjustment(RAdjustment.VERTICAL);
    }
    getContainer() {
        return (this.overlayRef &&
            this.isOpen &&
            {
                location: {
                    nativeElement: this.overlayRef.overlayElement,
                },
            });
    }
    createScrollStrategy() {
        return this.overlay.scrollStrategies.block();
    }
    subscribeOnInputChange() {
        fromEvent(this.input, 'input')
            .pipe(map(() => this.inputValue), takeUntil(this.destroy$))
            .subscribe((value) => this.handleInputChange(value));
    }
    subscribeToBlur() {
        merge(this.timepicker.blur, fromEvent(this.input, 'blur').pipe(filter(() => !this.isOpen && this.document.activeElement !== this.input)))
            .pipe(takeUntil(this.destroy$))
            .subscribe(() => this.onTouched());
    }
    /**
     * Parses input value and write if it isn't null.
     * @docs-private
     * */
    handleInputChange(value) {
        if (this.dateService.getId() === 'native') {
            /**
             * Native date service dont parse only time string value,
             * and we adding year mouth and day to convert string to valid date format
             **/
            value = this.parseNativeDateString(value);
        }
        const isValidDate = this.dateService.isValidDateString(value, this.timepicker.timeFormat);
        if (isValidDate) {
            this.lastInputValue = value;
            const date = this.dateService.parse(value, this.timepicker.timeFormat);
            this.onChange(date);
            this.timepicker.date = date;
        }
    }
    updateValue(value) {
        if (value) {
            this.timepicker.date = value;
            this.inputValue = this.dateService
                .format(value, this.timepicker.timeFormat)
                .toUpperCase();
        }
    }
    writeValue(value) {
        this.updateValue(value);
    }
    registerOnChange(fn) {
        this.onChange = fn;
    }
    registerOnTouched(fn) {
        this.onTouched = fn;
    }
    parseNativeDateString(value) {
        const date = this.dateService.today();
        const year = this.dateService.getYear(date);
        const month = this.calendarTimeModelService.paddToTwoSymbols(this.dateService.getMonth(date));
        const day = this.calendarTimeModelService.paddToTwoSymbols(this.dateService.getDate(date));
        return `${year}-${month}-${day} ${value}`;
    }
}
RTimePickerDirective.decorators = [
    { type: Directive, args: [{
                selector: 'input[rTimepicker]',
                providers: [
                    {
                        provide: NG_VALUE_ACCESSOR,
                        useExisting: forwardRef(() => RTimePickerDirective),
                        multi: true,
                    },
                ],
            },] }
];
RTimePickerDirective.ctorParameters = () => [
    { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
    { type: RPositionBuilderService },
    { type: ElementRef },
    { type: RTriggerStrategyBuilderService },
    { type: Overlay },
    { type: ChangeDetectorRef },
    { type: RCalendarTimeModelService },
    { type: RDateService },
    { type: Renderer2 },
    { type: String, decorators: [{ type: Attribute, args: ['placeholder',] }] }
];
RTimePickerDirective.propDecorators = {
    timepicker: [{ type: Input, args: ['rTimepicker',] }],
    overlayOffset: [{ type: Input }]
};
//# sourceMappingURL=timepicker.directive.js.map