/*!
 *
 * carbon-angular v0.0.7 | datepicker.component.js
 *
 * Copyright 2014, 2019 IBM
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import { Component, Input, Output, EventEmitter, ViewEncapsulation, ElementRef, HostListener } from "@angular/core";
import rangePlugin from "flatpickr/dist/plugins/rangePlugin";
import flatpickr from "flatpickr";
import { NG_VALUE_ACCESSOR } from "@angular/forms";
import { carbonFlatpickrMonthSelectPlugin } from "./carbon-flatpickr-month-select";
/**
 * [See demo](../../?path=/story/date-picker--single)
 *
 * <example-url>../../iframe.html?id=date-picker--single</example-url>
 */
var DatePicker = /** @class */ (function () {
    function DatePicker(elementRef) {
        var _this = this;
        this.elementRef = elementRef;
        /**
         * Select calendar range mode
         */
        this.range = false;
        /**
         * Format of date
         *
         * For reference: https://flatpickr.js.org/formatting/
         */
        this.dateFormat = "m/d/Y";
        this.placeholder = "mm/dd/yyyy";
        this.pattern = "^\\d{1,2}/\\d{1,2}/\\d{4}$";
        this.id = "datepicker-" + DatePicker.datePickerCount++;
        this.theme = "dark";
        this.disabled = false;
        this.invalid = false;
        this.skeleton = false;
        this.plugins = [];
        this.valueChange = new EventEmitter();
        this._value = [];
        this._flatpickrOptions = {
            allowInput: true
        };
        this.flatpickrBaseOptions = {
            mode: "single",
            dateFormat: "m/d/Y",
            plugins: this.plugins,
            onOpen: function () { _this.updateClassNames(); },
            value: this.value
        };
        this.flatpickrInstance = null;
        this.onTouched = function () { };
        this.propagateChange = function (_) { };
    }
    Object.defineProperty(DatePicker.prototype, "value", {
        get: function () {
            return this._value;
        },
        set: function (v) {
            if (!v) {
                v = [];
            }
            this._value = v;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(DatePicker.prototype, "flatpickrOptions", {
        get: function () {
            var plugins = this.plugins.concat([carbonFlatpickrMonthSelectPlugin]);
            if (this.range) {
                plugins.push(rangePlugin({ input: "#" + this.id + "-rangeInput", position: "left" }));
            }
            return Object.assign({}, this._flatpickrOptions, this.flatpickrBaseOptions, {
                mode: this.range ? "range" : "single",
                plugins: plugins,
                dateFormat: this.dateFormat
            });
        },
        set: function (options) {
            this._flatpickrOptions = Object.assign({}, this._flatpickrOptions, options);
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(DatePicker.prototype, "flatpickrOptionsRange", {
        get: function () {
            console.warn("flatpickrOptionsRange is deprecated, use flatpickrOptions and set the range to true instead");
            return this.flatpickrOptions;
        },
        set: function (options) {
            console.warn("flatpickrOptionsRange is deprecated, use flatpickrOptions and set the range to true instead");
            this.range = true;
            this.flatpickrOptions = options;
        },
        enumerable: true,
        configurable: true
    });
    DatePicker.prototype.ngOnChanges = function (changes) {
        if (this.isFlatpickrLoaded()) {
            var dates = this.flatpickrInstance.selectedDates;
            if (changes.value && this.didDateValueChange(changes.value.currentValue, changes.value.previousValue)) {
                dates = changes.value.currentValue;
            }
            // only reset the flatpickr instance on Input changes
            this.flatpickrInstance = flatpickr("#" + this.id, this.flatpickrOptions);
            this.setDateValues(dates);
        }
    };
    // because the actual view may be delayed in loading (think projection into a tab pane)
    // and because we rely on a library that operates outside the Angular view of the world
    // we need to keep trying to load the library, until the relevant DOM is actually live
    DatePicker.prototype.ngAfterViewChecked = function () {
        if (!this.isFlatpickrLoaded()) {
            this.flatpickrInstance = flatpickr("#" + this.id, this.flatpickrOptions);
            // if (and only if) the initialization succeeded, we can set the date values
            if (this.isFlatpickrLoaded()) {
                if (this.value.length > 0) {
                    this.setDateValues(this.value);
                }
            }
        }
    };
    DatePicker.prototype.onFocus = function () {
        this.onTouched();
    };
    /**
     * Writes a value from the model to the component. Expects the value to be `null` or `(Date | string)[]`
     * @param value value received from the model
     */
    DatePicker.prototype.writeValue = function (value) {
        this.value = value;
        this.setDateValues(this.value);
    };
    DatePicker.prototype.registerOnChange = function (fn) {
        this.propagateChange = fn;
    };
    DatePicker.prototype.registerOnTouched = function (fn) {
        this.onTouched = fn;
    };
    /**
     * Cleans up our flatpickr instance
     */
    DatePicker.prototype.ngOnDestroy = function () {
        if (!this.isFlatpickrLoaded()) {
            return;
        }
        this.flatpickrInstance.destroy();
    };
    /**
     * Handles the `valueChange` event from the primary/single input
     */
    DatePicker.prototype.onValueChange = function (event) {
        if (this.isFlatpickrLoaded()) {
            var date = this.flatpickrInstance.parseDate(event, this.dateFormat);
            if (this.range) {
                this.setDateValues([date, this.flatpickrInstance.selectedDates[1]]);
            }
            else {
                this.setDateValues([date]);
            }
            this.doSelect(this.flatpickrInstance.selectedDates);
        }
    };
    /**
     * Handles the `valueChange` event from the range input
     */
    DatePicker.prototype.onRangeValueChange = function (event) {
        if (this.isFlatpickrLoaded()) {
            var date = this.flatpickrInstance.parseDate(event, this.dateFormat);
            this.setDateValues([this.flatpickrInstance.selectedDates[0], date]);
            this.doSelect(this.flatpickrInstance.selectedDates);
        }
    };
    /**
     * Carbon uses a number of specific classnames for parts of the flatpickr - this idempotent method applies them if needed.
     */
    DatePicker.prototype.updateClassNames = function () {
        var _this = this;
        if (!this.elementRef) {
            return;
        }
        // get all the possible flatpickrs in the document - we need to add classes to (potentially) all of them
        var calendarContainer = document.querySelectorAll(".flatpickr-calendar");
        var monthContainer = document.querySelectorAll(".flatpickr-month");
        var weekdaysContainer = document.querySelectorAll(".flatpickr-weekdays");
        var weekdayContainer = document.querySelectorAll(".flatpickr-weekday");
        var daysContainer = document.querySelectorAll(".flatpickr-days");
        var dayContainer = document.querySelectorAll(".flatpickr-day");
        // add classes to lists of elements
        var addClassIfNotExists = function (classname, elementList) {
            Array.from(elementList).forEach(function (element) {
                if (!element.classList.contains(classname)) {
                    element.classList.add(classname);
                }
            });
        };
        // add classes (but only if they don't exist, small perf win)
        addClassIfNotExists("bx--date-picker__calendar", calendarContainer);
        addClassIfNotExists("bx--date-picker__month", monthContainer);
        addClassIfNotExists("bx--date-picker__weekdays", weekdaysContainer);
        addClassIfNotExists("bx--date-picker__days", daysContainer);
        // add weekday classes and format the text
        Array.from(weekdayContainer).forEach(function (element) {
            element.innerHTML = element.innerHTML.replace(/\s+/g, "");
            element.classList.add("bx--date-picker__weekday");
        });
        // add day classes and special case the "today" element based on `this.value`
        Array.from(dayContainer).forEach(function (element) {
            element.classList.add("bx--date-picker__day");
            if (!_this.value) {
                return;
            }
            if (element.classList.contains("today") && _this.value.length > 0) {
                element.classList.add("no-border");
            }
            else if (element.classList.contains("today") && _this.value.length === 0) {
                element.classList.remove("no-border");
            }
        });
    };
    /**
     * Applies the given date value array to both the flatpickr instance and the `input`(s)
     * @param dates the date values to apply
     */
    DatePicker.prototype.setDateValues = function (dates) {
        if (this.isFlatpickrLoaded()) {
            var singleInput = this.elementRef.nativeElement.querySelector("#" + this.id);
            var rangeInput = this.elementRef.nativeElement.querySelector("#" + this.id + "-rangeInput");
            // set the date on the instance
            this.flatpickrInstance.setDate(dates);
            // we can either set a date value or an empty string, so we start with an empty string
            var singleDate = "";
            // if date is a string, parse and format
            if (typeof dates[0] === "string") {
                singleDate = this.flatpickrInstance.parseDate(dates[0], this.dateFormat);
                singleDate = this.flatpickrInstance.formatDate(singleDate, this.dateFormat);
                // if date is not a string we can assume it's a Date and we should format
            }
            else if (!!dates[0]) {
                singleDate = this.flatpickrInstance.formatDate(dates[0], this.dateFormat);
            }
            // apply the value
            singleInput.value = singleDate;
            if (rangeInput) {
                // we can either set a date value or an empty string, so we start with an empty string
                var rangeDate = "";
                // if date is a string, parse and format
                if (typeof dates[1] === "string") {
                    rangeDate = this.flatpickrInstance.parseDate(dates[1].toString(), this.dateFormat);
                    rangeDate = this.flatpickrInstance.formatDate(rangeDate, this.dateFormat);
                    // if date is not a string we can assume it's a Date and we should format
                }
                else if (!!dates[1]) {
                    rangeDate = this.flatpickrInstance.formatDate(dates[1], this.dateFormat);
                }
                // apply the value
                rangeInput.value = rangeDate;
            }
        }
    };
    DatePicker.prototype.doSelect = function (selectedValue) {
        this.valueChange.emit(selectedValue);
        this.propagateChange(selectedValue);
    };
    DatePicker.prototype.didDateValueChange = function (currentValue, previousValue) {
        return currentValue[0] !== previousValue[0] || currentValue[1] !== previousValue[1];
    };
    /**
     * More advanced checking of the loaded state of flatpickr
     */
    DatePicker.prototype.isFlatpickrLoaded = function () {
        // cast the instance to a boolean, and some method that has to exist for the library to be loaded in this case `setDate`
        return !!this.flatpickrInstance && !!this.flatpickrInstance.setDate;
    };
    DatePicker.datePickerCount = 0;
    DatePicker.decorators = [
        { type: Component, args: [{
                    selector: "ibm-date-picker",
                    template: "\n\t<div class=\"bx--form-item\">\n\t\t<div class=\"bx--form-item\">\n\t\t\t<div\n\t\t\t\tclass=\"bx--date-picker\"\n\t\t\t\t[ngClass]=\"{\n\t\t\t\t\t'bx--date-picker--range' : range,\n\t\t\t\t\t'bx--date-picker--single' : !range,\n\t\t\t\t\t'bx--date-picker--light' : theme === 'light',\n\t\t\t\t\t'bx--skeleton' : skeleton\n\t\t\t\t}\">\n\t\t\t\t<div class=\"bx--date-picker-container\">\n\t\t\t\t\t<ibm-date-picker-input\n\t\t\t\t\t\t[label]=\"label\"\n\t\t\t\t\t\t[placeholder]=\"placeholder\"\n\t\t\t\t\t\t[pattern]=\"pattern\"\n\t\t\t\t\t\t[id]=\"id\"\n\t\t\t\t\t\t[type]=\"(range ? 'range' : 'single')\"\n\t\t\t\t\t\t[hasIcon]=\"(range ? false : true)\"\n\t\t\t\t\t\t[disabled]=\"disabled\"\n\t\t\t\t\t\t[invalid]=\"invalid\"\n\t\t\t\t\t\t[invalidText]=\"invalidText\"\n\t\t\t\t\t\t[skeleton]=\"skeleton\"\n\t\t\t\t\t\t(valueChange)=\"onValueChange($event)\">\n\t\t\t\t\t</ibm-date-picker-input>\n\t\t\t\t</div>\n\n\t\t\t\t<div *ngIf=\"range\" class=\"bx--date-picker-container\">\n\t\t\t\t\t<ibm-date-picker-input\n\t\t\t\t\t\t[label]=\"rangeLabel\"\n\t\t\t\t\t\t[placeholder]=\"placeholder\"\n\t\t\t\t\t\t[pattern]=\"pattern\"\n\t\t\t\t\t\t[id]=\"id + '-rangeInput'\"\n\t\t\t\t\t\t[type]=\"(range ? 'range' : 'single')\"\n\t\t\t\t\t\t[hasIcon]=\"(range ? true : null)\"\n\t\t\t\t\t\t[disabled]=\"disabled\"\n\t\t\t\t\t\t[invalid]=\"invalid\"\n\t\t\t\t\t\t[invalidText]=\"invalidText\"\n\t\t\t\t\t\t[skeleton]=\"skeleton\"\n\t\t\t\t\t\t(valueChange)=\"onRangeValueChange($event)\">\n\t\t\t\t\t</ibm-date-picker-input>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t",
                    styles: [
                        ".dayContainer {\n\t\t\tjustify-content: initial;\n\t\t}"
                    ],
                    providers: [
                        {
                            provide: NG_VALUE_ACCESSOR,
                            useExisting: DatePicker,
                            multi: true
                        }
                    ],
                    encapsulation: ViewEncapsulation.None
                },] },
    ];
    /** @nocollapse */
    DatePicker.ctorParameters = function () { return [
        { type: ElementRef }
    ]; };
    DatePicker.propDecorators = {
        range: [{ type: Input }],
        dateFormat: [{ type: Input }],
        label: [{ type: Input }],
        rangeLabel: [{ type: Input }],
        placeholder: [{ type: Input }],
        pattern: [{ type: Input }],
        id: [{ type: Input }],
        value: [{ type: Input }],
        theme: [{ type: Input }],
        disabled: [{ type: Input }],
        invalid: [{ type: Input }],
        invalidText: [{ type: Input }],
        skeleton: [{ type: Input }],
        plugins: [{ type: Input }],
        flatpickrOptions: [{ type: Input }],
        valueChange: [{ type: Output }],
        onFocus: [{ type: HostListener, args: ["focusin",] }]
    };
    return DatePicker;
}());
export { DatePicker };
//# sourceMappingURL=datepicker.component.js.map