/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { Bytes, capitalize, UnexpectedDataError } from "#general";
import { Schema } from "./Schema.js";
var BitRangeType = /* @__PURE__ */ ((BitRangeType2) => {
  BitRangeType2[BitRangeType2["Flag"] = 0] = "Flag";
  BitRangeType2[BitRangeType2["Number"] = 1] = "Number";
  BitRangeType2[BitRangeType2["Enum"] = 2] = "Enum";
  return BitRangeType2;
})(BitRangeType || {});
const BitRange = (type, offset, length) => ({ type, offset, length });
const BitFlag = (offset) => BitRange(0 /* Flag */, offset, 1);
const BitField = (offset, length) => BitRange(1 /* Number */, offset, length);
const BitFieldEnum = (offset, length) => BitRange(2 /* Enum */, offset, length);
class BitmapSchemaInternal extends Schema {
  constructor(bitSchemas) {
    super();
    this.bitSchemas = bitSchemas;
    const masks = {};
    for (const name in this.bitSchemas) {
      const { offset, length } = this.bitSchemas[name];
      masks[name] = (1 << length) - 1 << offset;
    }
    this.masks = masks;
  }
  masks;
  /**
   * Allow to use a fully defined Bitmap schema as input, but also allow one where only the entries of bits set are
   * provided, rest is unset.
   */
  encode(value) {
    return super.encode(value);
  }
  encodeInternal(value) {
    let result = 0;
    for (const name in this.bitSchemas) {
      const { type, offset } = this.bitSchemas[name];
      switch (type) {
        case 0 /* Flag */:
          if (value[name]) result |= this.masks[name];
          break;
        case 2 /* Enum */:
        case 1 /* Number */:
          result |= value[name] << offset;
      }
    }
    return result;
  }
  decodeInternal(bitmap) {
    const result = {};
    for (const name in this.bitSchemas) {
      const { type, offset } = this.bitSchemas[name];
      const mask = this.masks[name];
      if (type === 0 /* Flag */) {
        result[name] = (bitmap & mask) !== 0;
      } else {
        result[name] = (bitmap & mask) >> offset;
      }
    }
    return result;
  }
}
class ByteArrayBitmapSchemaInternal extends Schema {
  constructor(bitSchemas) {
    super();
    this.bitSchemas = bitSchemas;
    let maxBitLength = 0;
    const maskOffset = {};
    for (const name in this.bitSchemas) {
      const { type, offset, length } = this.bitSchemas[name];
      const bitOffset = offset % 8;
      const byteOffset = (offset - bitOffset) / 8;
      let mask;
      if (type === 0 /* Flag */) {
        mask = 1 << bitOffset;
      } else {
        mask = (1 << length) - 1;
      }
      maskOffset[name] = { bitOffset, byteOffset, mask };
      maxBitLength = Math.max(maxBitLength, offset + length);
    }
    this.byteArrayLength = Math.ceil(maxBitLength / 8);
    this.maskOffset = maskOffset;
  }
  byteArrayLength;
  maskOffset;
  encodeInternal(value) {
    const result = new Uint8Array(this.byteArrayLength);
    for (const name in this.bitSchemas) {
      const { type } = this.bitSchemas[name];
      let { bitOffset, byteOffset } = this.maskOffset[name];
      const { mask } = this.maskOffset[name];
      switch (type) {
        case 0 /* Flag */:
          if (value[name]) result[byteOffset] |= mask;
          break;
        case 2 /* Enum */:
        case 1 /* Number */: {
          let numValue = value[name] & mask;
          while (numValue !== 0) {
            result[byteOffset++] |= numValue << bitOffset & 255;
            const bitWritten = 8 - bitOffset;
            bitOffset = 0;
            numValue = numValue >> bitWritten;
          }
        }
      }
    }
    return result;
  }
  decodeInternal(data) {
    const bitmap = Bytes.of(data);
    if (bitmap.length !== this.byteArrayLength)
      throw new UnexpectedDataError(`Unexpected length: ${bitmap.length}. Expected ${this.byteArrayLength}`);
    const result = {};
    for (const name in this.bitSchemas) {
      const { type } = this.bitSchemas[name];
      let { mask, bitOffset, byteOffset } = this.maskOffset[name];
      if (type === 0 /* Flag */) {
        result[name] = (bitmap[byteOffset] & mask) !== 0;
      } else {
        let value = 0;
        let valueBitOffset = 0;
        while (mask !== 0) {
          value |= (bitmap[byteOffset++] >> bitOffset & mask) << valueBitOffset;
          const bitRead = 8 - bitOffset;
          bitOffset = 0;
          valueBitOffset += bitRead;
          mask = mask >> bitRead;
        }
        result[name] = value;
      }
    }
    return result;
  }
}
function BitFlags(bitSchemas, ...flags) {
  return Object.fromEntries(
    Object.keys(bitSchemas).map((name) => [
      name,
      !(flags.indexOf(capitalize(name)) === -1)
    ])
  );
}
function BitsFromPartial(schema, bits) {
  const result = {};
  for (const k in schema) {
    const value = bits[k];
    if (value !== void 0) {
      result[k] = value;
    } else {
      result[k] = 0;
    }
  }
  return result;
}
const BitmapSchema = (bitSchemas) => new BitmapSchemaInternal(bitSchemas);
const ByteArrayBitmapSchema = (bitSchemas) => new ByteArrayBitmapSchemaInternal(bitSchemas);
export {
  BitField,
  BitFieldEnum,
  BitFlag,
  BitFlags,
  BitmapSchema,
  BitmapSchemaInternal,
  BitsFromPartial,
  ByteArrayBitmapSchema,
  ByteArrayBitmapSchemaInternal
};
//# sourceMappingURL=BitmapSchema.js.map
