/*
 * @license
 * Copyright Endlessjs. All Rights Reserved.
 * Licensed under the MIT License. See License.txt in the project root for license information.
 */
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
import { Component, ComponentFactoryResolver, EventEmitter, Inject, Input, Output, Type, Optional, } from '@angular/core';
import { takeWhile } from 'rxjs/operators';
import { ReplaySubject, Subject } from 'rxjs';
import { ElComponentPortal } from '../cdk/overlay/mapping';
import { ElAdjustment, ElPosition, ElPositionBuilderService, } from '../cdk/overlay/overlay-position';
import { ElOverlayService, patch } from '../cdk/overlay/overlay-service';
import { ElTrigger, ElTriggerStrategyBuilderService } from '../cdk/overlay/overlay-trigger';
import { ElDatepickerContainerComponent } from './datepicker-container.component';
import { EL_DOCUMENT } from '../../theme.options';
import { ElCalendarRangeComponent } from '../calendar/calendar-range.component';
import { ElCalendarComponent } from '../calendar/calendar.component';
import { ElCalendarSize, ElCalendarViewMode, } from '../calendar-kit/model';
import { ElDateService } from '../calendar-kit/services/date.service';
import { EL_DATE_SERVICE_OPTIONS, ElDatepicker } from './datepicker.directive';
import { convertToBoolProperty } from '../helpers';
/**
 * The `ElBasePicker` component concentrates overlay manipulation logic.
 * */
