import { __esDecorate, __runInitializers } from "tslib";
import { MessagePriority, ZWaveError, ZWaveErrorCodes, validatePayload, } from "@zwave-js/core";
import { FunctionType, Message, MessageType, expectedResponse, messageTypes, priority, } from "@zwave-js/serial";
import { Bytes, getEnumMemberName, num2hex, } from "@zwave-js/shared";
export var NVMOperationsCommand;
(function (NVMOperationsCommand) {
    NVMOperationsCommand[NVMOperationsCommand["Open"] = 0] = "Open";
    NVMOperationsCommand[NVMOperationsCommand["Read"] = 1] = "Read";
    NVMOperationsCommand[NVMOperationsCommand["Write"] = 2] = "Write";
    NVMOperationsCommand[NVMOperationsCommand["Close"] = 3] = "Close";
})(NVMOperationsCommand || (NVMOperationsCommand = {}));
export var NVMOperationStatus;
(function (NVMOperationStatus) {
    NVMOperationStatus[NVMOperationStatus["OK"] = 0] = "OK";
    NVMOperationStatus[NVMOperationStatus["Error"] = 1] = "Error";
    NVMOperationStatus[NVMOperationStatus["Error_OperationMismatch"] = 2] = "Error_OperationMismatch";
    NVMOperationStatus[NVMOperationStatus["Error_OperationInterference"] = 3] = "Error_OperationInterference";
    NVMOperationStatus[NVMOperationStatus["EndOfFile"] = 255] = "EndOfFile";
})(NVMOperationStatus || (NVMOperationStatus = {}));
let NVMOperationsRequest = (() => {
    let _classDecorators = [messageTypes(MessageType.Request, FunctionType.NVMOperations), priority(MessagePriority.Controller), expectedResponse(FunctionType.NVMOperations)];
    let _classDescriptor;
    let _classExtraInitializers = [];
    let _classThis;
    let _classSuper = Message;
    var NVMOperationsRequest = class extends _classSuper {
        static { _classThis = this; }
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
            NVMOperationsRequest = _classThis = _classDescriptor.value;
            if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
            __runInitializers(_classThis, _classExtraInitializers);
        }
        // This must be set in subclasses
        command;
        serialize(ctx) {
            this.payload = Bytes.concat([
                [this.command],
                this.payload,
            ]);
            return super.serialize(ctx);
        }
        toLogEntry() {
            const message = {
                command: getEnumMemberName(NVMOperationsCommand, this.command),
            };
            return {
                ...super.toLogEntry(),
                message,
            };
        }
    };
    return NVMOperationsRequest = _classThis;
})();
export { NVMOperationsRequest };
// =============================================================================
export class NVMOperationsOpenRequest extends NVMOperationsRequest {
    constructor(options = {}) {
        super(options);
        this.command = NVMOperationsCommand.Open;
    }
}
// =============================================================================
export class NVMOperationsCloseRequest extends NVMOperationsRequest {
    constructor(options = {}) {
        super(options);
        this.command = NVMOperationsCommand.Close;
    }
}
export class NVMOperationsReadRequest extends NVMOperationsRequest {
    constructor(options) {
        super(options);
        this.command = NVMOperationsCommand.Read;
        if (options.length < 0 || options.length > 0xff) {
            throw new ZWaveError("The length must be between 0 and 255!", ZWaveErrorCodes.Argument_Invalid);
        }
        if (options.offset < 0 || options.offset > 0xffff) {
            throw new ZWaveError("The offset must be a 16-bit number!", ZWaveErrorCodes.Argument_Invalid);
        }
        this.length = options.length;
        this.offset = options.offset;
    }
    static from(_raw, _ctx) {
        throw new ZWaveError(`${this.name}: deserialization not implemented`, ZWaveErrorCodes.Deserialization_NotImplemented);
        // return new NVMOperationsReadRequest({});
    }
    length;
    offset;
    serialize(ctx) {
        this.payload = new Bytes(3);
        this.payload[0] = this.length;
        this.payload.writeUInt16BE(this.offset, 1);
        return super.serialize(ctx);
    }
    toLogEntry() {
        const ret = super.toLogEntry();
        return {
            ...ret,
            message: {
                ...ret.message,
                "data length": this.length,
                "address offset": num2hex(this.offset),
            },
        };
    }
}
export class NVMOperationsWriteRequest extends NVMOperationsRequest {
    constructor(options) {
        super(options);
        this.command = NVMOperationsCommand.Write;
        if (options.offset < 0 || options.offset > 0xffff) {
            throw new ZWaveError("The offset must be a 16-bit number!", ZWaveErrorCodes.Argument_Invalid);
        }
        if (options.buffer.length < 1 || options.buffer.length > 0xff) {
            throw new ZWaveError("The buffer must be between 1 and 255 bytes long", ZWaveErrorCodes.Argument_Invalid);
        }
        this.offset = options.offset;
        this.buffer = options.buffer;
    }
    static from(_raw, _ctx) {
        throw new ZWaveError(`${this.name}: deserialization not implemented`, ZWaveErrorCodes.Deserialization_NotImplemented);
        // return new NVMOperationsWriteRequest({});
    }
    offset;
    buffer;
    serialize(ctx) {
        this.payload = new Bytes(3 + this.buffer.length);
        this.payload[0] = this.buffer.length;
        this.payload.writeUInt16BE(this.offset, 1);
        this.payload.set(this.buffer, 3);
        return super.serialize(ctx);
    }
    toLogEntry() {
        const ret = super.toLogEntry();
        return {
            ...ret,
            message: {
                ...ret.message,
                offset: num2hex(this.offset),
                buffer: `(${this.buffer.length} byte${this.buffer.length === 1 ? "" : "s"})`,
            },
        };
    }
}
let NVMOperationsResponse = (() => {
    let _classDecorators = [messageTypes(MessageType.Response, FunctionType.NVMOperations)];
    let _classDescriptor;
    let _classExtraInitializers = [];
    let _classThis;
    let _classSuper = Message;
    var NVMOperationsResponse = class extends _classSuper {
        static { _classThis = this; }
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
            NVMOperationsResponse = _classThis = _classDescriptor.value;
            if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
            __runInitializers(_classThis, _classExtraInitializers);
        }
        constructor(options) {
            super(options);
            // TODO: Check implementation:
            this.status = options.status;
            this.offsetOrSize = options.offsetOrSize;
            this.buffer = options.buffer;
        }
        static from(raw, _ctx) {
            validatePayload(raw.payload.length >= 2);
            const status = raw.payload[0];
            let offsetOrSize;
            if (raw.payload.length >= 4) {
                offsetOrSize = raw.payload.readUInt16BE(2);
            }
            else {
                offsetOrSize = 0;
            }
            const dataLength = raw.payload[1];
            // The response to the write command contains the offset and written data length, but no data
            let buffer;
            if (dataLength > 0 && raw.payload.length >= 4 + dataLength) {
                buffer = raw.payload.subarray(4, 4 + dataLength);
            }
            else {
                buffer = new Uint8Array();
            }
            return new this({
                status,
                offsetOrSize,
                buffer,
            });
        }
        isOK() {
            return (this.status === NVMOperationStatus.OK
                || this.status === NVMOperationStatus.EndOfFile);
        }
        status;
        offsetOrSize;
        buffer;
        toLogEntry() {
            const message = {
                status: getEnumMemberName(NVMOperationStatus, this.status),
                "address offset / NVM size": num2hex(this.offsetOrSize),
            };
            if (this.buffer.length > 0) {
                message.buffer = `(${this.buffer.length} byte${this.buffer.length === 1 ? "" : "s"})`;
            }
            return {
                ...super.toLogEntry(),
                message,
            };
        }
    };
    return NVMOperationsResponse = _classThis;
})();
export { NVMOperationsResponse };
//# sourceMappingURL=NVMOperationsMessages.js.map