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

namespace MyGame.Example
{

[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
public enum Any : byte
{
  NONE = 0,
  Monster = 1,
  TestSimpleTableWithEnum = 2,
  MyGame_Example2_Monster = 3,
};

public class AnyUnion {
  public Any Type { get; set; }
  public object Value { get; set; }

  public AnyUnion() {
    this.Type = Any.NONE;
    this.Value = null;
  }

  public T As<T>() where T : class { return this.Value as T; }
  public MyGame.Example.MonsterT AsMonster() { return this.As<MyGame.Example.MonsterT>(); }
  public static AnyUnion FromMonster(MyGame.Example.MonsterT _monster) { return new AnyUnion{ Type = Any.Monster, Value = _monster }; }
  internal MyGame.Example.TestSimpleTableWithEnumT AsTestSimpleTableWithEnum() { return this.As<MyGame.Example.TestSimpleTableWithEnumT>(); }
  internal static AnyUnion FromTestSimpleTableWithEnum(MyGame.Example.TestSimpleTableWithEnumT _testsimpletablewithenum) { return new AnyUnion{ Type = Any.TestSimpleTableWithEnum, Value = _testsimpletablewithenum }; }
  public MyGame.Example2.MonsterT AsMyGame_Example2_Monster() { return this.As<MyGame.Example2.MonsterT>(); }
  public static AnyUnion FromMyGame_Example2_Monster(MyGame.Example2.MonsterT _mygame_example2_monster) { return new AnyUnion{ Type = Any.MyGame_Example2_Monster, Value = _mygame_example2_monster }; }

  public static int Pack(Google.FlatBuffers.FlatBufferBuilder builder, AnyUnion _o) {
    switch (_o.Type) {
      default: return 0;
      case Any.Monster: return MyGame.Example.Monster.Pack(builder, _o.AsMonster()).Value;
      case Any.TestSimpleTableWithEnum: return MyGame.Example.TestSimpleTableWithEnum.Pack(builder, _o.AsTestSimpleTableWithEnum()).Value;
      case Any.MyGame_Example2_Monster: return MyGame.Example2.Monster.Pack(builder, _o.AsMyGame_Example2_Monster()).Value;
    }
  }
}

public class AnyUnion_JsonConverter : Newtonsoft.Json.JsonConverter {
  public override bool CanConvert(System.Type objectType) {
    return objectType == typeof(AnyUnion) || objectType == typeof(System.Collections.Generic.List<AnyUnion>);
  }
  public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) {
    var _olist = value as System.Collections.Generic.List<AnyUnion>;
    if (_olist != null) {
      writer.WriteStartArray();
      foreach (var _o in _olist) { this.WriteJson(writer, _o, serializer); }
      writer.WriteEndArray();
    } else {
      this.WriteJson(writer, value as AnyUnion, serializer);
    }
  }
  public void WriteJson(Newtonsoft.Json.JsonWriter writer, AnyUnion _o, Newtonsoft.Json.JsonSerializer serializer) {
    if (_o == null) return;
    serializer.Serialize(writer, _o.Value);
  }
  public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) {
    var _olist = existingValue as System.Collections.Generic.List<AnyUnion>;
    if (_olist != null) {
      for (var _j = 0; _j < _olist.Count; ++_j) {
        reader.Read();
        _olist[_j] = this.ReadJson(reader, _olist[_j], serializer);
      }
      reader.Read();
      return _olist;
    } else {
      return this.ReadJson(reader, existingValue as AnyUnion, serializer);
    }
  }
  public AnyUnion ReadJson(Newtonsoft.Json.JsonReader reader, AnyUnion _o, Newtonsoft.Json.JsonSerializer serializer) {
    if (_o == null) return null;
    switch (_o.Type) {
      default: break;
      case Any.Monster: _o.Value = serializer.Deserialize<MyGame.Example.MonsterT>(reader); break;
      case Any.TestSimpleTableWithEnum: _o.Value = serializer.Deserialize<MyGame.Example.TestSimpleTableWithEnumT>(reader); break;
      case Any.MyGame_Example2_Monster: _o.Value = serializer.Deserialize<MyGame.Example2.MonsterT>(reader); break;
    }
    return _o;
  }
}



static public class AnyVerify
{
  static public bool Verify(Google.FlatBuffers.Verifier verifier, byte typeId, uint tablePos)
  {
    bool result = true;
    switch((Any)typeId)
    {
      case Any.Monster:
        result = MyGame.Example.MonsterVerify.Verify(verifier, tablePos);
        break;
      case Any.TestSimpleTableWithEnum:
        result = MyGame.Example.TestSimpleTableWithEnumVerify.Verify(verifier, tablePos);
        break;
      case Any.MyGame_Example2_Monster:
        result = MyGame.Example2.MonsterVerify.Verify(verifier, tablePos);
        break;
      default: result = true;
        break;
    }
    return result;
  }
}


}
