"use strict";
/**
 * Test case for Cmatch
 *
 *  Copyright (C) 2010-2020 R-T Specialty, LLC.
 *
 *  This file is part of the Liza Data Collection Framework
 *
 *  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/>.
 */
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 });
var CmatchVisibility_1 = require("../../src/client/CmatchVisibility");
var FieldResetter_1 = require("../../src/client/FieldResetter");
var chai_1 = require("chai");
var Cmatch_1 = require("../../src/client/Cmatch");
var CommonResources_1 = require("./CommonResources");
var sinon = require('sinon');
// these tests aren't terribly effective right now
describe('Cmatch', function () {
    it('marks hidden fields on class change to show', function () {
        var sut = createStubs().sut;
        chai_1.expect(sut.markShowHide('foo', {}, [1, 2], [])).to.deep.equal({ foo: { show: [1, 2] } });
    });
    it('marks shown fields on class change to hide', function () {
        var sut = createStubs().sut;
        chai_1.expect(sut.markShowHide('foo', {}, [], [3, 4, 5])).to.deep.equal({ foo: { hide: [3, 4, 5] } });
    });
    it('marks combination show/hide on class change', function () {
        var sut = createStubs().sut;
        chai_1.expect(sut.markShowHide('foo', {}, [2, 3], [4, 5, 6])).to.deep.equal({
            foo: {
                show: [2, 3],
                hide: [4, 5, 6],
            },
        });
    });
    it('marks no fields with no show or hide', function () {
        var sut = createStubs().sut;
        chai_1.expect(sut.markShowHide('foo', {}, [], [])).to.deep.equal({});
    });
    it('does not affect marking of other fields', function () {
        var barval = {};
        var visq = { bar: barval };
        var sut = createStubs().sut;
        var results = sut.markShowHide('foo', visq, [1], [0]);
        chai_1.expect(results.bar).to.equal(barval);
    });
    it('getCmatchFields returns only fields with cmatch data', function () {
        var expected_fields = ['foo_address', 'foo_phone'];
        var field_names = [
            'foo_name',
            'foo_id',
            'foo_address',
            'foo_term',
            'foo_date',
            'foo_phone',
            'foo_email',
        ];
        var cmatch = {
            foo_address: { all: true, any: true, indexes: [0] },
            foo_phone: { all: true, any: true, indexes: [0] },
        };
        var _a = createStubs(cmatch), sut = _a.sut, quote = _a.quote, data_validator = _a.data_validator;
        sut.hookClassifier(data_validator);
        quote.emit('classify');
        chai_1.expect(sut.getCmatchFields(field_names)).to.deep.equal(expected_fields);
    });
    /**
     * __classes is always returned (at least at the time of writing) by
     * TAME.  here was a bug when it was recognized as a field (e.g. marked
     * as an `external' in program.xml),
     */
    it('does not fail when __classes is a known field', function () {
        var cmatch = {
            // populated by TAME, always
            __classes: {},
        };
        var field_names = {
            __classes: true,
        };
        var step_ui = createStubStepUi(field_names);
        var _a = createStubs(cmatch, step_ui), sut = _a.sut, quote = _a.quote, data_validator = _a.data_validator;
        sut.hookClassifier(data_validator);
        quote.emit('classify');
    });
    describe('handleClassMatch', function () {
        it('throws error if step is undefined', function () {
            var sut = createStubs().sut;
            chai_1.expect(function () { return sut.handleClassMatch({}, false); }).to.throw(TypeError);
        });
        it('triggers dapi for every visible queued element', function () {
            var field_names = {
                foo: true,
                bar: true,
                baz: true,
            };
            var cmatch = {
                foo: { all: true, any: true, indexes: [0] },
                baz: { all: true, any: true, indexes: [0] },
            };
            var step_ui = createStubStepUi(field_names);
            var _a = createStubs(cmatch, step_ui), data_validator = _a.data_validator, quote = _a.quote, program = _a.program, sut = _a.sut;
            var given = [];
            var dapi_call_count = 0;
            program.dapi = function (_step_id, field, _bucket, _diff, _cmatch, _callback) {
                given.push(field);
                ++dapi_call_count;
                return {};
            };
            sut.hookClassifier(data_validator);
            quote.emit('classify');
            chai_1.expect(dapi_call_count).to.equal(2);
            chai_1.expect(given).to.deep.equal(['foo', 'baz']);
        });
        [
            {
                label: 'handles only current indexes in bucket',
                cur_data: ['bar'],
                cmatch: { foo: { all: true, any: true, indexes: [1, 1] } },
                expected: { foo: { all: true, any: true, indexes: [1] } },
            },
            {
                label: 'handles indexes requested when bucket and cmatch index counts are equal',
                cur_data: ['bar', 'baz'],
                cmatch: { foo: { all: true, any: true, indexes: [1, 1] } },
                expected: { foo: { all: true, any: true, indexes: [1, 1] } },
            },
            {
                label: 'handles indexes requested when bucket values exist',
                cur_data: ['bar', 'baz', 'foo'],
                cmatch: { foo: { all: true, any: true, indexes: [1, 1] } },
                expected: { foo: { all: true, any: true, indexes: [1, 1] } },
            },
        ].forEach(function (_a) {
            var label = _a.label, cur_data = _a.cur_data, cmatch = _a.cmatch, expected = _a.expected;
            it(label, function (done) {
                var step_ui = createStubStepUi({ foo: true });
                var _a = createStubs({}, step_ui), sut = _a.sut, client = _a.client, quote = _a.quote;
                var get_data_call_count = 0;
                quote.getDataByName = function (_field) {
                    ++get_data_call_count;
                    return cur_data;
                };
                client.handleEvent = function (_event_id, _data) {
                    chai_1.expect(get_data_call_count).to.equal(1);
                    chai_1.expect(sut.getMatches()).to.deep.equal(expected);
                    done();
                    return client;
                };
                sut.handleClassMatch(cmatch);
            });
        });
        [
            {
                label: "clear a field's value when a new index is automatically hidden",
                bucket: {
                    foo: ['1', 'default'],
                },
                previous_cmatch: { foo: { all: true, any: true, indexes: [1] } },
                cmatch: { foo: { all: true, any: true, indexes: [1, 0] } },
                expected: [
                    // first show events
                    {
                        foo: {},
                    },
                    // first hide events
                    {
                        foo: {},
                    },
                    // second show events
                    {
                        foo: {},
                    },
                    // second hide events
                    {
                        foo: { 1: '' },
                    },
                ],
                hasNaField: true,
            },
            {
                label: 'does not clear a retained value when a new index is automatically hidden',
                bucket: {
                    foo: ['1', 'default'],
                },
                cretain: { foo: true },
                cmatch: { foo: { all: true, any: true, indexes: [1, 0] } },
                expected: [
                    // show events
                    {
                        foo: {},
                    },
                    // hide events
                    {
                        foo: {},
                    },
                ],
            },
            {
                label: 'does not clear a field that has no default when index is automatically hidden',
                bucket: {
                    foo: ['1', 'default'],
                },
                defaults: {},
                cmatch: { foo: { all: true, any: true, indexes: [1, 0] } },
                expected: [
                    // show events
                    {
                        foo: {},
                    },
                    // hide events
                    {
                        foo: {},
                    },
                ],
            },
            {
                label: "restores a field's default value when it is shown",
                bucket: {
                    foo: ['1', ''],
                },
                cmatch: { foo: { all: true, any: true, indexes: [1, 1] } },
                expected: [
                    // show events
                    {
                        foo: { 1: 'default' },
                    },
                    // hide events
                    {
                        foo: {},
                    },
                ],
            },
            {
                label: "does not restore a field's default value that already exists in the bucket when it is shown",
                bucket: {
                    foo: ['1', 'default'],
                },
                cmatch: { foo: { all: true, any: true, indexes: [1, 1] } },
                expected: [
                    // show events
                    {
                        foo: {},
                    },
                    // hide events
                    {
                        foo: {},
                    },
                ],
            },
        ].forEach(function (_a) {
            var label = _a.label, bucket = _a.bucket, previous_cmatch = _a.previous_cmatch, cmatch = _a.cmatch, expected = _a.expected, cretain = _a.cretain, defaults = _a.defaults, hasNaField = _a.hasNaField;
            it(label, function () {
                var bucket_saves = [];
                var step_ui = createStubStepUi({ foo: true });
                var _a = createStubs({}, step_ui), sut = _a.sut, quote = _a.quote, program = _a.program;
                program.clearNaFields = true;
                program.cretain = cretain !== null && cretain !== void 0 ? cretain : {};
                program.defaults = defaults !== null && defaults !== void 0 ? defaults : program.defaults;
                program.hasNaField = function () {
                    return hasNaField !== null && hasNaField !== void 0 ? hasNaField : false;
                };
                quote.setData = function (data) {
                    var output = { foo: {} };
                    for (var i in data.foo) {
                        output.foo[i] = data.foo[i];
                    }
                    bucket_saves.push(output);
                    return {};
                };
                quote.getDataByName = function (key) {
                    if (key === 'foo') {
                        return bucket.foo;
                    }
                };
                if (previous_cmatch) {
                    sut.handleClassMatch(previous_cmatch, true);
                }
                sut.handleClassMatch(cmatch, true);
                var finished = new Promise(function (resolve, _reject) {
                    setTimeout(function () {
                        resolve(bucket_saves);
                    }, 450);
                });
                return chai_1.expect(finished).to.eventually.deep.equal(expected);
            });
        });
    });
    describe('clearCmatchFields', function () {
        it('clear only invisible fields', function () {
            var data = {
                shown_field: ['foo'],
                hidden_field: ['foo'],
            };
            var expected = {
                shown_field: ['foo'],
                hidden_field: ['default'],
            };
            var fields = {
                shown_field: true,
                hidden_field: true,
            };
            var cmatch = {};
            var step_ui = createStubStepUi(fields);
            var _a = createStubs(cmatch, step_ui, {
                program: {
                    defaults: {
                        shown_field: 'default',
                        hidden_field: 'default',
                    },
                    whens: fields,
                },
            }), sut = _a.sut, quote = _a.quote, visibility = _a.visibility;
            sinon.stub(quote, 'setData').callsFake(function (new_data) {
                if (new_data.shown_field) {
                    data.shown_field = new_data.shown_field;
                }
                if (new_data.hidden_field) {
                    data.hidden_field = new_data.hidden_field;
                }
            });
            sinon.stub(quote, 'getDataByName').callsFake(function () {
                return ['foo'];
            });
            sinon.stub(visibility, 'getBlueprints').callsFake(function () {
                return [
                    {
                        name: 'shown_field',
                        cname: '--vis-shown-field',
                        show: [0],
                        hide: [],
                    },
                    {
                        name: 'hidden_field',
                        cname: '--vis-hidden-field',
                        show: [],
                        hide: [0],
                    },
                ];
            });
            sut.clearCmatchFields();
            chai_1.expect(data).to.deep.equal(expected);
        });
        it('searches all fields in program whens', function () {
            var whens = {
                foo: [],
                bar: [],
                baz: [],
            };
            var expected = ['foo', 'bar', 'baz'];
            var actual = [];
            var cmatch = {};
            var step_ui = createStubStepUi({});
            var _a = createStubs(cmatch, step_ui, {
                program: {
                    defaults: {
                        shown_field: 'default',
                        hidden_field: 'default',
                    },
                    whens: whens,
                },
            }), sut = _a.sut, quote = _a.quote, visibility = _a.visibility;
            quote.getDataByName = function (name) {
                if (actual.indexOf(name) === -1) {
                    actual.push(name);
                }
                return {};
            };
            sinon.stub(visibility, 'getBlueprints').callsFake(function () {
                return [
                    {
                        name: 'foo',
                        cname: '--vis-foo',
                        show: [],
                        hide: [0],
                    },
                    {
                        name: 'bar',
                        cname: '--vis-bar',
                        show: [],
                        hide: [0],
                    },
                    {
                        name: 'baz',
                        cname: '--vis-baz',
                        show: [],
                        hide: [0],
                    },
                ];
            });
            sut.clearCmatchFields();
            chai_1.expect(actual).to.deep.equal(expected);
        });
    });
});
function createStubDataValidator() {
    return new (/** @class */ (function () {
        function class_1() {
        }
        class_1.prototype.validate = function (_diff, _classes, _validatef) {
            return new Promise(function () { });
        };
        return class_1;
    }()))();
}
function createStubClassMatcher(cmatch) {
    return new (/** @class */ (function () {
        function class_2() {
        }
        class_2.prototype.match = function (_classes, callback) {
            callback(cmatch);
            return this;
        };
        return class_2;
    }()))();
}
function createStubStepUi(field_names) {
    var step = {
        getExclusiveFieldNames: function () { return field_names; },
    };
    var step_ui = {
        getElementGroup: function () { return ({}); },
        getStep: function () { return step; },
        init: function () { return step_ui; },
        initGroupFieldData: function () { return undefined; },
        setContent: function (_) { return step_ui; },
        getContent: function () { return ({}); },
        setDirtyTrigger: function () { return undefined; },
        postAppend: function () { return step_ui; },
        emptyBucket: function (_, __) { return step_ui; },
        reset: function (_) { return step_ui; },
        isValid: function (_) { return true; },
        getFirstInvalidField: function (_) { return ['', 1, true]; },
        scrollTo: function (_, __, ___, ____) {
            return step_ui;
        },
        invalidate: function () { return undefined; },
        isInvalid: function () { return false; },
        hideAddRemove: function (_) { return step_ui; },
        preRender: function () { return step_ui; },
        visit: function (_) { return step_ui; },
        setActive: function (_) { return step_ui; },
        lock: function (_) { return step_ui; },
    };
    return step_ui;
}
function createStubs(cmatch, step, overrides) {
    var _a;
    if (cmatch === void 0) { cmatch = {}; }
    if (step === void 0) { step = null; }
    if (overrides === void 0) { overrides = {}; }
    var data_validator = createStubDataValidator();
    var quote = CommonResources_1.createStubClientQuote();
    var program = CommonResources_1.createStubProgram((_a = overrides.program) !== null && _a !== void 0 ? _a : {});
    var class_matcher = createStubClassMatcher(cmatch);
    var ui = CommonResources_1.createStubUi(step);
    var client = CommonResources_1.createStubClient(quote, ui, program);
    var visibility = createStubVisibility(client);
    var resetter = createStubFieldResetter(client);
    var sut = new (/** @class */ (function (_super) {
        __extends(class_3, _super);
        function class_3() {
            return _super !== null && _super.apply(this, arguments) || this;
        }
        class_3.prototype.markShowHide = function (field, visq, show, hide) {
            return _super.prototype.markShowHide.call(this, field, visq, show, hide);
        };
        class_3.prototype.handleClassMatch = function (cmatch, force) {
            _super.prototype.handleClassMatch.call(this, cmatch, force);
        };
        return class_3;
    }(Cmatch_1.Cmatch)))(class_matcher, program, client, visibility, resetter);
    return {
        sut: sut,
        data_validator: data_validator,
        quote: quote,
        ui: ui,
        client: client,
        program: program,
        class_matcher: class_matcher,
        visibility: visibility,
        resetter: resetter,
    };
}
function createStubFieldResetter(client) {
    var element_styler = {
        getDefault: function (_field) {
            return 'default';
        },
    };
    sinon.stub(client, 'elementStyler').get(function () {
        return element_styler;
    });
    return new (/** @class */ (function (_super) {
        __extends(class_4, _super);
        function class_4() {
            return _super !== null && _super.apply(this, arguments) || this;
        }
        return class_4;
    }(FieldResetter_1.FieldResetter)))(client);
}
function createStubVisibility(client) {
    return new (/** @class */ (function (_super) {
        __extends(class_5, _super);
        function class_5() {
            return _super !== null && _super.apply(this, arguments) || this;
        }
        return class_5;
    }(CmatchVisibility_1.CmatchVisibility)))(client);
}
//# sourceMappingURL=data:application/json;base64, 