// automatically generated by the FlatBuffers compiler, do not modify

/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */

import * as flatbuffers from 'flatbuffers';

import {Enum, EnumT} from '../reflection/enum.js';
import {Object_, Object_T} from '../reflection/object.js';
import {SchemaFile, SchemaFileT} from '../reflection/schema-file.js';
import {Service, ServiceT} from '../reflection/service.js';

export class Schema implements flatbuffers.IUnpackableObject<SchemaT> {
  bb: flatbuffers.ByteBuffer | null = null;
  bb_pos = 0;
  __init(i: number, bb: flatbuffers.ByteBuffer): Schema {
    this.bb_pos = i;
    this.bb = bb;
    return this;
  }

  static getRootAsSchema(bb: flatbuffers.ByteBuffer, obj?: Schema): Schema {
    return (obj || new Schema()).__init(
      bb.readInt32(bb.position()) + bb.position(),
      bb,
    );
  }

  static getSizePrefixedRootAsSchema(
    bb: flatbuffers.ByteBuffer,
    obj?: Schema,
  ): Schema {
    bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
    return (obj || new Schema()).__init(
      bb.readInt32(bb.position()) + bb.position(),
      bb,
    );
  }

  static bufferHasIdentifier(bb: flatbuffers.ByteBuffer): boolean {
    return bb.__has_identifier('BFBS');
  }

  objects(index: number, obj?: Object_): Object_ | null {
    const offset = this.bb!.__offset(this.bb_pos, 4);
    return offset
      ? (obj || new Object_()).__init(
          this.bb!.__indirect(
            this.bb!.__vector(this.bb_pos + offset) + index * 4,
          ),
          this.bb!,
        )
      : null;
  }

  objectsLength(): number {
    const offset = this.bb!.__offset(this.bb_pos, 4);
    return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
  }

  enums(index: number, obj?: Enum): Enum | null {
    const offset = this.bb!.__offset(this.bb_pos, 6);
    return offset
      ? (obj || new Enum()).__init(
          this.bb!.__indirect(
            this.bb!.__vector(this.bb_pos + offset) + index * 4,
          ),
          this.bb!,
        )
      : null;
  }

  enumsLength(): number {
    const offset = this.bb!.__offset(this.bb_pos, 6);
    return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
  }

