import { StateMachine, } from "@zwave-js/core";
function to(state) {
    return { newState: state };
}
export function createTransportServiceRXMachine(datagramSize, firstSegmentSize) {
    const initialState = {
        value: "receive",
    };
    const receivedBytes = [
        // When the machine is started, we've already received the first segment
        ...(new Array(firstSegmentSize).fill(true)),
        // The rest of the segments are still missing
        ...(new Array(datagramSize - firstSegmentSize).fill(false)),
    ];
    function markReceived(offset, length) {
        for (let i = offset; i < offset + length; i++) {
            receivedBytes[i] = true;
        }
    }
    function isComplete() {
        return receivedBytes.every(Boolean);
    }
    function hasReceivedLastSegment() {
        return receivedBytes.at(-1);
    }
    function hasHole() {
        return receivedBytes.lastIndexOf(true)
            > receivedBytes.indexOf(false);
    }
    const transitions = (state) => (input) => {
        if (input.value === "abort") {
            if (state.value !== "success" && state.value !== "failure") {
                return to({ value: "failure", done: true });
            }
            return;
        }
        switch (state.value) {
            case "receive": {
                if (input.value === "segment") {
                    markReceived(input.offset, input.length);
                    if (isComplete()) {
                        return to({ value: "success", done: true });
                    }
                    else if (hasReceivedLastSegment() && hasHole()) {
                        return to({
                            value: "requestMissing",
                            offset: receivedBytes.indexOf(false),
                        });
                    }
                    else {
                        return to({ value: "receive" });
                    }
                }
                else if (input.value === "timeout") {
                    // One or more segments are missing, start requesting them
                    return to({
                        value: "requestMissing",
                        offset: receivedBytes.indexOf(false),
                    });
                }
                break;
            }
            case "requestMissing": {
                if (input.value === "segment") {
                    markReceived(input.offset, input.length);
                    if (isComplete()) {
                        return to({ value: "success", done: true });
                    }
                    else {
                        // still not complete, request the next missing segment
                        return to({
                            value: "requestMissing",
                            offset: receivedBytes.indexOf(false),
                        });
                    }
                }
                else if (input.value === "timeout") {
                    // Give up
                    return to({ value: "failure", done: true });
                }
            }
        }
    };
    return new StateMachine(initialState, transitions);
}
//# sourceMappingURL=TransportServiceMachine.js.map