/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { deepCopy, serialize, UnexpectedDataError } from "@matter/general";
import {
  ValidationDatatypeMismatchError,
  ValidationError,
  ValidationOutOfBoundsError
} from "../common/ValidationError.js";
import { TlvType } from "./TlvCodec.js";
import { TlvSchema } from "./TlvSchema.js";
class ArraySchema extends TlvSchema {
  constructor(elementSchema, minLength = 0, maxLength = 65535) {
    super();
    this.elementSchema = elementSchema;
    this.minLength = minLength;
    this.maxLength = maxLength;
  }
  encodeTlvInternal(writer, value, tag, options) {
    writer.writeTag({ type: TlvType.Array }, tag);
    value.forEach((element) => this.elementSchema.encodeTlvInternal(writer, element, void 0, options));
    writer.writeTag({ type: TlvType.EndOfContainer });
  }
  decodeTlvInternalValue(reader, typeLength) {
    if (typeLength.type !== TlvType.Array)
      throw new UnexpectedDataError(`Unexpected type ${typeLength.type}, expected Array (${TlvType.Array}).`);
    const result = new Array();
    while (true) {
      const { tag: elementTag, typeLength: elementTypeLength } = reader.readTagType();
      if (elementTag !== void 0) throw new UnexpectedDataError("Array element tags should be anonymous.");
      if (elementTypeLength.type === TlvType.EndOfContainer) break;
      result.push(this.elementSchema.decodeTlvInternalValue(reader, elementTypeLength));
    }
    return result;
  }
  injectField(value, fieldId, fieldValue, injectChecker) {
    if (Array.isArray(value)) {
      value.forEach(
        (item, index) => value[index] = this.elementSchema.injectField(item, fieldId, fieldValue, injectChecker)
      );
    }
    return value;
  }
  removeField(value, fieldId, removeChecker) {
    if (Array.isArray(value)) {
      value.forEach(
        (item, index) => value[index] = this.elementSchema.removeField(item, fieldId, removeChecker)
      );
    }
    return value;
  }
  validate(data) {
    if (!Array.isArray(data)) throw new ValidationDatatypeMismatchError(`Expected array, got ${typeof data}.`);
    if (data.length > this.maxLength)
      throw new ValidationOutOfBoundsError(
        `Array ${serialize(data)} is too long: ${data.length}, max ${this.maxLength}.`
      );
    if (data.length < this.minLength)
      throw new ValidationOutOfBoundsError(
        `Array ${serialize(data)} is too short: ${data.length}, min ${this.minLength}.`
      );
    data.forEach((element, index) => {
      try {
        this.elementSchema.validate(element);
      } catch (e) {
        ValidationError.accept(e);
        e.fieldName = `[${index}]${e.fieldName !== void 0 ? `.${e.fieldName}` : ""}`;
        throw e;
      }
    });
  }
  decodeFromChunkedArray(chunks, currentValue) {
    if (currentValue === void 0 && chunks[0].listIndex !== void 0) {
      throw new UnexpectedDataError(
        `When no current value is supplied the first chunked element needs to have a list index of undefined, but received ${chunks[0].listIndex}.`
      );
    }
    currentValue = currentValue !== void 0 ? deepCopy(currentValue) : [];
    for (const { listIndex, element } of chunks) {
      if (listIndex === void 0) {
        currentValue = this.decodeTlv(element);
      } else if (listIndex === null) {
        const decodedElement = this.elementSchema.decodeTlv(element);
        currentValue.push(decodedElement);
      } else if (element[0].typeLength.type === TlvType.Null) {
        currentValue.splice(listIndex, 1);
      } else {
        currentValue[listIndex] = this.elementSchema.decodeTlv(element);
      }
    }
    return currentValue;
  }
  encodeAsChunkedArray(value, options) {
    const result = [];
    result.push({ listIndex: void 0, element: this.encodeTlv([], options) });
    value.forEach((element) => {
      const elementStream = this.elementSchema.encodeTlv(element, options);
      result.push({ listIndex: null, element: elementStream });
    });
    return result;
  }
}
const TlvArray = (elementSchema, { minLength, maxLength, length } = {}) => new ArraySchema(elementSchema, length ?? minLength, length ?? maxLength);
export {
  ArraySchema,
  TlvArray
};
//# sourceMappingURL=TlvArray.js.map