  fileIdent(): string | null;
  fileIdent(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null;
  fileIdent(optionalEncoding?: any): string | Uint8Array | null {
    const offset = this.bb!.__offset(this.bb_pos, 8);
    return offset
      ? this.bb!.__string(this.bb_pos + offset, optionalEncoding)
      : null;
  }

  fileExt(): string | null;
  fileExt(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null;
  fileExt(optionalEncoding?: any): string | Uint8Array | null {
    const offset = this.bb!.__offset(this.bb_pos, 10);
    return offset
      ? this.bb!.__string(this.bb_pos + offset, optionalEncoding)
      : null;
  }

  rootTable(obj?: Object_): Object_ | null {
    const offset = this.bb!.__offset(this.bb_pos, 12);
    return offset
      ? (obj || new Object_()).__init(
          this.bb!.__indirect(this.bb_pos + offset),
          this.bb!,
        )
      : null;
  }

  services(index: number, obj?: Service): Service | null {
    const offset = this.bb!.__offset(this.bb_pos, 14);
    return offset
      ? (obj || new Service()).__init(
          this.bb!.__indirect(
            this.bb!.__vector(this.bb_pos + offset) + index * 4,
          ),
          this.bb!,
        )
      : null;
  }

  servicesLength(): number {
    const offset = this.bb!.__offset(this.bb_pos, 14);
    return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
  }

  advancedFeatures(): bigint {
    const offset = this.bb!.__offset(this.bb_pos, 16);
    return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
  }

  mutate_advanced_features(value: bigint): boolean {
    const offset = this.bb!.__offset(this.bb_pos, 16);

    if (offset === 0) {
      return false;
    }

    this.bb!.writeUint64(this.bb_pos + offset, value);
    return true;
  }

  /**
   * All the files used in this compilation. Files are relative to where
   * flatc was invoked.
   */
  fbsFiles(index: number, obj?: SchemaFile): SchemaFile | null {
    const offset = this.bb!.__offset(this.bb_pos, 18);
    return offset
      ? (obj || new SchemaFile()).__init(
          this.bb!.__indirect(
            this.bb!.__vector(this.bb_pos + offset) + index * 4,
          ),
          this.bb!,
        )
      : null;
  }

  fbsFilesLength(): number {
    const offset = this.bb!.__offset(this.bb_pos, 18);
    return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
  }

  static getFullyQualifiedName(): string {
    return 'reflection.Schema';
  }

  static startSchema(builder: flatbuffers.Builder) {
    builder.startObject(8);
  }

  static addObjects(
    builder: flatbuffers.Builder,
    objectsOffset: flatbuffers.Offset,
  ) {
    builder.addFieldOffset(0, objectsOffset, 0);
  }

  static createObjectsVector(
    builder: flatbuffers.Builder,
    data: flatbuffers.Offset[],
  ): flatbuffers.Offset {
    builder.startVector(4, data.length, 4);
    for (let i = data.length - 1; i >= 0; i--) {
      builder.addOffset(data[i]!);
    }
    return builder.endVector();
  }

  static startObjectsVector(builder: flatbuffers.Builder, numElems: number) {
    builder.startVector(4, numElems, 4);
  }

  static addEnums(
    builder: flatbuffers.Builder,
    enumsOffset: flatbuffers.Offset,
  ) {
    builder.addFieldOffset(1, enumsOffset, 0);
  }

  static createEnumsVector(
    builder: flatbuffers.Builder,
    data: flatbuffers.Offset[],
  ): flatbuffers.Offset {
    builder.startVector(4, data.length, 4);
    for (let i = data.length - 1; i >= 0; i--) {
      builder.addOffset(data[i]!);
    }
    return builder.endVector();
  }

  static startEnumsVector(builder: flatbuffers.Builder, numElems: number) {
    builder.startVector(4, numElems, 4);
  }

  static addFileIdent(
    builder: flatbuffers.Builder,
    fileIdentOffset: flatbuffers.Offset,
  ) {
    builder.addFieldOffset(2, fileIdentOffset, 0);
  }

  static addFileExt(
    builder: flatbuffers.Builder,
    fileExtOffset: flatbuffers.Offset,
  ) {
    builder.addFieldOffset(3, fileExtOffset, 0);
  }

  static addRootTable(
    builder: flatbuffers.Builder,
    rootTableOffset: flatbuffers.Offset,
  ) {
    builder.addFieldOffset(4, rootTableOffset, 0);
  }

  static addServices(
    builder: flatbuffers.Builder,
    servicesOffset: flatbuffers.Offset,
  ) {
    builder.addFieldOffset(5, servicesOffset, 0);
  }

  static createServicesVector(
    builder: flatbuffers.Builder,
    data: flatbuffers.Offset[],
  ): flatbuffers.Offset {
    builder.startVector(4, data.length, 4);
    for (let i = data.length - 1; i >= 0; i--) {
      builder.addOffset(data[i]!);
    }
    return builder.endVector();
  }

  static startServicesVector(builder: flatbuffers.Builder, numElems: number) {
    builder.startVector(4, numElems, 4);
  }

  static addAdvancedFeatures(
    builder: flatbuffers.Builder,
    advancedFeatures: bigint,
  ) {
    builder.addFieldInt64(6, advancedFeatures, BigInt('0'));
  }

  static addFbsFiles(
    builder: flatbuffers.Builder,
    fbsFilesOffset: flatbuffers.Offset,
  ) {
    builder.addFieldOffset(7, fbsFilesOffset, 0);
  }

  static createFbsFilesVector(
    builder: flatbuffers.Builder,
    data: flatbuffers.Offset[],
  ): flatbuffers.Offset {
    builder.startVector(4, data.length, 4);
    for (let i = data.length - 1; i >= 0; i--) {
      builder.addOffset(data[i]!);
    }
    return builder.endVector();
  }

  static startFbsFilesVector(builder: flatbuffers.Builder, numElems: number) {
    builder.startVector(4, numElems, 4);
  }

  static endSchema(builder: flatbuffers.Builder): flatbuffers.Offset {
    const offset = builder.endObject();
    builder.requiredField(offset, 4); // objects
    builder.requiredField(offset, 6); // enums
    return offset;
  }

  static finishSchemaBuffer(
    builder: flatbuffers.Builder,
    offset: flatbuffers.Offset,
  ) {
    builder.finish(offset, 'BFBS');
  }

  static finishSizePrefixedSchemaBuffer(
    builder: flatbuffers.Builder,
    offset: flatbuffers.Offset,
  ) {
    builder.finish(offset, 'BFBS', true);
  }

  unpack(): SchemaT {
    return new SchemaT(
      this.bb!.createObjList<Object_, Object_T>(
        this.objects.bind(this),
        this.objectsLength(),
      ),
      this.bb!.createObjList<Enum, EnumT>(
        this.enums.bind(this),
        this.enumsLength(),
      ),
      this.fileIdent(),
      this.fileExt(),
      this.rootTable() !== null ? this.rootTable()!.unpack() : null,
      this.bb!.createObjList<Service, ServiceT>(
        this.services.bind(this),
        this.servicesLength(),
      ),
      this.advancedFeatures(),
      this.bb!.createObjList<SchemaFile, SchemaFileT>(
        this.fbsFiles.bind(this),
        this.fbsFilesLength(),
      ),
    );
  }

  unpackTo(_o: SchemaT): void {
    _o.objects = this.bb!.createObjList<Object_, Object_T>(
      this.objects.bind(this),
      this.objectsLength(),
    );
    _o.enums = this.bb!.createObjList<Enum, EnumT>(
      this.enums.bind(this),
      this.enumsLength(),
    );
    _o.fileIdent = this.fileIdent();
    _o.fileExt = this.fileExt();
    _o.rootTable =
      this.rootTable() !== null ? this.rootTable()!.unpack() : null;
    _o.services = this.bb!.createObjList<Service, ServiceT>(
      this.services.bind(this),
      this.servicesLength(),
    );
    _o.advancedFeatures = this.advancedFeatures();
    _o.fbsFiles = this.bb!.createObjList<SchemaFile, SchemaFileT>(
      this.fbsFiles.bind(this),
      this.fbsFilesLength(),
    );
  }
}

export class SchemaT implements flatbuffers.IGeneratedObject {
  constructor(
    public objects: Object_T[] = [],
    public enums: EnumT[] = [],
    public fileIdent: string | Uint8Array | null = null,
    public fileExt: string | Uint8Array | null = null,
    public rootTable: Object_T | null = null,
    public services: ServiceT[] = [],
    public advancedFeatures: bigint = BigInt('0'),
    public fbsFiles: SchemaFileT[] = [],
  ) {}

  pack(builder: flatbuffers.Builder): flatbuffers.Offset {
    const objects = Schema.createObjectsVector(
      builder,
      builder.createObjectOffsetList(this.objects),
    );
    const enums = Schema.createEnumsVector(
      builder,
      builder.createObjectOffsetList(this.enums),
    );
    const fileIdent =
      this.fileIdent !== null ? builder.createString(this.fileIdent!) : 0;
    const fileExt =
      this.fileExt !== null ? builder.createString(this.fileExt!) : 0;
    const rootTable =
      this.rootTable !== null ? this.rootTable!.pack(builder) : 0;
    const services = Schema.createServicesVector(
      builder,
      builder.createObjectOffsetList(this.services),
    );
    const fbsFiles = Schema.createFbsFilesVector(
      builder,
      builder.createObjectOffsetList(this.fbsFiles),
    );

    Schema.startSchema(builder);
    Schema.addObjects(builder, objects);
    Schema.addEnums(builder, enums);
    Schema.addFileIdent(builder, fileIdent);
    Schema.addFileExt(builder, fileExt);
    Schema.addRootTable(builder, rootTable);
    Schema.addServices(builder, services);
    Schema.addAdvancedFeatures(builder, this.advancedFeatures);
    Schema.addFbsFiles(builder, fbsFiles);

    return Schema.endSchema(builder);
  }
}
