"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var Extension_exports = {};
__export(Extension_exports, {
  InvalidExtension: () => InvalidExtension,
  MGRPExtension: () => MGRPExtension,
  MOSExtension: () => MOSExtension,
  MPANExtension: () => MPANExtension,
  SPANExtension: () => SPANExtension,
  Security2Extension: () => Security2Extension,
  Security2ExtensionRaw: () => Security2ExtensionRaw,
  ValidateS2ExtensionResult: () => ValidateS2ExtensionResult,
  extensionType: () => extensionType,
  getExtensionType: () => getExtensionType,
  getS2ExtensionConstructor: () => getS2ExtensionConstructor,
  validateS2Extension: () => validateS2Extension
});
module.exports = __toCommonJS(Extension_exports);
var import_tslib = require("tslib");
var import_core = require("@zwave-js/core");
var import_reflection = require("@zwave-js/core/reflection");
var import_shared = require("@zwave-js/shared");
var S2ExtensionType;
(function(S2ExtensionType2) {
  S2ExtensionType2[S2ExtensionType2["SPAN"] = 1] = "SPAN";
  S2ExtensionType2[S2ExtensionType2["MPAN"] = 2] = "MPAN";
  S2ExtensionType2[S2ExtensionType2["MGRP"] = 3] = "MGRP";
  S2ExtensionType2[S2ExtensionType2["MOS"] = 4] = "MOS";
})(S2ExtensionType || (S2ExtensionType = {}));
const extensionTypeDecorator = (0, import_reflection.createSimpleReflectionDecorator)({
  name: "extensionType"
});
const extensionType = extensionTypeDecorator.decorator;
const getExtensionType = extensionTypeDecorator.lookupValue;
const getS2ExtensionConstructor = extensionTypeDecorator.lookupConstructor;
var ValidateS2ExtensionResult;
(function(ValidateS2ExtensionResult2) {
  ValidateS2ExtensionResult2[ValidateS2ExtensionResult2["OK"] = 0] = "OK";
  ValidateS2ExtensionResult2[ValidateS2ExtensionResult2["DiscardExtension"] = 1] = "DiscardExtension";
  ValidateS2ExtensionResult2[ValidateS2ExtensionResult2["DiscardCommand"] = 2] = "DiscardCommand";
})(ValidateS2ExtensionResult || (ValidateS2ExtensionResult = {}));
function validateS2Extension(ext, wasEncrypted) {
  if (ext instanceof InvalidExtension) {
    return ValidateS2ExtensionResult.DiscardExtension;
  }
  if (ext.critical && !(ext.type in S2ExtensionType)) {
    return ValidateS2ExtensionResult.DiscardCommand;
  }
  switch (ext.type) {
    case S2ExtensionType.MPAN:
      if (!wasEncrypted) {
        return ValidateS2ExtensionResult.DiscardExtension;
      }
      break;
    case S2ExtensionType.SPAN:
    case S2ExtensionType.MGRP:
    case S2ExtensionType.MOS:
      if (wasEncrypted) {
        return ValidateS2ExtensionResult.DiscardExtension;
      }
      break;
  }
  return ValidateS2ExtensionResult.OK;
}
__name(validateS2Extension, "validateS2Extension");
class Security2ExtensionRaw {
  static {
    __name(this, "Security2ExtensionRaw");
  }
  type;
  critical;
  moreToFollow;
  payload;
  constructor(type, critical, moreToFollow, payload) {
    this.type = type;
    this.critical = critical;
    this.moreToFollow = moreToFollow;
    this.payload = payload;
  }
  static parse(data) {
    (0, import_core.validatePayload)(data.length >= 2);
    const totalLength = data[0];
    const moreToFollow = !!(data[1] & 128);
    const critical = !!(data[1] & 64);
    const type = data[1] & 63;
    const payload = data.subarray(2, totalLength);
    return new Security2ExtensionRaw(type, critical, moreToFollow, payload);
  }
  withPayload(payload) {
    return new Security2ExtensionRaw(this.type, this.critical, this.moreToFollow, payload);
  }
}
class Security2Extension {
  static {
    __name(this, "Security2Extension");
  }
  constructor(options) {
    const {
      // Try to determine the extension type if none is given
      type = getExtensionType(this),
      critical = false,
      moreToFollow = false,
      payload = new Uint8Array()
    } = options;
    if (type == void 0) {
      throw new import_core.ZWaveError("A Security2Extension must have a given or predefined extension type", import_core.ZWaveErrorCodes.Argument_Invalid);
    }
    this.type = type;
    this.critical = critical;
    this.moreToFollow = moreToFollow;
    this.payload = payload;
  }
  static parse(data) {
    const raw = Security2ExtensionRaw.parse(data);
    const Constructor = getS2ExtensionConstructor(raw.type) ?? Security2Extension;
    return Constructor.from(raw);
  }
  /** Creates an instance of the message that is serialized in the given buffer */
  static from(raw) {
    return new this({
      type: raw.type,
      critical: raw.critical,
      moreToFollow: raw.moreToFollow,
      payload: raw.payload
    });
  }
  type;
  critical;
  moreToFollow;
  payload;
  isEncrypted() {
    return false;
  }
  serialize(moreToFollow) {
    return import_shared.Bytes.concat([
      [
        2 + this.payload.length,
        (moreToFollow ? 128 : 0) | (this.critical ? 64 : 0) | this.type & 63
      ],
      this.payload
    ]);
  }
  /** Returns the number of bytes the first extension in the buffer occupies */
  static getExtensionLength(data) {
    const actual = data[0];
    let expected;
    const type = data[1] & 63;
    switch (type) {
      case S2ExtensionType.SPAN:
        expected = SPANExtension.expectedLength;
        break;
      case S2ExtensionType.MPAN:
        expected = MPANExtension.expectedLength;
        break;
      case S2ExtensionType.MGRP:
        expected = MGRPExtension.expectedLength;
        break;
      case S2ExtensionType.MOS:
        expected = MOSExtension.expectedLength;
        break;
    }
    return { expected, actual };
  }
  /** Returns the number of bytes the serialized extension will occupy */
  computeLength() {
    return 2 + this.payload.length;
  }
  toLogEntry() {
    let ret = `
\xB7 type: ${(0, import_shared.getEnumMemberName)(S2ExtensionType, this.type)}`;
    if (this.payload.length > 0) {
      ret += `
  payload: ${(0, import_shared.buffer2hex)(this.payload)}`;
    }
    return ret;
  }
}
class InvalidExtension extends Security2Extension {
  static {
    __name(this, "InvalidExtension");
  }
}
let SPANExtension = (() => {
  let _classDecorators = [extensionType(S2ExtensionType.SPAN)];
  let _classDescriptor;
  let _classExtraInitializers = [];
  let _classThis;
  let _classSuper = Security2Extension;
  var SPANExtension2 = class extends _classSuper {
    static {
      __name(this, "SPANExtension");
    }
    static {
      _classThis = this;
    }
    static {
      const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
      (0, import_tslib.__esDecorate)(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
      SPANExtension2 = _classThis = _classDescriptor.value;
      if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
    }
    constructor(options) {
      if (options.senderEI.length !== 16) {
        throw new import_core.ZWaveError("The sender's entropy must be a 16-byte buffer!", import_core.ZWaveErrorCodes.Argument_Invalid);
      }
      super({ critical: true, ...options });
      this.senderEI = options.senderEI;
    }
    static from(raw) {
      (0, import_core.validatePayload)(raw.payload.length === 16);
      const senderEI = raw.payload;
      return new SPANExtension2({
        critical: raw.critical,
        moreToFollow: raw.moreToFollow,
        senderEI
      });
    }
    senderEI;
    static expectedLength = 18;
    serialize(moreToFollow) {
      this.payload = this.senderEI;
      return super.serialize(moreToFollow);
    }
    toLogEntry() {
      let ret = super.toLogEntry().replace(/^  payload:.+$/m, "");
      ret += `  sender EI: ${(0, import_shared.buffer2hex)(this.senderEI)}`;
      return ret;
    }
    static {
      (0, import_tslib.__runInitializers)(_classThis, _classExtraInitializers);
    }
  };
  return SPANExtension2 = _classThis;
})();
let MPANExtension = (() => {
  let _classDecorators = [extensionType(S2ExtensionType.MPAN)];
  let _classDescriptor;
  let _classExtraInitializers = [];
  let _classThis;
  let _classSuper = Security2Extension;
  var MPANExtension2 = class extends _classSuper {
    static {
      __name(this, "MPANExtension");
    }
    static {
      _classThis = this;
    }
    static {
      const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
      (0, import_tslib.__esDecorate)(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
      MPANExtension2 = _classThis = _classDescriptor.value;
      if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
    }
    constructor(options) {
      if (options.innerMPANState.length !== 16) {
        throw new import_core.ZWaveError("The inner MPAN state must be a 16-byte buffer!", import_core.ZWaveErrorCodes.Argument_Invalid);
      }
      super({ critical: true, ...options });
      this.groupId = options.groupId;
      this.innerMPANState = options.innerMPANState;
    }
    static from(raw) {
      (0, import_core.validatePayload)(raw.payload.length === 17);
      const groupId = raw.payload[0];
      const innerMPANState = raw.payload.subarray(1);
      return new MPANExtension2({
        critical: raw.critical,
        moreToFollow: raw.moreToFollow,
        groupId,
        innerMPANState
      });
    }
    groupId;
    innerMPANState;
    isEncrypted() {
      return true;
    }
    static expectedLength = 19;
    serialize(moreToFollow) {
      this.payload = import_shared.Bytes.concat([
        [this.groupId],
        this.innerMPANState
      ]);
      return super.serialize(moreToFollow);
    }
    toLogEntry() {
      const mpanState = process.env.NODE_ENV === "test" || process.env.NODE_ENV === "development" ? (0, import_shared.buffer2hex)(this.innerMPANState) : "(hidden)";
      let ret = super.toLogEntry().replace(/^  payload:.+$/m, "");
      ret += `  group ID: ${this.groupId}
  MPAN state: ${mpanState}`;
      return ret;
    }
    static {
      (0, import_tslib.__runInitializers)(_classThis, _classExtraInitializers);
    }
  };
  return MPANExtension2 = _classThis;
})();
let MGRPExtension = (() => {
  let _classDecorators = [extensionType(S2ExtensionType.MGRP)];
  let _classDescriptor;
  let _classExtraInitializers = [];
  let _classThis;
  let _classSuper = Security2Extension;
  var MGRPExtension2 = class extends _classSuper {
    static {
      __name(this, "MGRPExtension");
    }
    static {
      _classThis = this;
    }
    static {
      const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
      (0, import_tslib.__esDecorate)(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
      MGRPExtension2 = _classThis = _classDescriptor.value;
      if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
    }
    constructor(options) {
      super({ critical: true, ...options });
      this.groupId = options.groupId;
    }
    static from(raw) {
      (0, import_core.validatePayload)(raw.payload.length === 1);
      const groupId = raw.payload[0];
      return new MGRPExtension2({
        critical: raw.critical,
        moreToFollow: raw.moreToFollow,
        groupId
      });
    }
    groupId;
    static expectedLength = 3;
    serialize(moreToFollow) {
      this.payload = import_shared.Bytes.from([this.groupId]);
      return super.serialize(moreToFollow);
    }
    toLogEntry() {
      let ret = super.toLogEntry().replace(/^  payload:.+$/m, "");
      ret += `  group ID: ${this.groupId}`;
      return ret;
    }
    static {
      (0, import_tslib.__runInitializers)(_classThis, _classExtraInitializers);
    }
  };
  return MGRPExtension2 = _classThis;
})();
let MOSExtension = (() => {
  let _classDecorators = [extensionType(S2ExtensionType.MOS)];
  let _classDescriptor;
  let _classExtraInitializers = [];
  let _classThis;
  let _classSuper = Security2Extension;
  var MOSExtension2 = class extends _classSuper {
    static {
      __name(this, "MOSExtension");
    }
    static {
      _classThis = this;
    }
    static {
      const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
      (0, import_tslib.__esDecorate)(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
      MOSExtension2 = _classThis = _classDescriptor.value;
      if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
    }
    constructor(options = {}) {
      super({ critical: false, ...options });
    }
    static expectedLength = 2;
    static {
      (0, import_tslib.__runInitializers)(_classThis, _classExtraInitializers);
    }
  };
  return MOSExtension2 = _classThis;
})();
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  InvalidExtension,
  MGRPExtension,
  MOSExtension,
  MPANExtension,
  SPANExtension,
  Security2Extension,
  Security2ExtensionRaw,
  ValidateS2ExtensionResult,
  extensionType,
  getExtensionType,
  getS2ExtensionConstructor,
  validateS2Extension
});
//# sourceMappingURL=Extension.js.map
