"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const Semifunctional_1 = require("../../../../Class/Semifunctional");
const Heap_1 = require("../../../../Heap");
const Waiter_1 = require("../../../../Waiter");
const _ids_1 = require("../../../_ids");
class Sort extends Semifunctional_1.Semifunctional {
    constructor(system) {
        super({
            fi: ['a'],
            fo: ['b'],
            i: ['a[i] < a[j]'],
            o: ['a[i]', 'a[j]'],
        }, {}, system, _ids_1.ID_SORT);
        this._forward_waiter = new Waiter_1.Waiter();
        this._backward_waiter = new Waiter_1.Waiter();
        this._predicate = (a, b) => __awaiter(this, void 0, void 0, function* () {
            this._forwarding = true;
            this._output['a[i]'].push(a);
            this._output['a[j]'].push(b);
            this._forwarding = false;
            const result = yield this._forward_waiter.once();
            this._forward_waiter.clear();
            this._input['a[i] < a[j]'].pull();
            yield this._backward_waiter.once();
            this._backward_waiter.clear();
            return result;
        });
    }
    f({ a }, done) {
        return __awaiter(this, void 0, void 0, function* () {
            let heap = null;
            for (const value of a) {
                heap = yield (0, Heap_1.asyncAddHeapNode)(heap, { parent: null, left: null, right: null, value }, this._predicate);
            }
            const b = heap ? yield (0, Heap_1.asyncToSortedArray)(heap, this._predicate) : [];
            done({
                b,
            });
        });
    }
    onIterDataInputData(name, data) {
        switch (name) {
            case 'a[i] < a[j]': {
                this._forward_waiter.set(data);
                break;
            }
        }
    }
    onIterDataOutputDrop(name) {
        // console.log('onIterDataOutputDrop', name)
        if (!this._forwarding) {
            if (this._output['a[i]'].empty() && this._output['a[j]'].empty()) {
                this._backward_waiter.set(true);
            }
        }
    }
}
exports.default = Sort;
//# sourceMappingURL=index.js.map