"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
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 TlvAny_exports = {};
__export(TlvAny_exports, {
  AnySchema: () => AnySchema,
  TlvAny: () => TlvAny
});
module.exports = __toCommonJS(TlvAny_exports);
var import_general = require("#general");
var import_ValidationError = require("../common/ValidationError.js");
var import_TlvCodec = require("./TlvCodec.js");
var import_TlvSchema = require("./TlvSchema.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
class AnySchema extends import_TlvSchema.TlvSchema {
  getEncodedByteLength(tlvStream) {
    let byteLength = 0;
    tlvStream.forEach(({ tag, typeLength, value }) => {
      switch (typeLength.type) {
        case import_TlvCodec.TlvType.Null:
        case import_TlvCodec.TlvType.Boolean:
        case import_TlvCodec.TlvType.Array:
        case import_TlvCodec.TlvType.Structure:
        case import_TlvCodec.TlvType.List:
        case import_TlvCodec.TlvType.EndOfContainer:
          byteLength += import_TlvCodec.TlvCodec.getTagByteLength(tag);
          break;
        case import_TlvCodec.TlvType.UnsignedInt:
        case import_TlvCodec.TlvType.SignedInt:
        case import_TlvCodec.TlvType.Float:
        case import_TlvCodec.TlvType.Utf8String:
        case import_TlvCodec.TlvType.ByteString:
          byteLength += import_TlvCodec.TlvCodec.getTagByteLength(tag);
          byteLength += import_TlvCodec.TlvCodec.getPrimitiveByteLength(typeLength, value);
          break;
      }
    });
    return byteLength;
  }
  encodeTlvInternal(writer, tlvStream, tagAssigned) {
    tlvStream.forEach(({ tag, typeLength, value }) => {
      if (tagAssigned !== void 0) {
        tag = tagAssigned;
        tagAssigned = void 0;
      }
      switch (typeLength.type) {
        case import_TlvCodec.TlvType.Null:
        case import_TlvCodec.TlvType.Boolean:
        case import_TlvCodec.TlvType.Array:
        case import_TlvCodec.TlvType.Structure:
        case import_TlvCodec.TlvType.List:
        case import_TlvCodec.TlvType.EndOfContainer:
          writer.writeTag(typeLength, tagAssigned ?? tag);
          break;
        case import_TlvCodec.TlvType.UnsignedInt:
        case import_TlvCodec.TlvType.SignedInt:
        case import_TlvCodec.TlvType.Float:
        case import_TlvCodec.TlvType.Utf8String:
        case import_TlvCodec.TlvType.ByteString:
          writer.writeTag(typeLength, tagAssigned ?? tag);
          writer.writePrimitive(typeLength, value);
          break;
      }
    });
  }
  decodeTlvInternalValue(reader, typeLength) {
    return this.decodeTlvValueRec(reader, typeLength, new Array());
  }
  decodeTlvValueRec(reader, typeLength, tlvStream, tag) {
    switch (typeLength.type) {
      case import_TlvCodec.TlvType.Null:
        tlvStream.push({ tag, typeLength, value: null });
        break;
      case import_TlvCodec.TlvType.Boolean:
      case import_TlvCodec.TlvType.UnsignedInt:
      case import_TlvCodec.TlvType.SignedInt:
      case import_TlvCodec.TlvType.Float:
      case import_TlvCodec.TlvType.Utf8String:
      case import_TlvCodec.TlvType.ByteString:
        tlvStream.push({ tag, typeLength, value: reader.readPrimitive(typeLength) });
        break;
      case import_TlvCodec.TlvType.Array:
      case import_TlvCodec.TlvType.Structure:
      case import_TlvCodec.TlvType.List:
        tlvStream.push({ tag, typeLength });
        while (true) {
          const { tag: elementTag, typeLength: typeLengthElement } = reader.readTagType();
          this.decodeTlvValueRec(reader, typeLengthElement, tlvStream, elementTag);
          if (typeLengthElement.type === import_TlvCodec.TlvType.EndOfContainer) break;
        }
        break;
      case import_TlvCodec.TlvType.EndOfContainer:
        tlvStream.push({ tag, typeLength });
        break;
    }
    return tlvStream;
  }
  validate(tlvStream) {
    if (!Array.isArray(tlvStream))
      throw new import_ValidationError.ValidationDatatypeMismatchError(`Expected TlvStream, got ${typeof tlvStream}.`);
    tlvStream.forEach(({ typeLength }) => {
      if (!typeLength || typeof typeLength !== "object")
        throw new import_ValidationError.ValidationDatatypeMismatchError(
          `Expected typeLength properties in TlvStream, got ${typeof typeLength}.`
        );
      if (typeof typeLength.type !== "number")
        throw new import_ValidationError.ValidationDatatypeMismatchError(
          `Expected typeLength.type as number in TlvStream, got ${typeof typeLength.type}.`
        );
    });
  }
  decodeAnyTlvStream(encoded) {
    if (encoded.length === 0) {
      return void 0;
    }
    const reader = new import_TlvSchema.TlvArrayReader(encoded);
    const result = this.decodeGenericElement(reader);
    const nextElement = reader.readTagType();
    if (nextElement !== void 0) {
      throw new import_general.UnexpectedDataError(
        `Unexpected data left after parsing all data: ${import_general.Diagnostic.json(nextElement)}`
      );
    }
    return result;
  }
  decodeGenericElement(reader, preReadElement, allowTag = false) {
    const element = preReadElement ?? reader.readTagType();
    const {
      tag,
      typeLength: { type }
    } = element;
    switch (type) {
      case import_TlvCodec.TlvType.Null:
      case import_TlvCodec.TlvType.Boolean:
      case import_TlvCodec.TlvType.UnsignedInt:
      case import_TlvCodec.TlvType.SignedInt:
      case import_TlvCodec.TlvType.Float:
      case import_TlvCodec.TlvType.Utf8String:
      case import_TlvCodec.TlvType.ByteString:
        if (tag !== void 0 && !allowTag) {
          throw new import_general.UnexpectedDataError(`Tag detected for a native type: ${import_general.Diagnostic.json(element)}`);
        }
        return reader.readPrimitive(element.typeLength);
      case import_TlvCodec.TlvType.Array:
      case import_TlvCodec.TlvType.List:
        return this.decodeGenericArrayOrList(reader, type === import_TlvCodec.TlvType.List);
      case import_TlvCodec.TlvType.Structure:
        return this.decodeGenericStructure(reader);
      default:
        throw new import_general.UnexpectedDataError(`Unknown type: ${type}`);
    }
  }
  decodeGenericArrayOrList(reader, allowTag = false) {
    const result = new Array();
    while (true) {
      const element = reader.readTagType();
      const {
        tag,
        typeLength: { type }
      } = element;
      if (type === import_TlvCodec.TlvType.EndOfContainer) break;
      if (tag !== void 0 && !allowTag) {
        throw new import_general.UnexpectedDataError(`Tag detected : ${import_general.Diagnostic.json(element)}`);
      }
      result.push(this.decodeGenericElement(reader, element, allowTag));
    }
    return result;
  }
  decodeGenericStructure(reader) {
    const result = {};
    while (true) {
      const element = reader.readTagType();
      const {
        tag,
        typeLength: { type }
      } = element;
      if (type === import_TlvCodec.TlvType.EndOfContainer) break;
      if (tag === void 0 || tag.id === void 0) {
        throw new import_general.UnexpectedDataError(`Tag missing for a structure: ${import_general.Diagnostic.json(element)}`);
      }
      result[tag.id] = this.decodeGenericElement(reader, element, true);
    }
    return result;
  }
}
const TlvAny = new AnySchema();
//# sourceMappingURL=TlvAny.js.map
