"use strict";
/* eslint @typescript-eslint/no-var-requires: "off" */
/**
 * Step abstraction
 *
 *  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
 *   - References to "quote" should be replaced with generic terminology
 *     representing a document.
 *   - Sorting logic must be extracted, and MultiSort decoupled.
 * @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.Step = void 0;
var EventEmitter = require('events').EventEmitter;
/**
 * Represents a single step to be displayed in the UI
 */
var Step = /** @class */ (function (_super) {
    __extends(Step, _super);
    /**
     * Initializes step
     *
     * @param id         - step identifier
     * @param quote      - quote to contain step data
     * @param _multisort - a sorting function
     */
    function Step(id, quote, _multi_sort) {
        var _this = _super.call(this) || this;
        _this._multi_sort = _multi_sort;
        /**
         * Called when quote is changed
         */
        _this.EVENT_QUOTE_UPDATE = 'updateQuote';
        /**
         * Step identifier
         */
        _this._id = 0;
        /**
         * Data bucket to store the raw data for submission
         */
        _this._bucket = null;
        /**
         * Fields contained exclusively on the step (no linked)
         */
        _this._exclusiveFields = {};
        /**
         * Fields that must contain a value
         */
        _this._requiredFields = {};
        /**
         * Whether all fields on the step contain valid data
         */
        _this._valid = true;
        /**
         * Explanation of what made the step valid/invalid, if applicable
         *
         * This is useful for error messages
         */
        _this._validCause = '';
        /**
         * Sorted group sets
         */
        _this._sortedGroups = {};
        _this._id = +id;
        // TODO: this is temporary; do not pass bucket, pass quote
        quote.visitData(function (bucket) {
            _this._bucket = bucket;
        });
        return _this;
    }
    /**
     * Returns the numeric step identifier
     *
     * @return step identifier
     */
    Step.prototype.getId = function () {
        return this._id;
    };
    /**
     * Return the bucket associated with this step
     *
     * XXX: Remove me; breaks encapsulation.
     *
     * @return bucket associated with step
     */
    Step.prototype.getBucket = function () {
        return this._bucket;
    };
    /**
     * Set whether or not the data on the step is valid
     *
     * @param valid - whether the step contains only valid data
     * @param cause - Explanation of what made the step valid/invalid
     */
    Step.prototype.setValid = function (valid, cause) {
        this._valid = !!valid;
        this._validCause = cause;
        return this;
    };
    /**
     * Returns whether all the elements in the step contain valid data
     *
     * @param cmatch - cmatch data
     *
     * @return true if all elements are valid, otherwise false
     */
    Step.prototype.isValid = function (cmatch) {
        if (!cmatch) {
            throw Error('Missing cmatch data');
        }
        return this._valid && this.getNextRequired(cmatch) === null;
    };
    Step.prototype.getValidCause = function () {
        return this._validCause;
    };
    /**
     * Retrieve the next required value that is empty
     *
     * Aborts on first missing required field with its name and index.
     *
     * @param cmatch - cmatch data
     *
     * @return first missing required field
     */
    Step.prototype.getNextRequired = function (cmatch) {
        var _a;
        cmatch = cmatch || {};
        // check to ensure that each required field has a value in the bucket
        for (var name_1 in this._requiredFields) {
            var data = (_a = this._bucket) === null || _a === void 0 ? void 0 : _a.getDataByName(name_1), cdata = cmatch[name_1];
            // a non-empty string indicates that the data is missing (absense of
            // an index has no significance)
            for (var i in data) {
                // any falsy value will be considered empty (note that !"0" ===
                // false, so this will work)
                if (!data[+i] && data[+i] !== 0) {
                    if (!cdata || (cdata && cdata.indexes[i])) {
                        return [name_1, i];
                    }
                }
            }
        }
        // all required fields have values
        return null;
    };
    /**
     * Sets a new quote to be used for data storage and retrieval
     *
     * @param quote - new quote
     */
    Step.prototype.updateQuote = function (quote) {
        var _this = this;
        quote.visitData(function (quote_bucket) {
            _this._bucket = quote_bucket;
        });
        this.emit(this.__self.$('EVENT_QUOTE_UPDATE'));
        return this;
    };
    /**
     * Adds field names exclusively contained on this step (no linked)
     *
     * @param fields - field names
     */
    Step.prototype.addExclusiveFieldNames = function (fields) {
        var i = fields.length;
        while (i--) {
            this._exclusiveFields[fields[i]] = true;
        }
        return this;
    };
    /**
     * Retrieve list of field names (no linked)
     *
     * @return field names
     */
    Step.prototype.getExclusiveFieldNames = function () {
        return this._exclusiveFields;
    };
    /**
     * Set names of fields that must contain a value
     *
     * @param required - required field names
     */
    Step.prototype.setRequiredFieldNames = function (required) {
        this._requiredFields = required;
        return this;
    };
    Step.prototype.setSortedGroupSets = function (sets) {
        this._sortedGroups = sets;
        return this;
    };
    Step.prototype.eachSortedGroupSet = function (c) {
        for (var id in this._sortedGroups) {
            // call continuation with each sorted set containing the group ids
            c(this._processSortedGroup(this._sortedGroups[id]));
        }
    };
    Step.prototype._processSortedGroup = function (group_data) {
        var _a;
        var data = [];
        for (var i in group_data) {
            var cur = group_data[i], name_2 = cur[0], fields = cur[1];
            // get data for each of the fields
            var fdata = [];
            for (var j in fields) {
                fdata.push((_a = this._bucket) === null || _a === void 0 ? void 0 : _a.getDataByName(fields[j]));
            }
            data.push([name_2, fdata]);
        }
        var toint = [0, 0, 1];
        function pred(i, a, b) {
            var vala = a[1][i][0], valb = b[1][i][0];
            // convert to numeric if it makes sense to do so (otherwise, we may
            // be comparing them as strings, which does not quite give us the
            // ordering we desire)
            if (toint[+i]) {
                vala = +vala;
                valb = +valb;
            }
            if (vala > valb) {
                return 1;
            }
            else if (vala < valb) {
                return -1;
            }
            return 0;
        }
        // generate predicates
        var preds = [];
        for (var i in group_data[0][1]) {
            (function (i) {
                preds.push(function (a, b) {
                    return pred(i, a, b);
                });
            })(i);
        }
        // sort the data
        var sorted = this._multi_sort(data, preds);
        // return the group names
        var ret = [];
        for (var i in sorted) {
            // add name
            ret.push(sorted[i][0]);
        }
        return ret;
    };
    return Step;
}(EventEmitter));
exports.Step = Step;
//# sourceMappingURL=data:application/json;base64, 