var ElBasePicker = /** @class */ (function (_super) {
    __extends(ElBasePicker, _super);
    function ElBasePicker(document, positionBuilder, triggerStrategyBuilder, overlay, cfr, dateService, dateServiceOptions) {
        var _this = _super.call(this) || this;
        _this.document = document;
        _this.positionBuilder = positionBuilder;
        _this.triggerStrategyBuilder = triggerStrategyBuilder;
        _this.overlay = overlay;
        _this.cfr = cfr;
        _this.dateService = dateService;
        _this.dateServiceOptions = dateServiceOptions;
        /**
         * Defines if we should render previous and next months
         * in the current month view.
         * */
        _this.boundingMonth = true;
        /**
         * Defines starting view for calendar.
         * */
        _this.startView = ElCalendarViewMode.DATE;
        /**
         * Size of the calendar and entire components.
         * Can be 'medium' which is default or 'large'.
         * */
        _this.size = ElCalendarSize.MEDIUM;
        /**
         * Hide picker when a date or a range is selected, `true` by default
         * @type {boolean}
         */
        _this.hideOnSelect = true;
        /**
         * Determines should we show calendars header or not.
         * @type {boolean}
         */
        _this.showHeader = true;
        /**
         * Sets symbol used as a header for week numbers column
         * */
        _this.weekNumberSymbol = '#';
        _this._showWeekNumber = false;
        _this.init$ = new ReplaySubject();
        /**
         * Stream of picker changes. Required to be the subject because picker hides and shows and picker
         * change stream becomes recreated.
         * */
        _this.onChange$ = new Subject();
        _this.alive = true;
        _this.blur$ = new Subject();
        return _this;
    }
    Object.defineProperty(ElBasePicker.prototype, "showWeekNumber", {
        /**
         * Determines should we show week numbers column.
         * False by default.
         * */
        get: function () {
            return this._showWeekNumber;
        },
        set: function (value) {
            this._showWeekNumber = convertToBoolProperty(value);
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(ElBasePicker.prototype, "picker", {
        /**
         * Returns picker instance.
         * */
        get: function () {
            return this.pickerRef && this.pickerRef.instance;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(ElBasePicker.prototype, "valueChange", {
        /**
         * Stream of picker value changes.
         * */
        get: function () {
            return this.onChange$.asObservable();
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(ElBasePicker.prototype, "isShown", {
        get: function () {
            return this.ref && this.ref.hasAttached();
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(ElBasePicker.prototype, "init", {
        get: function () {
            return this.init$.asObservable();
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(ElBasePicker.prototype, "blur", {
        /**
         * Emits when datepicker looses focus.
         */
        get: function () {
            return this.blur$.asObservable();
        },
        enumerable: true,
        configurable: true
    });
    ElBasePicker.prototype.ngOnInit = function () {
        this.checkFormat();
    };
    ElBasePicker.prototype.ngOnChanges = function (changes) {
        if (changes.format && !changes.format.isFirstChange()) {
            this.checkFormat();
        }
    };
    ElBasePicker.prototype.ngAfterViewInit = function () {
        this.init$.next();
    };
    ElBasePicker.prototype.ngOnDestroy = function () {
        this.alive = false;
        this.hide();
        this.init$.complete();
        if (this.ref) {
            this.ref.dispose();
        }
        if (this.triggerStrategy) {
            this.triggerStrategy.destroy();
        }
    };
    /**
     * Datepicker knows nothing about host html input element.
     * So, attach method attaches datepicker to the host input element.
     * */
    ElBasePicker.prototype.attach = function (hostRef) {
        this.hostRef = hostRef;
        this.subscribeOnTriggers();
    };
    ElBasePicker.prototype.getValidatorConfig = function () {
        return { min: this.min, max: this.max, filter: this.filter };
    };
    ElBasePicker.prototype.show = function () {
        if (!this.ref) {
            this.createOverlay();
        }
        this.openDatepicker();
    };
    ElBasePicker.prototype.shouldHide = function () {
        return this.hideOnSelect && !!this.value;
    };
    ElBasePicker.prototype.hide = function () {
        if (this.ref) {
            this.ref.detach();
        }
        // save current value if picker was rendered
        if (this.picker) {
            this.queue = this.value;
            this.pickerRef.destroy();
            this.pickerRef = null;
            this.container = null;
        }
    };
    ElBasePicker.prototype.createOverlay = function () {
        this.positionStrategy = this.createPositionStrategy();
        this.ref = this.overlay.create({
            positionStrategy: this.positionStrategy,
            scrollStrategy: this.overlay.scrollStrategies.reposition(),
        });
        this.subscribeOnPositionChange();
    };
    ElBasePicker.prototype.openDatepicker = function () {
        this.container = this.ref.attach(new ElComponentPortal(ElDatepickerContainerComponent, null, null, this.cfr));
        this.instantiatePicker();
        this.subscribeOnValueChange();
        this.writeQueue();
        this.patchWithInputs();
    };
    ElBasePicker.prototype.createPositionStrategy = function () {
        return this.positionBuilder
            .connectedTo(this.hostRef)
            .position(ElPosition.BOTTOM)
            .adjustment(ElAdjustment.COUNTERCLOCKWISE);
    };
    ElBasePicker.prototype.subscribeOnPositionChange = function () {
        var _this = this;
        this.positionStrategy.positionChange
            .pipe(takeWhile(function () { return _this.alive; }))
            .subscribe(function (position) { return patch(_this.container, { position: position }); });
    };
    ElBasePicker.prototype.createTriggerStrategy = function () {
        var _this = this;
        return this.triggerStrategyBuilder
            .trigger(ElTrigger.FOCUS)
            .host(this.hostRef.nativeElement)
            .container(function () { return _this.container; })
            .build();
    };
    ElBasePicker.prototype.subscribeOnTriggers = function () {
        var _this = this;
        this.triggerStrategy = this.createTriggerStrategy();
        this.triggerStrategy.show$.subscribe(function () { return _this.show(); });
        this.triggerStrategy.hide$.subscribe(function () {
            _this.blur$.next();
            _this.hide();
        });
    };
    ElBasePicker.prototype.instantiatePicker = function () {
        this.pickerRef = this.container.instance.attach(new ElComponentPortal(this.pickerClass, null, null, this.cfr));
    };
    /**
     * Subscribes on picker value changes and emit data through this.onChange$ subject.
     * */
    ElBasePicker.prototype.subscribeOnValueChange = function () {
        var _this = this;
        this.pickerValueChange.subscribe(function (date) {
            _this.onChange$.next(date);
        });
    };
    ElBasePicker.prototype.patchWithInputs = function () {
        this.picker.boundingMonth = this.boundingMonth;
        this.picker.startView = this.startView;
        this.picker.min = this.min;
        this.picker.max = this.max;
        this.picker.filter = this.filter;
        this.picker._cellComponent = this.dayCellComponent;
        this.picker.monthCellComponent = this.monthCellComponent;
        this.picker._yearCellComponent = this.yearCellComponent;
        this.picker.size = this.size;
        this.picker.showHeader = this.showHeader;
        this.picker.visibleDate = this.visibleDate;
        this.picker.showWeekNumber = this.showWeekNumber;
        this.picker.weekNumberSymbol = this.weekNumberSymbol;
    };
    ElBasePicker.prototype.checkFormat = function () {
        if (this.dateService.getId() === 'native' && this.format) {
            throw new Error('Can\'t format native date. To use custom formatting you have to install @endlessjs/moment or ' +
                '@endlessjs/date-fns package and import ElMomentDateModule or ElDateFnsDateModule accordingly.' +
                'More information at "Formatting issue" ' +
                'https://endlessjs.github.io/endlessjs/docs/components/datepicker/overview#eldatepickercomponent');
        }
        var isFormatSet = this.format || (this.dateServiceOptions && this.dateServiceOptions.format);
        if (this.dateService.getId() === 'date-fns' && !isFormatSet) {
            throw new Error('format is required when using ElDateFnsDateModule');
        }
    };
    __decorate([
        Input(),
        __metadata("design:type", String)
    ], ElBasePicker.prototype, "format", void 0);
    __decorate([
        Input(),
        __metadata("design:type", Boolean)
    ], ElBasePicker.prototype, "boundingMonth", void 0);
    __decorate([
        Input(),
        __metadata("design:type", String)
    ], ElBasePicker.prototype, "startView", void 0);
    __decorate([
        Input(),
        __metadata("design:type", Object)
    ], ElBasePicker.prototype, "min", void 0);
    __decorate([
        Input(),
        __metadata("design:type", Object)
    ], ElBasePicker.prototype, "max", void 0);
    __decorate([
        Input(),
        __metadata("design:type", Function)
    ], ElBasePicker.prototype, "filter", void 0);
    __decorate([
        Input(),
        __metadata("design:type", Type)
    ], ElBasePicker.prototype, "dayCellComponent", void 0);
    __decorate([
        Input(),
        __metadata("design:type", Type)
    ], ElBasePicker.prototype, "monthCellComponent", void 0);
    __decorate([
        Input(),
        __metadata("design:type", Type)
    ], ElBasePicker.prototype, "yearCellComponent", void 0);
    __decorate([
        Input(),
        __metadata("design:type", String)
    ], ElBasePicker.prototype, "size", void 0);
    __decorate([
        Input(),
        __metadata("design:type", Object)
    ], ElBasePicker.prototype, "visibleDate", void 0);
    __decorate([
        Input(),
        __metadata("design:type", Boolean)
    ], ElBasePicker.prototype, "hideOnSelect", void 0);
    __decorate([
        Input(),
        __metadata("design:type", Boolean)
    ], ElBasePicker.prototype, "showHeader", void 0);
    __decorate([
        Input(),
        __metadata("design:type", String)
    ], ElBasePicker.prototype, "weekNumberSymbol", void 0);
    __decorate([
        Input(),
        __metadata("design:type", Boolean),
        __metadata("design:paramtypes", [Boolean])
    ], ElBasePicker.prototype, "showWeekNumber", null);
    ElBasePicker = __decorate([
        __param(0, Inject(EL_DOCUMENT)),
        __param(6, Optional()), __param(6, Inject(EL_DATE_SERVICE_OPTIONS)),
        __metadata("design:paramtypes", [Object, ElPositionBuilderService,
            ElTriggerStrategyBuilderService,
            ElOverlayService,
            ComponentFactoryResolver,
            ElDateService, Object])
    ], ElBasePicker);
    return ElBasePicker;
}(ElDatepicker));
export { ElBasePicker };
/**
 * The DatePicker components itself.
 * Provides a proxy to `ElCalendar` options as well as custom picker options.
 */
var ElDatepickerComponent = /** @class */ (function (_super) {
    __extends(ElDatepickerComponent, _super);
    function ElDatepickerComponent() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.pickerClass = ElCalendarComponent;
        return _this;
    }
    Object.defineProperty(ElDatepickerComponent.prototype, "date", {
        /**
         * Date which will be rendered as selected.
         * */
        set: function (date) {
            this.value = date;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(ElDatepickerComponent.prototype, "dateChange", {
        /**
         * Emits date when selected.
         * */
        get: function () {
            return this.valueChange;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(ElDatepickerComponent.prototype, "value", {
        get: function () {
            return this.picker ? this.picker.date : undefined;
        },
        set: function (date) {
            if (!this.picker) {
                this.queue = date;
                return;
            }
            if (date) {
                this.visibleDate = date;
                this.picker.visibleDate = date;
                this.picker.date = date;
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(ElDatepickerComponent.prototype, "pickerValueChange", {
        get: function () {
            return this.picker.dateChange;
        },
        enumerable: true,
        configurable: true
    });
    ElDatepickerComponent.prototype.writeQueue = function () {
        if (this.queue) {
            var date = this.queue;
            this.queue = null;
            this.value = date;
        }
    };
    __decorate([
        Input(),
        __metadata("design:type", Object),
        __metadata("design:paramtypes", [Object])
    ], ElDatepickerComponent.prototype, "date", null);
    __decorate([
        Output(),
        __metadata("design:type", EventEmitter),
        __metadata("design:paramtypes", [])
    ], ElDatepickerComponent.prototype, "dateChange", null);
    ElDatepickerComponent = __decorate([
        Component({
            selector: 'el-datepicker',
            template: ''
        })
    ], ElDatepickerComponent);
    return ElDatepickerComponent;
}(ElBasePicker));
export { ElDatepickerComponent };
/**
 * The RangeDatePicker components itself.
 * Provides a proxy to `ElCalendarRange` options as well as custom picker options.
 */
var ElRangepickerComponent = /** @class */ (function (_super) {
    __extends(ElRangepickerComponent, _super);
    function ElRangepickerComponent() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.pickerClass = ElCalendarRangeComponent;
        return _this;
    }
    Object.defineProperty(ElRangepickerComponent.prototype, "range", {
        /**
         * Range which will be rendered as selected.
         * */
        set: function (range) {
            this.value = range;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(ElRangepickerComponent.prototype, "rangeChange", {
        /**
         * Emits range when start selected and emits again when end selected.
         * */
        get: function () {
            return this.valueChange;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(ElRangepickerComponent.prototype, "value", {
        get: function () {
            return this.picker ? this.picker.range : undefined;
        },
        set: function (range) {
            if (!this.picker) {
                this.queue = range;
                return;
            }
            if (range) {
                var visibleDate = range && range.start;
                this.visibleDate = visibleDate;
                this.picker.visibleDate = visibleDate;
                this.picker.range = range;
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(ElRangepickerComponent.prototype, "pickerValueChange", {
        get: function () {
            return this.picker.rangeChange;
        },
        enumerable: true,
        configurable: true
    });
    ElRangepickerComponent.prototype.shouldHide = function () {
        return _super.prototype.shouldHide.call(this) && !!(this.value && this.value.start && this.value.end);
    };
    ElRangepickerComponent.prototype.writeQueue = function () {
        if (this.queue) {
            var range = this.queue;
            this.queue = null;
            this.value = range;
        }
    };
    __decorate([
        Input(),
        __metadata("design:type", Object),
        __metadata("design:paramtypes", [Object])
    ], ElRangepickerComponent.prototype, "range", null);
    __decorate([
        Output(),
        __metadata("design:type", EventEmitter),
        __metadata("design:paramtypes", [])
    ], ElRangepickerComponent.prototype, "rangeChange", null);
    ElRangepickerComponent = __decorate([
        Component({
            selector: 'el-rangepicker',
            template: ''
        })
    ], ElRangepickerComponent);
    return ElRangepickerComponent;
}(ElBasePicker));
export { ElRangepickerComponent };
//# sourceMappingURL=datepicker.component.js.map