(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('@angular/common'), require('@angular/forms'), require('@wm/components/base'), require('@wm/core'), require('@wm/components/input'), require('lodash-es')) :
    typeof define === 'function' && define.amd ? define(['exports', '@angular/core', '@angular/common', '@angular/forms', '@wm/components/base', '@wm/core', '@wm/components/input', 'lodash-es'], factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.wm = global.wm || {}, global.wm.components = global.wm.components || {}, global.wm.components.input = global.wm.components.input || {}, global.wm.components.input.rating = {}), global.ng.core, global.ng.common, global.ng.forms, global.wm.components.base, global.wm.core, global.wm.components.input, global._));
})(this, (function (exports, i0, i1, i2, i3, core, input, lodashEs) { 'use strict';

    function _interopNamespaceDefault(e) {
        var n = Object.create(null);
        if (e) {
            Object.keys(e).forEach(function (k) {
                if (k !== 'default') {
                    var d = Object.getOwnPropertyDescriptor(e, k);
                    Object.defineProperty(n, k, d.get ? d : {
                        enumerable: true,
                        get: function () { return e[k]; }
                    });
                }
            });
        }
        n.default = e;
        return Object.freeze(n);
    }

    var i0__namespace = /*#__PURE__*/_interopNamespaceDefault(i0);
    var i1__namespace = /*#__PURE__*/_interopNamespaceDefault(i1);
    var i2__namespace = /*#__PURE__*/_interopNamespaceDefault(i2);
    var i3__namespace = /*#__PURE__*/_interopNamespaceDefault(i3);

    const ratingProps = new Map([
        ['caption', i3.PROP_STRING],
        ['class', i3.PROP_STRING],
        ['datafield', i3.PROP_STRING],
        ['dataset', i3.PROP_ANY],
        ['datavaluesource', i3.PROP_ANY],
        ['datavalue', i3.PROP_STRING],
        ['displayexpression', i3.PROP_STRING],
        ['displayfield', i3.PROP_STRING],
        ['iconcolor', i3.PROP_STRING],
        ['iconsize', i3.PROP_STRING],
        ['maxvalue', { value: 5, ...i3.PROP_NUMBER }],
        ['name', i3.PROP_STRING],
        ['orderby', i3.PROP_STRING],
        ['readonly', i3.PROP_BOOLEAN],
        ['show', { value: true, ...i3.PROP_BOOLEAN }],
        ['showcaptions', { value: true, ...i3.PROP_BOOLEAN }],
        ['tabindex', { value: 0, ...i3.PROP_NUMBER }],
        ['usekeys', i3.PROP_BOOLEAN]
    ]);
    const registerProps = () => {
        i3.register('wm-rating', ratingProps);
        i3.registerFormWidget(core.FormWidgetType.RATING, new Map(ratingProps));
    };

    const _c0 = ["ratingInput"];
    const _c1 = ["wmRating", ""];
    const _c2 = () => ({ standalone: true });
    const _c3 = a0 => ({ "font-size": a0 });
    const _c4 = (a0, a1) => ({ width: a0, color: a1 });
    const _c5 = a0 => ({ active: a0 });
    const _c6 = (a0, a1) => ({ "font-size": a0, color: a1 });
    function RatingComponent_div_1_label_1_Template(rf, ctx) { if (rf & 1) {
        const _r1 = i0__namespace.ɵɵgetCurrentView();
        i0__namespace.ɵɵelementStart(0, "label", 8);
        i0__namespace.ɵɵlistener("touchstart", function RatingComponent_div_1_label_1_Template_label_touchstart_0_listener($event) { i0__namespace.ɵɵrestoreView(_r1); const ctx_r1 = i0__namespace.ɵɵnextContext(2); return i0__namespace.ɵɵresetView(ctx_r1.onTouchStart($event)); })("mouseleave", function RatingComponent_div_1_label_1_Template_label_mouseleave_0_listener($event) { const rate_r3 = i0__namespace.ɵɵrestoreView(_r1).$implicit; const ctx_r1 = i0__namespace.ɵɵnextContext(2); return i0__namespace.ɵɵresetView(ctx_r1.onMouseleave($event, rate_r3)); })("mouseover", function RatingComponent_div_1_label_1_Template_label_mouseover_0_listener($event) { const rate_r3 = i0__namespace.ɵɵrestoreView(_r1).$implicit; const ctx_r1 = i0__namespace.ɵɵnextContext(2); return i0__namespace.ɵɵresetView(ctx_r1.onMouseOver($event, rate_r3)); });
        i0__namespace.ɵɵelementStart(1, "input", 9, 0);
        i0__namespace.ɵɵlistener("click", function RatingComponent_div_1_label_1_Template_input_click_1_listener($event) { const rate_r3 = i0__namespace.ɵɵrestoreView(_r1).$implicit; const ctx_r1 = i0__namespace.ɵɵnextContext(2); return i0__namespace.ɵɵresetView(ctx_r1.onRatingClick($event, rate_r3)); });
        i0__namespace.ɵɵelementEnd()();
    } if (rf & 2) {
        const rate_r3 = ctx.$implicit;
        const ctx_r1 = i0__namespace.ɵɵnextContext(2);
        i0__namespace.ɵɵproperty("ngClass", i0__namespace.ɵɵpureFunction1(8, _c5, rate_r3.index <= ctx_r1.selectedRatingValue))("ngStyle", i0__namespace.ɵɵpureFunction2(10, _c6, ctx_r1.iconsize, rate_r3.index <= ctx_r1.selectedRatingValue && ctx_r1.iconcolor))("title", rate_r3.label || rate_r3.index)("for", ctx_r1._id + "-" + rate_r3.index);
        i0__namespace.ɵɵadvance();
        i0__namespace.ɵɵproperty("id", ctx_r1._id + "-" + rate_r3.index)("value", rate_r3.key || rate_r3.index);
        i0__namespace.ɵɵattribute("aria-label", (rate_r3.label || rate_r3.index) + " out of " + ctx_r1.ratingItems.length + " ratings")("aria-checked", rate_r3.label === ctx_r1.datavalue ? "true" : "false");
    } }
    function RatingComponent_div_1_Template(rf, ctx) { if (rf & 1) {
        i0__namespace.ɵɵelementStart(0, "div", 6);
        i0__namespace.ɵɵtemplate(1, RatingComponent_div_1_label_1_Template, 3, 13, "label", 7);
        i0__namespace.ɵɵelementEnd();
    } if (rf & 2) {
        const ctx_r1 = i0__namespace.ɵɵnextContext();
        i0__namespace.ɵɵadvance();
        i0__namespace.ɵɵproperty("ngForOf", ctx_r1.ratingItems);
    } }
    function RatingComponent_label_4_Template(rf, ctx) { if (rf & 1) {
        i0__namespace.ɵɵelement(0, "label", 10);
    } if (rf & 2) {
        const ctx_r1 = i0__namespace.ɵɵnextContext();
        i0__namespace.ɵɵproperty("textContent", ctx_r1.caption);
    } }
    const DEFAULT_CLS = 'app-ratings';
    const WIDGET_CONFIG = { widgetType: 'wm-rating', hostClass: DEFAULT_CLS };
    const MAX_RATING = 10;
    const DEFAULT_RATING = 5;
    class RatingComponent extends input.DatasetAwareFormComponent {
        static { this.initializeProps = registerProps(); }
        get selectedRatingValue() {
            return this._selectedRatingValue;
        }
        set selectedRatingValue(val) {
            this._selectedRatingValue = val;
            this.calculateRatingsWidth();
        }
        constructor(inj, explicitContext) {
            super(inj, WIDGET_CONFIG, explicitContext);
            this._id = core.generateGUId();
            i3.styler(this.nativeElement, this);
            // prepare the rating options on dataset ready.
            const datasetSubscription = this.dataset$.subscribe(() => {
                this.prepareRatingDataset();
            });
            this.registerDestroyListener(() => datasetSubscription.unsubscribe());
            // listen to changes in datavalue.
            const datavalueSubscription = this.datavalue$.subscribe(() => this.onDatavalueChange(this.datavalue));
            this.registerDestroyListener(() => datavalueSubscription.unsubscribe());
        }
        // Change event is registered from the template, Prevent the framework from registering one more event
        handleEvent(node, eventName, eventCallback, locals) {
            if (eventName !== 'change' && eventName !== 'blur') {
                super.handleEvent(this.ratingEl.nativeElement, eventName, eventCallback, locals);
            }
        }
        // This function returns the rating widget dataset containing the index, value and label
        prepareRatingDataset() {
            if (!this.datasetItems.length) {
                this.ratingItems = [];
                this.caption = '';
            }
            let ratingItems = [];
            let data = this.datasetItems;
            const maxvalue = parseInt(this.maxvalue || this.datasetItems.length, 10);
            const maxValue = (maxvalue > MAX_RATING ? MAX_RATING : maxvalue) || DEFAULT_RATING;
            /**
             * 1. If datasetItems.length is more than maxValue (i.e. 10 ratings) then just extract maxValue of items from datasetItems.
             * 2. If datasetItems are not available then prepare ratings value depending on maxvalue. eg: 1,2,3 .. upto maxvalue
             * 3. If maxvalue / i value is more than datasetItems length, prepare default rating items for i values more than datasetItems.length
             */
            if (data.length && data.length > maxValue) {
                data = lodashEs.slice(data, 0, maxValue);
            }
            for (let i = maxValue; i > 0; i--) {
                if (!data.length) {
                    ratingItems.push({ key: i, value: i, index: i, label: i });
                }
                else {
                    if (i > data.length) {
                        ratingItems.push({ key: i, value: i, index: i, label: i });
                    }
                    else {
                        data = i3.getOrderedDataset(data, 'index:desc');
                        ratingItems = ratingItems.concat(data);
                        break;
                    }
                }
            }
            this.ratingItems = ratingItems;
            if (!data.length) { // constructs default datasetItems when there is no dataset binding.
                this.datasetItems = ratingItems;
            }
            this.onDatavalueChange(this.datavalue);
        }
        onRatingClick($event, rate) {
            this.modelByKey = rate.key;
            this.selectedRatingValue = rate.index;
            // support if the caption is binded in the old projects for backward compatibility
            if (!this.showcaptions) {
                this.caption = rate.label;
            }
            this.invokeOnTouched();
            // invoke on datavalue change.
            this.invokeOnChange(this.datavalue, $event || {}, true);
        }
        // Update the selected flag on datasetItems and assign the ratingValue.
        /**
         * On datavalue change, update the caption, selectedRatingValue.
         * 1. if datasetItems contain the selected item (check the selected flag on item), find the index of selected item.
         * 2. if not, just check if the datavalue is provided as the index on the item.
         *
         * @param dataVal datavalue
         */
        onDatavalueChange(dataVal) {
            if (!lodashEs.isEmpty(this.datasetItems)) {
                let selectedItem = lodashEs.find(this.datasetItems, { 'selected': true });
                if (!selectedItem && !lodashEs.isUndefined(dataVal)) {
                    selectedItem = lodashEs.find(this.datasetItems, function (item) {
                        return lodashEs.toString(item.index) === dataVal;
                    });
                    if (selectedItem) {
                        selectedItem.selected = true;
                    }
                }
                if (!selectedItem) {
                    // reset the  model if there is no item found.
                    this.modelByKey = undefined;
                    this.caption = '';
                }
                this.selectedRatingValue = selectedItem ? selectedItem.index : 0;
                if (selectedItem) {
                    this.caption = selectedItem.label;
                }
            }
            else {
                this.selectedRatingValue = 0;
            }
            if (this.readonly) {
                // when dataset is not given but datavalue is provided which is integer
                if (!this.selectedRatingValue && !isNaN(dataVal)) {
                    this.selectedRatingValue = (parseFloat(dataVal) <= this.maxvalue) ? dataVal : this.maxvalue;
                }
                this.ratingsWidth = this.calculateRatingsWidth(dataVal);
            }
        }
        calculateRatingsWidth(dataVal) {
            const selectedRating = parseFloat(this.selectedRatingValue), starWidth = 0.925, maxValue = parseInt(this.maxvalue || this.datasetItems.length, 10) || DEFAULT_RATING;
            core.setCSS(this.nativeElement.querySelector('.ratings-container'), 'width', (starWidth * maxValue) + 'em');
            dataVal = dataVal || this.datavalue;
            if (dataVal === undefined || dataVal === '' || dataVal === null) {
                this.caption = '';
                return 0;
            }
            if (selectedRating <= maxValue && selectedRating >= 0) {
                return selectedRating * starWidth + 'em';
            }
            if (selectedRating > maxValue) {
                return maxValue * starWidth + 'em';
            }
        }
        onPropertyChange(key, nv, ov) {
            if (key === 'readonly') {
                if (nv) {
                    this.ratingsWidth = this.calculateRatingsWidth();
                }
            }
            else if (key === 'maxvalue') {
                /** Storing the datavalue in temp variable and assiging back to datavalue
                 * after default datalist is prepared to trigger Dataset Aware class select cycle
                 * as the datavalue property change is triggering first rather than maxvalue
                 * in the rating widget is used inside a datatable
                 */
                let tempDataValue = this.datavalue;
                this.prepareRatingDataset();
                // reset all the items.
                this.resetDatasetItems();
                if (!lodashEs.isUndefined(tempDataValue)) {
                    this.datavalue = tempDataValue;
                }
            }
            else {
                super.onPropertyChange(key, nv, ov);
            }
        }
        /* Detect touch enabled devices & update hover styles*/
        onTouchStart($event) {
            this.touchEnabled = true;
            this.onTouchStart = core.noop;
        }
        onMouseleave() {
            this.caption = this.displayValue;
        }
        onMouseOver($event, rate) {
            this.caption = rate.label;
            !this.touchEnabled && !$event.target.classList.contains('rating-label-hover') && $event.target.classList.add('rating-label-hover');
        }
        static { this.ɵfac = function RatingComponent_Factory(t) { return new (t || RatingComponent)(i0__namespace.ɵɵdirectiveInject(i0__namespace.Injector), i0__namespace.ɵɵdirectiveInject('EXPLICIT_CONTEXT', 8)); }; }
        static { this.ɵcmp = /*@__PURE__*/ i0__namespace.ɵɵdefineComponent({ type: RatingComponent, selectors: [["", "wmRating", ""]], viewQuery: function RatingComponent_Query(rf, ctx) { if (rf & 1) {
                i0__namespace.ɵɵviewQuery(_c0, 5, i0.ElementRef);
            } if (rf & 2) {
                let _t;
                i0__namespace.ɵɵqueryRefresh(_t = i0__namespace.ɵɵloadQuery()) && (ctx.ratingEl = _t.first);
            } }, features: [i0__namespace.ɵɵProvidersFeature([
                    i3.provideAs(RatingComponent, i2.NG_VALUE_ACCESSOR, true),
                    i3.provideAsWidgetRef(RatingComponent)
                ]), i0__namespace.ɵɵInheritDefinitionFeature], attrs: _c1, decls: 5, vars: 14, consts: [["ratingInput", ""], ["aria-multiselectable", "true", "ngDefaultControl", "", 1, "ratings-wrapper", 3, "focus", "ngModelChange", "ngModel", "ngModelOptions"], ["class", "rating-style", 4, "ngIf"], [1, "ratings-container", "disabled", 3, "ngStyle"], [1, "ratings", "active", 3, "ngStyle"], ["class", "caption", 3, "textContent", 4, "ngIf"], [1, "rating-style"], [3, "ngClass", "ngStyle", "title", "for", "touchstart", "mouseleave", "mouseover", 4, "ngFor", "ngForOf"], [3, "touchstart", "mouseleave", "mouseover", "ngClass", "ngStyle", "title", "for"], ["type", "radio", "role", "radio", "name", "ratings-id", 3, "click", "id", "value"], [1, "caption", 3, "textContent"]], template: function RatingComponent_Template(rf, ctx) { if (rf & 1) {
                i0__namespace.ɵɵelementStart(0, "div", 1);
                i0__namespace.ɵɵlistener("focus", function RatingComponent_Template_div_focus_0_listener($event) { return ctx.onFocus($event); });
                i0__namespace.ɵɵtwoWayListener("ngModelChange", function RatingComponent_Template_div_ngModelChange_0_listener($event) { i0__namespace.ɵɵtwoWayBindingSet(ctx.modelByKey, $event) || (ctx.modelByKey = $event); return $event; });
                i0__namespace.ɵɵtemplate(1, RatingComponent_div_1_Template, 2, 1, "div", 2);
                i0__namespace.ɵɵelementStart(2, "div", 3);
                i0__namespace.ɵɵelement(3, "div", 4);
                i0__namespace.ɵɵelementEnd();
                i0__namespace.ɵɵtemplate(4, RatingComponent_label_4_Template, 1, 1, "label", 5);
                i0__namespace.ɵɵelementEnd();
            } if (rf & 2) {
                i0__namespace.ɵɵtwoWayProperty("ngModel", ctx.modelByKey);
                i0__namespace.ɵɵproperty("ngModelOptions", i0__namespace.ɵɵpureFunction0(8, _c2));
                i0__namespace.ɵɵadvance();
                i0__namespace.ɵɵproperty("ngIf", !ctx.readonly);
                i0__namespace.ɵɵadvance();
                i0__namespace.ɵɵclassProp("hidden", !ctx.readonly);
                i0__namespace.ɵɵproperty("ngStyle", i0__namespace.ɵɵpureFunction1(9, _c3, ctx.iconsize));
                i0__namespace.ɵɵadvance();
                i0__namespace.ɵɵproperty("ngStyle", i0__namespace.ɵɵpureFunction2(11, _c4, ctx.ratingsWidth, ctx.iconcolor));
                i0__namespace.ɵɵadvance();
                i0__namespace.ɵɵproperty("ngIf", ctx.showcaptions);
            } }, dependencies: [i1__namespace.NgClass, i1__namespace.NgForOf, i1__namespace.NgIf, i1__namespace.NgStyle, i2__namespace.DefaultValueAccessor, i2__namespace.NgControlStatus, i2__namespace.NgModel, i3__namespace.TextContentDirective], encapsulation: 2 }); }
    }
    (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0__namespace.ɵsetClassMetadata(RatingComponent, [{
            type: i0.Component,
            args: [{ selector: '[wmRating]', providers: [
                        i3.provideAs(RatingComponent, i2.NG_VALUE_ACCESSOR, true),
                        i3.provideAsWidgetRef(RatingComponent)
                    ], template: "<div (focus)=\"onFocus($event)\" [(ngModel)]=\"modelByKey\" [ngModelOptions]=\"{standalone: true}\" aria-multiselectable=\"true\"\n     class=\"ratings-wrapper\" ngDefaultControl>\n    <div *ngIf=\"!readonly\" class=\"rating-style\">\n        <label *ngFor=\"let rate of ratingItems;\"\n               [ngClass]=\"{active : rate.index <= selectedRatingValue}\"\n               [ngStyle]=\"{'font-size' :iconsize, color: rate.index <= selectedRatingValue && iconcolor}\"\n               [title]=\"rate.label || rate.index\"\n               (touchstart)=\"onTouchStart($event)\"\n               (mouseleave)=\"onMouseleave($event, rate)\"\n               (mouseover)=\"onMouseOver($event, rate)\"\n               [for]=\"_id + '-' + rate.index\">\n            <input #ratingInput type=\"radio\" role=\"radio\" [attr.aria-label]=\"(rate.label || rate.index) + ' out of ' + ratingItems.length + ' ratings'\" [attr.aria-checked]=\"rate.label === datavalue ? 'true' : 'false'\"\n                   [id]=\"_id + '-' + rate.index\" (click)=\"onRatingClick($event, rate)\" name=\"ratings-id\" [value]=\"rate.key || rate.index\"/>\n        </label>\n    </div>\n    <div [class.hidden]=\"!readonly\" [ngStyle]=\"{'font-size' :iconsize}\" class=\"ratings-container disabled\" >\n        <div class=\"ratings active\" [ngStyle]=\"{width: ratingsWidth, color: iconcolor}\"></div>\n    </div>\n    <label *ngIf=\"showcaptions\" class=\"caption\" [textContent]=\"caption\"></label>\n</div>\n" }]
        }], () => [{ type: i0__namespace.Injector }, { type: undefined, decorators: [{
                    type: i0.Inject,
                    args: ['EXPLICIT_CONTEXT']
                }, {
                    type: i0.Optional
                }] }], { ratingEl: [{
                type: i0.ViewChild,
                args: ['ratingInput', /* TODO: add static flag */ { read: i0.ElementRef }]
            }] }); })();
    (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0__namespace.ɵsetClassDebugInfo(RatingComponent, { className: "RatingComponent", filePath: "rating.component.ts", lineNumber: 25 }); })();

    const components = [
        RatingComponent
    ];
    class RatingModule {
        static { this.ɵfac = function RatingModule_Factory(t) { return new (t || RatingModule)(); }; }
        static { this.ɵmod = /*@__PURE__*/ i0__namespace.ɵɵdefineNgModule({ type: RatingModule }); }
        static { this.ɵinj = /*@__PURE__*/ i0__namespace.ɵɵdefineInjector({ imports: [i1.CommonModule,
                i2.FormsModule,
                i3.WmComponentsModule] }); }
    }
    (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0__namespace.ɵsetClassMetadata(RatingModule, [{
            type: i0.NgModule,
            args: [{
                    imports: [
                        i1.CommonModule,
                        i2.FormsModule,
                        i3.WmComponentsModule
                    ],
                    declarations: [...components],
                    exports: [...components]
                }]
        }], null, null); })();
    (function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0__namespace.ɵɵsetNgModuleScope(RatingModule, { declarations: [RatingComponent], imports: [i1.CommonModule,
            i2.FormsModule,
            i3.WmComponentsModule], exports: [RatingComponent] }); })();

    exports.RatingComponent = RatingComponent;
    exports.RatingModule = RatingModule;

}));
