"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const debug_1 = __importDefault(require("debug"));
const debug = {
    info: (0, debug_1.default)('zigbee-herdsman:helpers:requestQueue'),
    error: (0, debug_1.default)('zigbee-herdsman:helpers:requestQeue'),
};
class RequestQueue extends Set {
    sendInProgress;
    ID;
    deviceIeeeAddress;
    constructor(endpoint) {
        super();
        this.sendInProgress = false;
        this.ID = endpoint.ID;
        this.deviceIeeeAddress = endpoint.deviceIeeeAddress;
    }
    async send(fastPolling) {
        if (this.size === 0)
            return;
        if (!fastPolling && this.sendInProgress) {
            debug.info(`Request Queue (${this.deviceIeeeAddress}/${this.ID}): sendPendingRequests already in progress`);
            return;
        }
        this.sendInProgress = true;
        // Remove expired requests first
        const now = Date.now();
        for (const request of this) {
            if (now > request.expires) {
                debug.info(`Request Queue (${this.deviceIeeeAddress}/${this.ID}): discard after timeout. ` +
                    `Size before: ${this.size}`);
                request.reject();
                this.delete(request);
            }
        }
        debug.info(`Request Queue (${this.deviceIeeeAddress}/${this.ID}): send pending requests (` +
            `${this.size}, ${fastPolling})`);
        for (const request of this) {
            if (fastPolling || request.sendPolicy !== 'bulk') {
                try {
                    const result = await request.send();
                    debug.info(`Request Queue (${this.deviceIeeeAddress}/${this.ID}): send success`);
                    request.resolve(result);
                    this.delete(request);
                }
                catch (error) {
                    debug.info(`Request Queue (${this.deviceIeeeAddress}/${this.ID}): send failed, expires in ` +
                        `${(request.expires - now) / 1000} seconds`);
                }
            }
        }
        this.sendInProgress = false;
    }
    async queue(request) {
        debug.info(`Request Queue (${this.deviceIeeeAddress}/${this.ID}): Sending when active. ` +
            `Expires: ${request.expires}`);
        return new Promise((resolve, reject) => {
            request.addCallbacks(resolve, reject);
            this.add(request);
        });
    }
    filter(newRequest) {
        if (this.size === 0 || !(typeof newRequest.frame.getCommand === 'function')) {
            return;
        }
        const clusterID = newRequest.frame.Cluster.ID;
        const payload = newRequest.frame.Payload;
        const commandID = newRequest.frame.getCommand().ID;
        debug.info(`Request Queue (${this.deviceIeeeAddress}/${this.ID}): ZCL ${newRequest.frame.getCommand().name} ` +
            `command, filter requests. Before: ${this.size}`);
        for (const request of this) {
            if (request?.frame?.Cluster?.ID === undefined || typeof request.frame.getCommand !== 'function') {
                continue;
            }
            if (['bulk', 'queue', 'immediate'].includes(request.sendPolicy)) {
                continue;
            }
            /* istanbul ignore else */
            if (request.frame.Cluster.ID === clusterID && request.frame.getCommand().ID === commandID) {
                /* istanbul ignore else */
                if (newRequest.sendPolicy === 'keep-payload'
                    && JSON.stringify(request.frame.Payload) === JSON.stringify(payload)) {
                    debug.info(`Request Queue (${this.deviceIeeeAddress}/${this.ID}): Merge duplicate request`);
                    this.delete(request);
                    newRequest.moveCallbacks(request);
                }
                else if ((newRequest.sendPolicy === 'keep-command' || newRequest.sendPolicy === 'keep-cmd-undiv') &&
                    Array.isArray(request.frame.Payload)) {
                    const filteredPayload = request.frame.Payload.filter((oldEl) => !payload.find((newEl) => oldEl.attrId === newEl.attrId));
                    if (filteredPayload.length == 0) {
                        debug.info(`Request Queue (${this.deviceIeeeAddress}/${this.ID}): Remove & reject request`);
                        if (JSON.stringify(request.frame.Payload) === JSON.stringify(payload)) {
                            newRequest.moveCallbacks(request);
                        }
                        else {
                            request.reject();
                        }
                        this.delete(request);
                    }
                    else if (newRequest.sendPolicy !== 'keep-cmd-undiv') {
                        // remove all duplicate attributes if we shall not write undivided
                        request.frame.Payload = filteredPayload;
                        debug.info(`Request Queue (${this.deviceIeeeAddress}/${this.ID}): `
                            + `Remove commands from request`);
                    }
                }
            }
        }
        debug.info(`Request Queue (${this.deviceIeeeAddress}/${this.ID}): After: ${this.size}`);
    }
}
exports.default = RequestQueue;
//# sourceMappingURL=requestQueue.js.map