/**
 * Autogenerated by Thrift Compiler (0.14.0)
 *
 * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
 *  @generated
 */
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Thrift;
using Thrift.Collections;
using System.ServiceModel;
using System.Runtime.Serialization;

using Thrift.Protocol;
using Thrift.Protocol.Entities;
using Thrift.Protocol.Utilities;
using Thrift.Transport;
using Thrift.Transport.Client;
using Thrift.Transport.Server;
using Thrift.Processor;


#pragma warning disable IDE0079  // remove unnecessary pragmas
#pragma warning disable IDE1006  // parts of the code use IDL spelling

namespace ThriftTest
{
  public abstract partial class SomeUnion : TUnionBase
  {
    public abstract global::System.Threading.Tasks.Task WriteAsync(TProtocol tProtocol, CancellationToken cancellationToken);
    public readonly int Isset;
    public abstract object Data { get; }
    protected SomeUnion(int isset)
    {
      Isset = isset;
    }

    public override bool Equals(object that)
    {
      if (!(that is SomeUnion other)) return false;
      if (ReferenceEquals(this, other)) return true;

      if(this.Isset != other.Isset) return false;

      switch (Isset)
      {
        case 1:
          return Equals(As_map_thing, other.As_map_thing);
        case 2:
          return Equals(As_string_thing, other.As_string_thing);
        case 3:
          return Equals(As_i32_thing, other.As_i32_thing);
        case 4:
          return Equals(As_xtruct_thing, other.As_xtruct_thing);
        case 5:
          return Equals(As_insanity_thing, other.As_insanity_thing);
        default:
          return true;
    }
  }

  public override int GetHashCode()
  {
    switch (Isset)
    {
      case 1:
        return As_map_thing.GetHashCode();
      case 2:
        return As_string_thing.GetHashCode();
      case 3:
        return As_i32_thing.GetHashCode();
      case 4:
        return As_xtruct_thing.GetHashCode();
      case 5:
        return As_insanity_thing.GetHashCode();
      default:
        return (new ___undefined()).GetHashCode();
    }
  }

  public SomeUnion DeepCopy()
  {
    switch (Isset)
    {
      case 1:
        return new map_thing(As_map_thing.DeepCopy());
      case 2:
        return new string_thing(As_string_thing);
      case 3:
        return new i32_thing(As_i32_thing);
      case 4:
        return new xtruct_thing(As_xtruct_thing.DeepCopy());
      case 5:
        return new insanity_thing(As_insanity_thing.DeepCopy());
      default:
        return new ___undefined();
    }
  }

  public class ___undefined : SomeUnion
  {
    public override object Data { get { return null; } }
    public ___undefined() : base(0) {}

    public new ___undefined DeepCopy()
    {
      return new ___undefined();
    }

    public override bool Equals(object that)
    {
      if (!(that is ___undefined other)) return false;
      if (ReferenceEquals(this, other)) return true;
      return true;
    }

    public override int GetHashCode() {
      int hashcode = 157;
      unchecked {
      }
      return hashcode;
    }

    public override global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)
    {
      throw new TProtocolException( TProtocolException.INVALID_DATA, "Cannot persist an union type which is not set.");
    }

  }

  public Dictionary<global::ThriftTest.Numberz, long> As_map_thing
  {
    get
    {
      return (1 == Isset) ? (Dictionary<global::ThriftTest.Numberz, long>)Data : default(Dictionary<global::ThriftTest.Numberz, long>);
    }
  }

  public class map_thing : SomeUnion
  {
    private Dictionary<global::ThriftTest.Numberz, long> _data;
    public override object Data { get { return _data; } }
    public map_thing(Dictionary<global::ThriftTest.Numberz, long> data) : base(1)
    {
      this._data = data;
    }
    public new map_thing DeepCopy()
    {
      return new map_thing(_data.DeepCopy());
    }

    public override bool Equals(object that)
    {
      if (!(that is SomeUnion other)) return false;
      if (ReferenceEquals(this, other)) return true;

      return Equals( _data, other.As_map_thing);
    }

    public override int GetHashCode()
    {
      return _data.GetHashCode();
    }

