// <auto-generated>
//  automatically generated by the FlatBuffers compiler, do not modify
// </auto-generated>

namespace NamespaceA
{

using global::System;
using global::System.Collections.Generic;
using global::Google.FlatBuffers;

public struct TableInFirstNS : IFlatbufferObject
{
  private Table __p;
  public ByteBuffer ByteBuffer { get { return __p.bb; } }
  public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_24_3_7(); }
  public static TableInFirstNS GetRootAsTableInFirstNS(ByteBuffer _bb) { return GetRootAsTableInFirstNS(_bb, new TableInFirstNS()); }
  public static TableInFirstNS GetRootAsTableInFirstNS(ByteBuffer _bb, TableInFirstNS obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
  public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
  public TableInFirstNS __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }

  public NamespaceA.NamespaceB.TableInNestedNS? FooTable { get { int o = __p.__offset(4); return o != 0 ? (NamespaceA.NamespaceB.TableInNestedNS?)(new NamespaceA.NamespaceB.TableInNestedNS()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
  public NamespaceA.NamespaceB.EnumInNestedNS FooEnum { get { int o = __p.__offset(6); return o != 0 ? (NamespaceA.NamespaceB.EnumInNestedNS)__p.bb.GetSbyte(o + __p.bb_pos) : NamespaceA.NamespaceB.EnumInNestedNS.A; } }
  public bool MutateFooEnum(NamespaceA.NamespaceB.EnumInNestedNS foo_enum) { int o = __p.__offset(6); if (o != 0) { __p.bb.PutSbyte(o + __p.bb_pos, (sbyte)foo_enum); return true; } else { return false; } }
  public NamespaceA.NamespaceB.UnionInNestedNS FooUnionType { get { int o = __p.__offset(8); return o != 0 ? (NamespaceA.NamespaceB.UnionInNestedNS)__p.bb.Get(o + __p.bb_pos) : NamespaceA.NamespaceB.UnionInNestedNS.NONE; } }
  public TTable? FooUnion<TTable>() where TTable : struct, IFlatbufferObject { int o = __p.__offset(10); return o != 0 ? (TTable?)__p.__union<TTable>(o + __p.bb_pos) : null; }
  public NamespaceA.NamespaceB.TableInNestedNS FooUnionAsTableInNestedNS() { return FooUnion<NamespaceA.NamespaceB.TableInNestedNS>().Value; }
  public NamespaceA.NamespaceB.StructInNestedNS? FooStruct { get { int o = __p.__offset(12); return o != 0 ? (NamespaceA.NamespaceB.StructInNestedNS?)(new NamespaceA.NamespaceB.StructInNestedNS()).__assign(o + __p.bb_pos, __p.bb) : null; } }

  public static Offset<NamespaceA.TableInFirstNS> CreateTableInFirstNS(FlatBufferBuilder builder,
      Offset<NamespaceA.NamespaceB.TableInNestedNS> foo_tableOffset = default(Offset<NamespaceA.NamespaceB.TableInNestedNS>),
      NamespaceA.NamespaceB.EnumInNestedNS foo_enum = NamespaceA.NamespaceB.EnumInNestedNS.A,
      NamespaceA.NamespaceB.UnionInNestedNS foo_union_type = NamespaceA.NamespaceB.UnionInNestedNS.NONE,
      int foo_unionOffset = 0,
      NamespaceA.NamespaceB.StructInNestedNST foo_struct = null) {
    builder.StartTable(5);
    TableInFirstNS.AddFooStruct(builder, NamespaceA.NamespaceB.StructInNestedNS.Pack(builder, foo_struct));
    TableInFirstNS.AddFooUnion(builder, foo_unionOffset);
    TableInFirstNS.AddFooTable(builder, foo_tableOffset);
    TableInFirstNS.AddFooUnionType(builder, foo_union_type);
    TableInFirstNS.AddFooEnum(builder, foo_enum);
    return TableInFirstNS.EndTableInFirstNS(builder);
  }

  public static void StartTableInFirstNS(FlatBufferBuilder builder) { builder.StartTable(5); }
  public static void AddFooTable(FlatBufferBuilder builder, Offset<NamespaceA.NamespaceB.TableInNestedNS> fooTableOffset) { builder.AddOffset(0, fooTableOffset.Value, 0); }
  public static void AddFooEnum(FlatBufferBuilder builder, NamespaceA.NamespaceB.EnumInNestedNS fooEnum) { builder.AddSbyte(1, (sbyte)fooEnum, 0); }
  public static void AddFooUnionType(FlatBufferBuilder builder, NamespaceA.NamespaceB.UnionInNestedNS fooUnionType) { builder.AddByte(2, (byte)fooUnionType, 0); }
  public static void AddFooUnion(FlatBufferBuilder builder, int fooUnionOffset) { builder.AddOffset(3, fooUnionOffset, 0); }
  public static void AddFooStruct(FlatBufferBuilder builder, Offset<NamespaceA.NamespaceB.StructInNestedNS> fooStructOffset) { builder.AddStruct(4, fooStructOffset.Value, 0); }
  public static Offset<NamespaceA.TableInFirstNS> EndTableInFirstNS(FlatBufferBuilder builder) {
    int o = builder.EndTable();
    return new Offset<NamespaceA.TableInFirstNS>(o);
  }
  public TableInFirstNST UnPack() {
    var _o = new TableInFirstNST();
    this.UnPackTo(_o);
    return _o;
  }
  public void UnPackTo(TableInFirstNST _o) {
    _o.FooTable = this.FooTable.HasValue ? this.FooTable.Value.UnPack() : null;
    _o.FooEnum = this.FooEnum;
    _o.FooUnion = new NamespaceA.NamespaceB.UnionInNestedNSUnion();
    _o.FooUnion.Type = this.FooUnionType;
    switch (this.FooUnionType) {
      default: break;
      case NamespaceA.NamespaceB.UnionInNestedNS.TableInNestedNS:
        _o.FooUnion.Value = this.FooUnion<NamespaceA.NamespaceB.TableInNestedNS>().HasValue ? this.FooUnion<NamespaceA.NamespaceB.TableInNestedNS>().Value.UnPack() : null;
        break;
    }
    _o.FooStruct = this.FooStruct.HasValue ? this.FooStruct.Value.UnPack() : null;
  }
  public static Offset<NamespaceA.TableInFirstNS> Pack(FlatBufferBuilder builder, TableInFirstNST _o) {
    if (_o == null) return default(Offset<NamespaceA.TableInFirstNS>);
    var _foo_table = _o.FooTable == null ? default(Offset<NamespaceA.NamespaceB.TableInNestedNS>) : NamespaceA.NamespaceB.TableInNestedNS.Pack(builder, _o.FooTable);
    var _foo_union_type = _o.FooUnion == null ? NamespaceA.NamespaceB.UnionInNestedNS.NONE : _o.FooUnion.Type;
    var _foo_union = _o.FooUnion == null ? 0 : NamespaceA.NamespaceB.UnionInNestedNSUnion.Pack(builder, _o.FooUnion);
    return CreateTableInFirstNS(
      builder,
      _foo_table,
      _o.FooEnum,
      _foo_union_type,
      _foo_union,
      _o.FooStruct);
  }
}

public class TableInFirstNST
{
  [Newtonsoft.Json.JsonProperty("foo_table")]
  public NamespaceA.NamespaceB.TableInNestedNST FooTable { get; set; }
  [Newtonsoft.Json.JsonProperty("foo_enum")]
  public NamespaceA.NamespaceB.EnumInNestedNS FooEnum { get; set; }
  [Newtonsoft.Json.JsonProperty("foo_union_type")]
  private NamespaceA.NamespaceB.UnionInNestedNS FooUnionType {
    get {
      return this.FooUnion != null ? this.FooUnion.Type : NamespaceA.NamespaceB.UnionInNestedNS.NONE;
    }
    set {
      this.FooUnion = new NamespaceA.NamespaceB.UnionInNestedNSUnion();
      this.FooUnion.Type = value;
    }
  }
  [Newtonsoft.Json.JsonProperty("foo_union")]
  [Newtonsoft.Json.JsonConverter(typeof(NamespaceA.NamespaceB.UnionInNestedNSUnion_JsonConverter))]
  public NamespaceA.NamespaceB.UnionInNestedNSUnion FooUnion { get; set; }
  [Newtonsoft.Json.JsonProperty("foo_struct")]
  public NamespaceA.NamespaceB.StructInNestedNST FooStruct { get; set; }

  public TableInFirstNST() {
    this.FooTable = null;
    this.FooEnum = NamespaceA.NamespaceB.EnumInNestedNS.A;
    this.FooUnion = null;
    this.FooStruct = new NamespaceA.NamespaceB.StructInNestedNST();
  }
}


static public class TableInFirstNSVerify
{
  static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos)
  {
    return verifier.VerifyTableStart(tablePos)
      && verifier.VerifyTable(tablePos, 4 /*FooTable*/, NamespaceA.NamespaceB.TableInNestedNSVerify.Verify, false)
      && verifier.VerifyField(tablePos, 6 /*FooEnum*/, 1 /*NamespaceA.NamespaceB.EnumInNestedNS*/, 1, false)
      && verifier.VerifyField(tablePos, 8 /*FooUnionType*/, 1 /*NamespaceA.NamespaceB.UnionInNestedNS*/, 1, false)
      && verifier.VerifyUnion(tablePos, 8, 10 /*FooUnion*/, NamespaceA.NamespaceB.UnionInNestedNSVerify.Verify, false)
      && verifier.VerifyField(tablePos, 12 /*FooStruct*/, 8 /*NamespaceA.NamespaceB.StructInNestedNS*/, 4, false)
      && verifier.VerifyTableEnd(tablePos);
  }
}

}
