"use strict";
/* TODO auto-generated eslint ignore, please fix! */
/* eslint no-undef: "off", @typescript-eslint/no-this-alias: "off", @typescript-eslint/no-inferrable-types: "off", no-var: "off", prefer-arrow-callback: "off", prefer-const: "off", block-scoped-var: "off", no-redeclare: "off", no-unused-vars: "off" */
/**
 * Group tabbed block UI
 *
 *  Copyright (C) 2010-2019 R-T Specialty, LLC.
 *
 *  This file is part of liza.
 *
 *  liza is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @needsLove
 *   - Remove reliance on jQuery.
 *   - Dependencies need to be liberated: Styler; Group.
 * @end needsLove
 */
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 (Object.prototype.hasOwnProperty.call(b, 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 __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.TabbedBlockGroupUi = void 0;
var GroupUi_1 = require("./GroupUi");
/**
 * Represents a tabbed block group
 *
 * Does not currently support removing individual tabs (it will only clear
 * out all tabs)
 */
var TabbedBlockGroupUi = /** @class */ (function (_super) {
    __extends(TabbedBlockGroupUi, _super);
    function TabbedBlockGroupUi() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        /**
         * The parent element boxy thingy that contains all other elements
         */
        _this._box = null;
        /**
         * The list containing all clickable tabs
         */
        _this._tabList = null;
        /**
         * Element representing a tab itself
         */
        _this._tabItem = null;
        /**
         * Base tab content element
         */
        _this._contentItem = null;
        /**
         * Index of the currently selected tab
         */
        _this._curIndex = 0;
        /**
         * Index of the default selected tab
         */
        _this._defaultSelectionField = null;
        /**
         * Disable flags
         */
        _this._disableFlags = [];
        /**
         * Message to display when group is disabled after a blocking state resolves
         */
        _this._disableMessage = '';
        /**
         * Bucket prefix for "tab extraction" source data
         */
        _this._tabExtractSrc = '';
        /**
         * Bucket prefix for "tab extraction" result data
         */
        _this._tabExtractDest = '';
        /**
         * Field to check for length (number of tabs); will default to first field
         */
        _this._lengthField = '';
        return _this;
    }
    TabbedBlockGroupUi.prototype.processContent = function (quote) {
        this._box = this.$content.find('.groupTabbedBlock')[0];
        // determine if we should lock this group down
        if (this.$content.find('.groupTabbedBlock').hasClass('locked')) {
            this.group.locked(true);
        }
        this._processNonInternalHides(quote);
        this._processTabExtract();
        this._processElements();
        this._processAddButton();
        this._processLengthField();
    };
    TabbedBlockGroupUi.prototype._processNonInternalHides = function (quote) {
        var _self = this;
        var disable_attr = this._box.getAttribute('data-disable-flags');
        var disable_msg_attr = this._box.getAttribute('data-disable-message');
        this._disableFlags = disable_attr ? disable_attr.split(';') : [];
        this._disableMessage = disable_msg_attr
            ? disable_msg_attr
            : 'Unable to provide a rate at this time';
        this._state_manager.processDataAttributes(this._box);
        quote.visitData(function (bucket) {
            _self._bucket = bucket;
        });
    };
    TabbedBlockGroupUi.prototype._processTabExtract = function () {
        this._tabExtractSrc = this._box.getAttribute('data-tabextract-src');
        this._tabExtractDest = this._box.getAttribute('data-tabextract-dest');
        this._defaultSelectionField =
            this._box.getAttribute('data-default-selected-field') || '';
    };
    TabbedBlockGroupUi.prototype._processElements = function () {
        this._tabList = this._box.querySelector('ul.tabs');
        var tab = this._box.querySelector('li');
        var content = this._box.querySelector('.tab-content');
        this._tabItem = tab.parentElement.removeChild(tab);
        this._contentItem = content.parentElement.removeChild(content);
        this._box.appendChild(this._createElement('div', {
            classList: ['group-pending', 'hidden'],
            elems: [
                this._createElement('div', { classList: ['spinny'] }),
                this._createElement('p', { innerText: 'Please wait...' }),
            ],
        }));
        this._box.appendChild(this._createElement('div', {
            classList: ['group-unavailable', 'hidden'],
            innerText: this._disableMessage,
        }));
    };
    /**
     * Create an element by tag name with a set of attributes
     *
     * @param tagName    - Element's tag name
     * @param attributes - List of attributes
     *
     * @return An HTML element
     */
    TabbedBlockGroupUi.prototype._createElement = function (tagName, attributes) {
        attributes = attributes || {};
        var elem = document.createElement(tagName);
        if (Array.isArray(attributes.classList)) {
            attributes.classList.forEach(function (c) { return elem.classList.add(c); });
        }
        if (Array.isArray(attributes.elems)) {
            attributes.elems.forEach(function (e) { return elem.appendChild(e); });
        }
        if (typeof attributes.innerText === 'string') {
            elem.innerText = attributes.innerText;
        }
        return elem;
    };
    TabbedBlockGroupUi.prototype._processAddButton = function () {
        var $btn = this._getAddButton();
        if (this.group.locked()) {
            $btn.hide();
            return;
        }
    };
    TabbedBlockGroupUi.prototype._processLengthField = function () {
        this._lengthField = this._box.getAttribute('data-length-field') || '';
    };
    TabbedBlockGroupUi.prototype._processHideFlags = function () {
        var _a;
        if (this._disableFlags.length === 0) {
            return false;
        }
        var data = (_a = this._bucket) === null || _a === void 0 ? void 0 : _a.getData();
        if (!data) {
            return false;
        }
        var n = 0;
        var disables = [];
        for (var i in this._disableFlags) {
            var flag = this._disableFlags[i];
            for (var tabi in data[flag] || {}) {
                var val = data[flag][tabi], hide = !(val === '' || +val === 0);
                // hides should be preserved for multiple criteria
                disables[+tabi] = disables[+tabi] || hide;
            }
        }
        // perform the show/hide
        for (var tabi = 0; tabi < disables.length; tabi++) {
            var hide = disables[tabi];
            this._disableTab(tabi, hide);
            // count the number of hidden
            n += +hide;
        }
        var isHidden = n >= this._getTabCount();
        this._toggleClass(this._box, 'disabled', isHidden);
        return isHidden;
    };
    /**
     * Handle forced-visibility for a disabled tab group when a blocking state
     * is resolved
     *
     * @param isDisabled - If the group is disabled
     * @param isPending  - If the group is pending the resolution of a
     *                             blocking flag
     */
    TabbedBlockGroupUi.prototype._processUnavailable = function (isDisabled, isPending) {
        var unavailableMsg = this._box.querySelector('.group-unavailable');
        this._toggleClass(this._box, 'unavailable', isDisabled);
        this._toggleClass(unavailableMsg, 'hidden', isPending || !isDisabled);
    };
    /**
     * Update the related pending UI elements
     *
     * @param pending - whether we are setting pending to true or false
     *
     * @return Pending state
     */
    TabbedBlockGroupUi.prototype._setPending = function (pending) {
        this._toggleClass(this._box.querySelector('.group-pending'), 'hidden', !pending);
        this._toggleClass(this._box.querySelector('.supplier-selector'), 'hidden', pending);
        this._toggleClass(this._box.querySelector('.tab-content'), 'hidden', pending);
        this._toggleClass(this._tabList, 'hidden', pending);
        return pending;
    };
    TabbedBlockGroupUi.prototype._disableTab = function (i, disable) {
        var tab = this._getTab(i);
        if (disable && !tab.classList.contains('disabled')) {
            tab.classList.add('disabled');
        }
        else if (!disable && tab.classList.contains('disabled')) {
            tab.classList.remove('disabled');
        }
    };
    TabbedBlockGroupUi.prototype._removeTab = function (index) {
        var tab = this._getTab(index);
        var content = this._getTabContent(index);
        tab.parentElement.removeChild(tab);
        content.parentElement.removeChild(content);
    };
    TabbedBlockGroupUi.prototype.getFirstElementName = function (_) {
        return this._lengthField || _super.prototype.getFirstElementName.call(this);
    };
    TabbedBlockGroupUi.prototype.postPreEmptyBucketFirst = function () {
        // select the first tab
        this._selectTab(0);
        return this;
    };
    /**
     * Sets element value given a name and index
     *
     * This has the performance benefit of searching *only* within the group
     * rather than scanning the entire DOM (or a much larger subset)
     *
     * @param name         - element name
     * @param index        - index to set
     * @param value        - value to set
     * @param change_event - whether to trigger change event
     */
    TabbedBlockGroupUi.prototype.setValueByName = function (name, index, value, change_event) {
        var isDisabled = this._processHideFlags();
        var isPending = this._state_manager.is('pending', this._bucket);
        this._setPending(isPending);
        if (this._state_manager.observes('pending')) {
            this._processUnavailable(isDisabled, isPending);
        }
        _super.prototype.setValueByName.call(this, name, index, value, change_event);
        return this;
    };
    TabbedBlockGroupUi.prototype.addIndex = function (index) {
        this.addTab();
        _super.prototype.addIndex.call(this, index);
        return this;
    };
    TabbedBlockGroupUi.prototype.removeIndex = function (index) {
        this._removeTab(this.getCurrentIndexCount() - 1);
        _super.prototype.removeIndex.call(this, index);
        return this;
    };
    TabbedBlockGroupUi.prototype._getAddButton = function () {
        return this.$content.find('.addTab:first');
    };
    TabbedBlockGroupUi.prototype._showAddButton = function () {
        // only show if we're not locked
        if (this.group.locked()) {
            return;
        }
        this._getAddButton().show();
    };
    TabbedBlockGroupUi.prototype._hideAddButton = function () {
        this._getAddButton().hide();
    };
    TabbedBlockGroupUi.prototype._checkAddButton = function () {
        // max rows reached
        if (this.group.maxRows() &&
            this.getCurrentIndexCount() === this.group.maxRows()) {
            this._hideAddButton();
        }
        else {
            this._showAddButton();
        }
    };
    TabbedBlockGroupUi.prototype._getNextIndex = function () {
        var index = this.getCurrentIndexCount();
        if (this.group.maxRows() && index === this.group.maxRows()) {
            throw Error('Max rows reached');
        }
        return index;
    };
    TabbedBlockGroupUi.prototype._getTabCount = function () {
        return this.getCurrentIndexCount();
    };
    TabbedBlockGroupUi.prototype.addTab = function () {
        try {
            var index = this._getNextIndex();
        }
        catch (e) {
            this._checkAddButton();
            return false;
        }
        // append the tab itself
        this._tabList.appendChild(this._createTab(index)[0]);
        // append the tab content
        var clear_tabs = this._box.getElementsByClassName('tabClear');
        clear_tabs[clear_tabs.length - 1].insertAdjacentElement('beforebegin', this._createTabContent(index)[0]);
        // hide the add button if needed
        this._checkAddButton();
        this._hideTab(index);
        return true;
    };
    TabbedBlockGroupUi.prototype._createTab = function (index) {
        var _self = this;
        return this._finalizeContent(index, this.jquery(this._tabItem.cloneNode(true))
            .click(function () {
            _self._selectTab(index);
        })
            .find('a')
            // prevent anchor clicks from updating the URL
            .click(function (event) {
            event.preventDefault();
        })
            .end());
    };
    TabbedBlockGroupUi.prototype._createTabContent = function (index) {
        var item = this._contentItem.cloneNode(true);
        // Set field content parent for this index
        this.fieldContentParent[index] = item.querySelector('dl');
        if (this.getDomPerfFlag() === true) {
            this.context.addIndex(index, this.fieldContentParent[index]);
        }
        return this._finalizeContent(index, this.jquery(item));
    };
    TabbedBlockGroupUi.prototype._finalizeContent = function (index, $content) {
        var content = $content[0];
        // properly name the elements to prevent id conflicts
        this.setElementIdIndexes(content.getElementsByTagName('*'), index);
        this.styler.apply($content);
        // allow hooks to perform their magic on our content
        this.postAddRow($content, index);
        return $content;
    };
    TabbedBlockGroupUi.prototype._selectTab = function (index) {
        this._hideTab(this._curIndex);
        this._showTab((this._curIndex = +index));
        this._tabExtract(index);
    };
    TabbedBlockGroupUi.prototype._tabExtract = function (index) {
        var _self = this;
        function pred(name) {
            // determine if the name matches the expected prefix (previously,
            // this was a regex, but profiling showed that performance was very
            // negatively impacted, so this is the faster solution)
            return (name.substr(0, _self._tabExtractSrc.length) === _self._tabExtractSrc);
        }
        // wait for a repaint so that we don't slow down the tab selection
        setTimeout(function () {
            var _a, _b;
            var cur = {};
            (_a = _self._bucket) === null || _a === void 0 ? void 0 : _a.filter(pred, function (data, name) {
                var curdata = data[index];
                // ignore bogus data
                if (curdata === undefined || curdata === null) {
                    return;
                }
                // guess if this is an array (if not, then it needs to be, since
                // we'll be storing it in the bucket)
                if (typeof curdata === 'string' || curdata.length === undefined) {
                    curdata = [curdata];
                }
                cur[_self._tabExtractDest + name] = curdata;
            });
            (_b = _self._bucket) === null || _b === void 0 ? void 0 : _b.setValues(cur);
        }, 25);
    };
    TabbedBlockGroupUi.prototype._getTabContent = function (index) {
        return this._box.getElementsByClassName('tab-content')[index];
    };
    TabbedBlockGroupUi.prototype._getTab = function (index) {
        return this._tabList.querySelectorAll('li')[index];
    };
    TabbedBlockGroupUi.prototype._showTab = function (index) {
        this._toggleClass(this._getTab(index), 'inactive', false);
        this._toggleClass(this._getTabContent(index), 'inactive', false);
    };
    TabbedBlockGroupUi.prototype._hideTab = function (index) {
        this._toggleClass(this._getTab(index), 'inactive', true);
        this._toggleClass(this._getTabContent(index), 'inactive', true);
    };
    TabbedBlockGroupUi.prototype._getLastEligibleTab = function () {
        var tab_count = this._getTabCount();
        var tab_index = -1;
        for (var i = 0; i < tab_count; i++) {
            if (this._isEligibleTab(i)) {
                tab_index = i;
            }
        }
        return Math.max(0, tab_index);
    };
    TabbedBlockGroupUi.prototype._isEligibleTab = function (index) {
        return !this._tabList
            .querySelectorAll('li')[index].classList.contains('disabled');
    };
    TabbedBlockGroupUi.prototype.visit = function () {
        var _a;
        // let supertype do its own thing
        _super.prototype.visit.call(this);
        // we will have already rated once by the time this is called
        var isDisabled = this._processHideFlags();
        var isPending = this._state_manager.is('pending', this._bucket);
        this._setPending(isPending);
        if (this._state_manager.observes('pending')) {
            this._processUnavailable(isDisabled, isPending);
        }
        if (this._defaultSelectionField === '') {
            // select first tab that is eligible and
            // perform tab extraction (to reflect first eligible tab)
            this._selectTab(this._getLastEligibleTab());
        }
        else {
            // select the tab based on selection index
            var index = (_a = this._bucket) === null || _a === void 0 ? void 0 : _a.getDataByName(this._defaultSelectionField || '')[0];
            if (index !== undefined && this._isEligibleTab(index)) {
                this._selectTab(index || 0);
            }
            else {
                this._selectTab(this._getLastEligibleTab());
            }
        }
        return this;
    };
    /**
     * Toggles a class name on a given element
     *
     * @param elem       - the element
     * @param class_name - the class to toggle`
     * @param force      - whether to add or remove the class
     *
     * @return whether or not the toggle happened
     */
    TabbedBlockGroupUi.prototype._toggleClass = function (elem, class_name, force) {
        if (elem) {
            if (force && !elem.classList.contains(class_name)) {
                elem.classList.add(class_name);
                return true;
            }
            else if (!force && elem.classList.contains(class_name)) {
                elem.classList.remove(class_name);
                return true;
            }
        }
        return false;
    };
    return TabbedBlockGroupUi;
}(GroupUi_1.GroupUi));
exports.TabbedBlockGroupUi = TabbedBlockGroupUi;
//# sourceMappingURL=data:application/json;base64, 