/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { Aspect } from "./Aspect.js";
var AccessLevel = /* @__PURE__ */ ((AccessLevel2) => {
  AccessLevel2[AccessLevel2["View"] = 1] = "View";
  AccessLevel2[AccessLevel2["ProxyView"] = 2] = "ProxyView";
  AccessLevel2[AccessLevel2["Operate"] = 3] = "Operate";
  AccessLevel2[AccessLevel2["Manage"] = 4] = "Manage";
  AccessLevel2[AccessLevel2["Administer"] = 5] = "Administer";
  return AccessLevel2;
})(AccessLevel || {});
class Access extends Aspect {
  rw;
  readPriv;
  writePriv;
  fabric;
  timed;
  get readable() {
    return !this.rw || this.rw !== Access.Rw.Write;
  }
  get writable() {
    return !!this.rw && this.rw !== Access.Rw.Read;
  }
  get fabricScoped() {
    return this.fabric === Access.Fabric.Scoped;
  }
  get fabricSensitive() {
    return this.fabric === Access.Fabric.Sensitive;
  }
  /**
   * Determine whether this access is fully specified.  This means we know whether reads and/or writes are allowed and
   * if so the required access levels.
   */
  get complete() {
    return this.rw !== void 0 && (!this.readable || this.readPriv !== void 0) && (!this.writable || this.writePriv !== void 0);
  }
  /**
   * Initialize from an Access.Definition or the access control DSL defined by the Matter Specification.
   */
  constructor(definition) {
    super(definition);
    if (Array.isArray(definition)) {
      definition = translateFlags(definition.flat());
    } else if (typeof definition === "string") {
      definition = translateFlags(Array.from(Access.parse(this, definition)));
    }
    this.rw = definition?.rw;
    this.readPriv = definition?.readPriv;
    this.writePriv = definition?.writePriv;
    this.fabric = definition?.fabric;
    this.timed = definition?.timed;
    this.isEmpty = (!this.rw || this.rw === Access.Rw.Read) && !this.fabric && !this.readPriv && !this.writePriv && !this.timed;
    this.freeze();
  }
  extend(other) {
    if (other.isEmpty) {
      return this;
    }
    if (this.isEmpty) {
      return other;
    }
    return new Access({
      rw: other.rw ?? this.rw,
      readPriv: other.readPriv ?? this.readPriv,
      writePriv: other.writePriv ?? this.writePriv,
      fabric: other.fabric ?? this.fabric,
      timed: other.timed ?? this.timed
    });
  }
  /**
   * Parses standard Matter access syntax into an AccessFlag set.  Extremely lenient.
   */
  static parse(access, definition) {
    definition = definition.toUpperCase();
    if (definition === "DERIVED") {
      return [];
    }
    const flags = [];
    for (let i = 0; i < definition.length; i++) {
      switch (definition[i]) {
        case "R":
          flags.push(Access.Rw.Read);
          break;
        case "U":
          flags.push(Access.Fabric.Unaware);
          break;
        case "F":
          flags.push(Access.Fabric.Scoped);
          break;
        case "S":
          flags.push(Access.Fabric.Sensitive);
          break;
        case "V":
          flags.push(Access.Privilege.View);
          break;
        case "O":
          flags.push(Access.Privilege.Operate);
          break;
        case "M":
          flags.push(Access.Privilege.Manage);
          break;
        case "A":
          flags.push(Access.Privilege.Administer);
          break;
        case "T":
          flags.push(Access.Timed.Required);
          break;
        case "W":
          flags.push(Access.Rw.Write);
          break;
        case "[":
          if (i < definition.length - 2 && definition[i + 1] === "W" && definition[i + 2] === "]") {
            flags.push(Access.Rw.ReadWriteOption);
            i += 2;
          }
          break;
        case "*":
          if (i < definition.length - 1 && definition[i + 1] === "W") {
            flags.push(Access.Rw.ReadWriteOption);
            i++;
          }
          break;
        case " ":
        case "	":
        case "\n":
        case "\r":
        case "\f":
        case "\v":
          break;
        default:
          access.error("UNKNOWN_ACCESS_FLAG", `Unknown flag "${definition[i]}"`);
          i++;
          break;
      }
    }
    return flags;
  }
  /**
   * Displays access using the standard Matter syntax.
   */
  toString() {
    const parts = [];
    if (this.rw !== void 0) {
      parts.push(this.rw);
    }
    if (this.fabric !== void 0) {
      parts.push(this.fabric);
    }
    if (this.readPriv === this.writePriv) {
      if (this.readPriv !== void 0) {
        parts.push(this.readPriv);
      }
    } else if (this.readPriv) {
      if (this.writePriv) {
        parts.push(`${this.readPriv}${this.writePriv}`);
      } else {
        parts.push(this.readPriv);
      }
    } else if (this.writePriv) {
      parts.push(this.writePriv);
    }
    if (this.timed) {
      parts.push(Access.Timed.Required);
    }
    return parts.join(" ");
  }
}
function translateFlags(input) {
  const output = {};
  input.forEach((f) => {
    switch (f) {
      case Access.Rw.Read:
        if (!output.rw) {
          output.rw = f;
        }
        break;
      case Access.Rw.Write:
        if (!output.rw) {
          output.rw = f;
        } else if (output.rw === Access.Rw.Read) {
          output.rw = Access.Rw.ReadWrite;
        }
        break;
      case Access.Rw.ReadWrite:
        if (output.rw !== Access.Rw.ReadWriteOption) {
          output.rw = f;
        }
        break;
      case Access.Rw.ReadWriteOption:
        output.rw = f;
        break;
      case Access.Fabric.Unaware:
        output.fabric = Access.Fabric.Unaware;
        break;
      case Access.Fabric.Scoped:
        if (output.fabric !== Access.Fabric.Sensitive) {
          output.fabric = f;
        }
        break;
      case Access.Fabric.Sensitive:
        output.fabric = f;
        break;
      case Access.Privilege.View:
        output.readPriv = f;
        break;
      case Access.Privilege.Operate:
      case Access.Privilege.Manage:
      case Access.Privilege.Administer:
        if (!output.readPriv || Access.PrivilegeLevel[f] < Access.PrivilegeLevel[output.readPriv]) {
          output.readPriv = f;
        }
        if (!output.writePriv || Access.PrivilegeLevel[f] > Access.PrivilegeLevel[output.writePriv]) {
          output.writePriv = f;
        }
        break;
      case Access.Timed.Required:
        output.timed = true;
        break;
    }
  });
  return output;
}
((Access2) => {
  let Rw;
  ((Rw2) => {
    Rw2["Read"] = "R";
    Rw2["Write"] = "W";
    Rw2["ReadWrite"] = "RW";
    Rw2["ReadWriteOption"] = "R[W]";
  })(Rw = Access2.Rw || (Access2.Rw = {}));
  let Fabric;
  ((Fabric2) => {
    Fabric2["Unaware"] = "U";
    Fabric2["Scoped"] = "F";
    Fabric2["Sensitive"] = "S";
  })(Fabric = Access2.Fabric || (Access2.Fabric = {}));
  let Privilege;
  ((Privilege2) => {
    Privilege2["View"] = "V";
    Privilege2["Operate"] = "O";
    Privilege2["Manage"] = "M";
    Privilege2["Administer"] = "A";
  })(Privilege = Access2.Privilege || (Access2.Privilege = {}));
  let PrivilegeName;
  ((PrivilegeName2) => {
    PrivilegeName2["V"] = "View";
    PrivilegeName2["O"] = "Operate";
    PrivilegeName2["M"] = "Manage";
    PrivilegeName2["A"] = "Administer";
  })(PrivilegeName = Access2.PrivilegeName || (Access2.PrivilegeName = {}));
  Access2.PrivilegeLevel = {
    V: 1 /* View */,
    O: 3 /* Operate */,
    M: 4 /* Manage */,
    A: 5 /* Administer */
  };
  let Timed;
  ((Timed2) => {
    Timed2["Required"] = "T";
  })(Timed = Access2.Timed || (Access2.Timed = {}));
  Access2.R = "R" /* Read */;
  Access2.W = "W" /* Write */;
  Access2.RW = "RW" /* ReadWrite */;
  Access2.RWo = "R[W]" /* ReadWriteOption */;
  Access2.U = "U" /* Unaware */;
  Access2.F = "F" /* Scoped */;
  Access2.S = "S" /* Sensitive */;
  Access2.V = "V" /* View */;
  Access2.O = ["O" /* Operate */];
  Access2.M = ["M" /* Manage */];
  Access2.A = ["A" /* Administer */];
  Access2.VO = ["V" /* View */, "O" /* Operate */];
  Access2.VM = ["V" /* View */, "M" /* Manage */];
  Access2.VA = ["V" /* View */, "A" /* Administer */];
  Access2.OM = ["O" /* Operate */, "M" /* Manage */];
  Access2.OA = ["O" /* Operate */, "A" /* Administer */];
  Access2.MA = ["M" /* Manage */, "A" /* Administer */];
  Access2.T = "T" /* Required */;
})(Access || (Access = {}));
((Access2) => {
  Access2.Default = new Access2({
    rw: Access2.RW,
    readPriv: "V" /* View */,
    writePriv: "O" /* Operate */
  });
})(Access || (Access = {}));
export {
  Access,
  AccessLevel
};
//# sourceMappingURL=Access.js.map