    public override async global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken) {
      oprot.IncrementRecursionDepth();
      try
      {
        var struc = new TStruct("SomeUnion");
        await oprot.WriteStructBeginAsync(struc, cancellationToken);
        var field = new TField();
        field.Name = "map_thing";
        field.Type = TType.Map;
        field.ID = 1;
        await oprot.WriteFieldBeginAsync(field, cancellationToken);
        {
          await oprot.WriteMapBeginAsync(new TMap(TType.I32, TType.I64, _data.Count), cancellationToken);
          foreach (global::ThriftTest.Numberz _iter58 in _data.Keys)
          {
            await oprot.WriteI32Async((int)_iter58, cancellationToken);
            await oprot.WriteI64Async(_data[_iter58], cancellationToken);
          }
          await oprot.WriteMapEndAsync(cancellationToken);
        }
        await oprot.WriteFieldEndAsync(cancellationToken);
        await oprot.WriteFieldStopAsync(cancellationToken);
        await oprot.WriteStructEndAsync(cancellationToken);
      }
      finally
      {
        oprot.DecrementRecursionDepth();
      }
    }
  }

  public string As_string_thing
  {
    get
    {
      return (2 == Isset) ? (string)Data : default(string);
    }
  }

  public class string_thing : SomeUnion
  {
    private string _data;
    public override object Data { get { return _data; } }
    public string_thing(string data) : base(2)
    {
      this._data = data;
    }
    public new string_thing DeepCopy()
    {
      return new string_thing(_data);
    }

    public override bool Equals(object that)
    {
      if (!(that is SomeUnion other)) return false;
      if (ReferenceEquals(this, other)) return true;

      return Equals( _data, other.As_string_thing);
    }

    public override int GetHashCode()
    {
      return _data.GetHashCode();
    }

    public override async global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken) {
      oprot.IncrementRecursionDepth();
      try
      {
        var struc = new TStruct("SomeUnion");
        await oprot.WriteStructBeginAsync(struc, cancellationToken);
        var field = new TField();
        field.Name = "string_thing";
        field.Type = TType.String;
        field.ID = 2;
        await oprot.WriteFieldBeginAsync(field, cancellationToken);
        await oprot.WriteStringAsync(_data, cancellationToken);
        await oprot.WriteFieldEndAsync(cancellationToken);
        await oprot.WriteFieldStopAsync(cancellationToken);
        await oprot.WriteStructEndAsync(cancellationToken);
      }
      finally
      {
        oprot.DecrementRecursionDepth();
      }
    }
  }

  public int As_i32_thing
  {
    get
    {
      return (3 == Isset) ? (int)Data : default(int);
    }
  }

  public class i32_thing : SomeUnion
  {
    private int _data;
    public override object Data { get { return _data; } }
    public i32_thing(int data) : base(3)
    {
      this._data = data;
    }
    public new i32_thing DeepCopy()
    {
      return new i32_thing(_data);
    }

    public override bool Equals(object that)
    {
      if (!(that is SomeUnion other)) return false;
      if (ReferenceEquals(this, other)) return true;

      return Equals( _data, other.As_i32_thing);
    }

    public override int GetHashCode()
    {
      return _data.GetHashCode();
    }

    public override async global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken) {
      oprot.IncrementRecursionDepth();
      try
      {
        var struc = new TStruct("SomeUnion");
        await oprot.WriteStructBeginAsync(struc, cancellationToken);
        var field = new TField();
        field.Name = "i32_thing";
        field.Type = TType.I32;
        field.ID = 3;
        await oprot.WriteFieldBeginAsync(field, cancellationToken);
        await oprot.WriteI32Async(_data, cancellationToken);
        await oprot.WriteFieldEndAsync(cancellationToken);
        await oprot.WriteFieldStopAsync(cancellationToken);
        await oprot.WriteStructEndAsync(cancellationToken);
      }
      finally
      {
        oprot.DecrementRecursionDepth();
      }
    }
  }

  public global::ThriftTest.Xtruct3 As_xtruct_thing
  {
    get
    {
      return (4 == Isset) ? (global::ThriftTest.Xtruct3)Data : default(global::ThriftTest.Xtruct3);
    }
  }

  public class xtruct_thing : SomeUnion
  {
    private global::ThriftTest.Xtruct3 _data;
    public override object Data { get { return _data; } }
    public xtruct_thing(global::ThriftTest.Xtruct3 data) : base(4)
    {
      this._data = data;
    }
    public new xtruct_thing DeepCopy()
    {
      return new xtruct_thing(_data.DeepCopy());
    }

    public override bool Equals(object that)
    {
      if (!(that is SomeUnion other)) return false;
      if (ReferenceEquals(this, other)) return true;

      return Equals( _data, other.As_xtruct_thing);
    }

    public override int GetHashCode()
    {
      return _data.GetHashCode();
    }

    public override async global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken) {
      oprot.IncrementRecursionDepth();
      try
      {
        var struc = new TStruct("SomeUnion");
        await oprot.WriteStructBeginAsync(struc, cancellationToken);
        var field = new TField();
        field.Name = "xtruct_thing";
        field.Type = TType.Struct;
        field.ID = 4;
        await oprot.WriteFieldBeginAsync(field, cancellationToken);
        await _data.WriteAsync(oprot, cancellationToken);
        await oprot.WriteFieldEndAsync(cancellationToken);
        await oprot.WriteFieldStopAsync(cancellationToken);
        await oprot.WriteStructEndAsync(cancellationToken);
      }
      finally
      {
        oprot.DecrementRecursionDepth();
      }
    }
  }

  public global::ThriftTest.Insanity As_insanity_thing
  {
    get
    {
      return (5 == Isset) ? (global::ThriftTest.Insanity)Data : default(global::ThriftTest.Insanity);
    }
  }

  public class insanity_thing : SomeUnion
  {
    private global::ThriftTest.Insanity _data;
    public override object Data { get { return _data; } }
    public insanity_thing(global::ThriftTest.Insanity data) : base(5)
    {
      this._data = data;
    }
    public new insanity_thing DeepCopy()
    {
      return new insanity_thing(_data.DeepCopy());
    }

    public override bool Equals(object that)
    {
      if (!(that is SomeUnion other)) return false;
      if (ReferenceEquals(this, other)) return true;

      return Equals( _data, other.As_insanity_thing);
    }

    public override int GetHashCode()
    {
      return _data.GetHashCode();
    }

    public override async global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken) {
      oprot.IncrementRecursionDepth();
      try
      {
        var struc = new TStruct("SomeUnion");
        await oprot.WriteStructBeginAsync(struc, cancellationToken);
        var field = new TField();
        field.Name = "insanity_thing";
        field.Type = TType.Struct;
        field.ID = 5;
        await oprot.WriteFieldBeginAsync(field, cancellationToken);
        await _data.WriteAsync(oprot, cancellationToken);
        await oprot.WriteFieldEndAsync(cancellationToken);
        await oprot.WriteFieldStopAsync(cancellationToken);
        await oprot.WriteStructEndAsync(cancellationToken);
      }
      finally
      {
        oprot.DecrementRecursionDepth();
      }
    }
  }

  public static async Task<SomeUnion> ReadAsync(TProtocol iprot, CancellationToken cancellationToken)
  {
    iprot.IncrementRecursionDepth();
    try
    {
      SomeUnion retval;
      await iprot.ReadStructBeginAsync(cancellationToken);
      TField field = await iprot.ReadFieldBeginAsync(cancellationToken);
      if (field.Type == TType.Stop)
      {
        await iprot.ReadFieldEndAsync(cancellationToken);
        retval = new ___undefined();
      }
      else
      {
        switch (field.ID)
        {
          case 1:
            if (field.Type == TType.Map) {
              Dictionary<global::ThriftTest.Numberz, long> temp;
              {
                TMap _map59 = await iprot.ReadMapBeginAsync(cancellationToken);
                temp = new Dictionary<global::ThriftTest.Numberz, long>(_map59.Count);
                for(int _i60 = 0; _i60 < _map59.Count; ++_i60)
                {
                  global::ThriftTest.Numberz _key61;
                  long _val62;
                  _key61 = (global::ThriftTest.Numberz)await iprot.ReadI32Async(cancellationToken);
                  _val62 = await iprot.ReadI64Async(cancellationToken);
                  temp[_key61] = _val62;
                }
                await iprot.ReadMapEndAsync(cancellationToken);
              }
              retval = new map_thing(temp);
            } else { 
             await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
              retval = new ___undefined();
            }
            break;
          case 2:
            if (field.Type == TType.String) {
              string temp;
              temp = await iprot.ReadStringAsync(cancellationToken);
              retval = new string_thing(temp);
            } else { 
             await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
              retval = new ___undefined();
            }
            break;
          case 3:
            if (field.Type == TType.I32) {
              int temp;
              temp = await iprot.ReadI32Async(cancellationToken);
              retval = new i32_thing(temp);
            } else { 
             await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
              retval = new ___undefined();
            }
            break;
          case 4:
            if (field.Type == TType.Struct) {
              global::ThriftTest.Xtruct3 temp;
              temp = new global::ThriftTest.Xtruct3();
              await temp.ReadAsync(iprot, cancellationToken);
              retval = new xtruct_thing(temp);
            } else { 
             await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
              retval = new ___undefined();
            }
            break;
          case 5:
            if (field.Type == TType.Struct) {
              global::ThriftTest.Insanity temp;
              temp = new global::ThriftTest.Insanity();
              await temp.ReadAsync(iprot, cancellationToken);
              retval = new insanity_thing(temp);
            } else { 
             await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
              retval = new ___undefined();
            }
            break;
          default: 
            await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
            retval = new ___undefined();
            break;
        }
        await iprot.ReadFieldEndAsync(cancellationToken);
        if ((await iprot.ReadFieldBeginAsync(cancellationToken)).Type != TType.Stop)
        {
          throw new TProtocolException(TProtocolException.INVALID_DATA);
        }
      }
      await iprot.ReadStructEndAsync(cancellationToken);
      return retval;
  }
  finally
  {
    iprot.DecrementRecursionDepth();
  }
  }

}

}
