/**
 * 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
{

  [DataContract(Namespace="")]
  public partial class CrazyNesting : TBase
  {
    private string _string_field;
    private THashSet<global::ThriftTest.Insanity> _set_field;
    private byte[] _binary_field;

    [DataMember(Order = 0)]
    public string String_field
    {
      get
      {
        return _string_field;
      }
      set
      {
        __isset.string_field = true;
        this._string_field = value;
      }
    }

    [DataMember(Order = 0)]
    public THashSet<global::ThriftTest.Insanity> Set_field
    {
      get
      {
        return _set_field;
      }
      set
      {
        __isset.set_field = true;
        this._set_field = value;
      }
    }

    [DataMember(Order = 0)]
    public List<Dictionary<THashSet<int>, Dictionary<int, THashSet<List<Dictionary<global::ThriftTest.Insanity, string>>>>>> List_field { get; set; }

    [DataMember(Order = 0)]
    public byte[] Binary_field
    {
      get
      {
        return _binary_field;
      }
      set
      {
        __isset.binary_field = true;
        this._binary_field = value;
      }
    }


    [DataMember(Order = 1)]
    public Isset __isset;
    [DataContract]
    public struct Isset
    {
      [DataMember]
      public bool string_field;
      [DataMember]
      public bool set_field;
      [DataMember]
      public bool binary_field;
    }

    #region XmlSerializer support

    public bool ShouldSerializeString_field()
    {
      return __isset.string_field;
    }

    public bool ShouldSerializeSet_field()
    {
      return __isset.set_field;
    }

    public bool ShouldSerializeBinary_field()
    {
      return __isset.binary_field;
    }

    #endregion XmlSerializer support

    public CrazyNesting()
    {
    }

    public CrazyNesting(List<Dictionary<THashSet<int>, Dictionary<int, THashSet<List<Dictionary<global::ThriftTest.Insanity, string>>>>>> list_field) : this()
    {
      this.List_field = list_field;
    }

    public CrazyNesting DeepCopy()
    {
      var tmp21 = new CrazyNesting();
      if((String_field != null) && __isset.string_field)
      {
        tmp21.String_field = this.String_field;
      }
      tmp21.__isset.string_field = this.__isset.string_field;
      if((Set_field != null) && __isset.set_field)
      {
        tmp21.Set_field = this.Set_field.DeepCopy();
      }
      tmp21.__isset.set_field = this.__isset.set_field;
      if((List_field != null))
      {
        tmp21.List_field = this.List_field.DeepCopy();
      }
      if((Binary_field != null) && __isset.binary_field)
      {
        tmp21.Binary_field = this.Binary_field.ToArray();
      }
      tmp21.__isset.binary_field = this.__isset.binary_field;
      return tmp21;
    }

    public async global::System.Threading.Tasks.Task ReadAsync(TProtocol iprot, CancellationToken cancellationToken)
    {
      iprot.IncrementRecursionDepth();
      try
      {
        bool isset_list_field = false;
        TField field;
        await iprot.ReadStructBeginAsync(cancellationToken);
        while (true)
        {
          field = await iprot.ReadFieldBeginAsync(cancellationToken);
          if (field.Type == TType.Stop)
          {
            break;
          }

          switch (field.ID)
          {
            case 1:
              if (field.Type == TType.String)
              {
                String_field = await iprot.ReadStringAsync(cancellationToken);
              }
              else
              {
                await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
              }
              break;
            case 2:
              if (field.Type == TType.Set)
              {
                {
                  TSet _set22 = await iprot.ReadSetBeginAsync(cancellationToken);
                  Set_field = new THashSet<global::ThriftTest.Insanity>(_set22.Count);
                  for(int _i23 = 0; _i23 < _set22.Count; ++_i23)
                  {
                    global::ThriftTest.Insanity _elem24;
                    _elem24 = new global::ThriftTest.Insanity();
                    await _elem24.ReadAsync(iprot, cancellationToken);
                    Set_field.Add(_elem24);
                  }
                  await iprot.ReadSetEndAsync(cancellationToken);
                }
              }
              else
              {
                await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
              }
              break;
            case 3:
              if (field.Type == TType.List)
              {
                {
                  TList _list25 = await iprot.ReadListBeginAsync(cancellationToken);
                  List_field = new List<Dictionary<THashSet<int>, Dictionary<int, THashSet<List<Dictionary<global::ThriftTest.Insanity, string>>>>>>(_list25.Count);
                  for(int _i26 = 0; _i26 < _list25.Count; ++_i26)
                  {
                    Dictionary<THashSet<int>, Dictionary<int, THashSet<List<Dictionary<global::ThriftTest.Insanity, string>>>>> _elem27;
                    {
                      TMap _map28 = await iprot.ReadMapBeginAsync(cancellationToken);
                      _elem27 = new Dictionary<THashSet<int>, Dictionary<int, THashSet<List<Dictionary<global::ThriftTest.Insanity, string>>>>>(_map28.Count);
                      for(int _i29 = 0; _i29 < _map28.Count; ++_i29)
                      {
                        THashSet<int> _key30;
                        Dictionary<int, THashSet<List<Dictionary<global::ThriftTest.Insanity, string>>>> _val31;
                        {
                          TSet _set32 = await iprot.ReadSetBeginAsync(cancellationToken);
                          _key30 = new THashSet<int>(_set32.Count);
                          for(int _i33 = 0; _i33 < _set32.Count; ++_i33)
                          {
                            int _elem34;
                            _elem34 = await iprot.ReadI32Async(cancellationToken);
                            _key30.Add(_elem34);
                          }
                          await iprot.ReadSetEndAsync(cancellationToken);
                        }
                        {
                          TMap _map35 = await iprot.ReadMapBeginAsync(cancellationToken);
                          _val31 = new Dictionary<int, THashSet<List<Dictionary<global::ThriftTest.Insanity, string>>>>(_map35.Count);
                          for(int _i36 = 0; _i36 < _map35.Count; ++_i36)
                          {
                            int _key37;
                            THashSet<List<Dictionary<global::ThriftTest.Insanity, string>>> _val38;
                            _key37 = await iprot.ReadI32Async(cancellationToken);
                            {
                              TSet _set39 = await iprot.ReadSetBeginAsync(cancellationToken);
                              _val38 = new THashSet<List<Dictionary<global::ThriftTest.Insanity, string>>>(_set39.Count);
                              for(int _i40 = 0; _i40 < _set39.Count; ++_i40)
                              {
                                List<Dictionary<global::ThriftTest.Insanity, string>> _elem41;
                                {
                                  TList _list42 = await iprot.ReadListBeginAsync(cancellationToken);
                                  _elem41 = new List<Dictionary<global::ThriftTest.Insanity, string>>(_list42.Count);
                                  for(int _i43 = 0; _i43 < _list42.Count; ++_i43)
                                  {
                                    Dictionary<global::ThriftTest.Insanity, string> _elem44;
                                    {
                                      TMap _map45 = await iprot.ReadMapBeginAsync(cancellationToken);
                                      _elem44 = new Dictionary<global::ThriftTest.Insanity, string>(_map45.Count);
                                      for(int _i46 = 0; _i46 < _map45.Count; ++_i46)
                                      {
                                        global::ThriftTest.Insanity _key47;
                                        string _val48;
                                        _key47 = new global::ThriftTest.Insanity();
                                        await _key47.ReadAsync(iprot, cancellationToken);
                                        _val48 = await iprot.ReadStringAsync(cancellationToken);
                                        _elem44[_key47] = _val48;
                                      }
                                      await iprot.ReadMapEndAsync(cancellationToken);
                                    }
                                    _elem41.Add(_elem44);
                                  }
                                  await iprot.ReadListEndAsync(cancellationToken);
                                }
                                _val38.Add(_elem41);
                              }
                              await iprot.ReadSetEndAsync(cancellationToken);
                            }
                            _val31[_key37] = _val38;
                          }
                          await iprot.ReadMapEndAsync(cancellationToken);
                        }
                        _elem27[_key30] = _val31;
                      }
                      await iprot.ReadMapEndAsync(cancellationToken);
                    }
                    List_field.Add(_elem27);
                  }
                  await iprot.ReadListEndAsync(cancellationToken);
                }
                isset_list_field = true;
              }
              else
              {
                await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
              }
              break;
            case 4:
              if (field.Type == TType.String)
              {
                Binary_field = await iprot.ReadBinaryAsync(cancellationToken);
              }
              else
              {
                await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
              }
              break;
            default: 
              await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
              break;
          }

          await iprot.ReadFieldEndAsync(cancellationToken);
        }

        await iprot.ReadStructEndAsync(cancellationToken);
        if (!isset_list_field)
        {
          throw new TProtocolException(TProtocolException.INVALID_DATA);
        }
      }
      finally
      {
        iprot.DecrementRecursionDepth();
      }
    }

    public async global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)
    {
      oprot.IncrementRecursionDepth();
      try
      {
        var struc = new TStruct("CrazyNesting");
        await oprot.WriteStructBeginAsync(struc, cancellationToken);
        var field = new TField();
        if((String_field != null) && __isset.string_field)
        {
          field.Name = "string_field";
          field.Type = TType.String;
          field.ID = 1;
          await oprot.WriteFieldBeginAsync(field, cancellationToken);
          await oprot.WriteStringAsync(String_field, cancellationToken);
          await oprot.WriteFieldEndAsync(cancellationToken);
        }
        if((Set_field != null) && __isset.set_field)
        {
          field.Name = "set_field";
          field.Type = TType.Set;
          field.ID = 2;
          await oprot.WriteFieldBeginAsync(field, cancellationToken);
          {
            await oprot.WriteSetBeginAsync(new TSet(TType.Struct, Set_field.Count), cancellationToken);
            foreach (global::ThriftTest.Insanity _iter49 in Set_field)
            {
              await _iter49.WriteAsync(oprot, cancellationToken);
            }
            await oprot.WriteSetEndAsync(cancellationToken);
          }
          await oprot.WriteFieldEndAsync(cancellationToken);
        }
        if((List_field != null))
        {
          field.Name = "list_field";
          field.Type = TType.List;
          field.ID = 3;
          await oprot.WriteFieldBeginAsync(field, cancellationToken);
          {
            await oprot.WriteListBeginAsync(new TList(TType.Map, List_field.Count), cancellationToken);
            foreach (Dictionary<THashSet<int>, Dictionary<int, THashSet<List<Dictionary<global::ThriftTest.Insanity, string>>>>> _iter50 in List_field)
            {
              {
                await oprot.WriteMapBeginAsync(new TMap(TType.Set, TType.Map, _iter50.Count), cancellationToken);
                foreach (THashSet<int> _iter51 in _iter50.Keys)
                {
                  {
                    await oprot.WriteSetBeginAsync(new TSet(TType.I32, _iter51.Count), cancellationToken);
                    foreach (int _iter52 in _iter51)
                    {
                      await oprot.WriteI32Async(_iter52, cancellationToken);
                    }
                    await oprot.WriteSetEndAsync(cancellationToken);
                  }
                  {
                    await oprot.WriteMapBeginAsync(new TMap(TType.I32, TType.Set, _iter50[_iter51].Count), cancellationToken);
                    foreach (int _iter53 in _iter50[_iter51].Keys)
                    {
                      await oprot.WriteI32Async(_iter53, cancellationToken);
                      {
                        await oprot.WriteSetBeginAsync(new TSet(TType.List, _iter50[_iter51][_iter53].Count), cancellationToken);
                        foreach (List<Dictionary<global::ThriftTest.Insanity, string>> _iter54 in _iter50[_iter51][_iter53])
                        {
                          {
                            await oprot.WriteListBeginAsync(new TList(TType.Map, _iter54.Count), cancellationToken);
                            foreach (Dictionary<global::ThriftTest.Insanity, string> _iter55 in _iter54)
                            {
                              {
                                await oprot.WriteMapBeginAsync(new TMap(TType.Struct, TType.String, _iter55.Count), cancellationToken);
                                foreach (global::ThriftTest.Insanity _iter56 in _iter55.Keys)
                                {
                                  await _iter56.WriteAsync(oprot, cancellationToken);
                                  await oprot.WriteStringAsync(_iter55[_iter56], cancellationToken);
                                }
                                await oprot.WriteMapEndAsync(cancellationToken);
                              }
                            }
                            await oprot.WriteListEndAsync(cancellationToken);
                          }
                        }
                        await oprot.WriteSetEndAsync(cancellationToken);
                      }
                    }
                    await oprot.WriteMapEndAsync(cancellationToken);
                  }
                }
                await oprot.WriteMapEndAsync(cancellationToken);
              }
            }
            await oprot.WriteListEndAsync(cancellationToken);
          }
          await oprot.WriteFieldEndAsync(cancellationToken);
        }
        if((Binary_field != null) && __isset.binary_field)
        {
          field.Name = "binary_field";
          field.Type = TType.String;
          field.ID = 4;
          await oprot.WriteFieldBeginAsync(field, cancellationToken);
          await oprot.WriteBinaryAsync(Binary_field, cancellationToken);
          await oprot.WriteFieldEndAsync(cancellationToken);
        }
        await oprot.WriteFieldStopAsync(cancellationToken);
        await oprot.WriteStructEndAsync(cancellationToken);
      }
      finally
      {
        oprot.DecrementRecursionDepth();
      }
    }

    public override bool Equals(object that)
    {
      if (!(that is CrazyNesting other)) return false;
      if (ReferenceEquals(this, other)) return true;
      return ((__isset.string_field == other.__isset.string_field) && ((!__isset.string_field) || (System.Object.Equals(String_field, other.String_field))))
        && ((__isset.set_field == other.__isset.set_field) && ((!__isset.set_field) || (TCollections.Equals(Set_field, other.Set_field))))
        && TCollections.Equals(List_field, other.List_field)
        && ((__isset.binary_field == other.__isset.binary_field) && ((!__isset.binary_field) || (TCollections.Equals(Binary_field, other.Binary_field))));
    }

    public override int GetHashCode() {
      int hashcode = 157;
      unchecked {
        if((String_field != null) && __isset.string_field)
        {
          hashcode = (hashcode * 397) + String_field.GetHashCode();
        }
        if((Set_field != null) && __isset.set_field)
        {
          hashcode = (hashcode * 397) + TCollections.GetHashCode(Set_field);
        }
        if((List_field != null))
        {
          hashcode = (hashcode * 397) + TCollections.GetHashCode(List_field);
        }
        if((Binary_field != null) && __isset.binary_field)
        {
          hashcode = (hashcode * 397) + Binary_field.GetHashCode();
        }
      }
      return hashcode;
    }

    public override string ToString()
    {
      var sb = new StringBuilder("CrazyNesting(");
      int tmp57 = 0;
      if((String_field != null) && __isset.string_field)
      {
        if(0 < tmp57++) { sb.Append(", "); }
        sb.Append("String_field: ");
        String_field.ToString(sb);
      }
      if((Set_field != null) && __isset.set_field)
      {
        if(0 < tmp57++) { sb.Append(", "); }
        sb.Append("Set_field: ");
        Set_field.ToString(sb);
      }
      if((List_field != null))
      {
        if(0 < tmp57) { sb.Append(", "); }
        sb.Append("List_field: ");
        List_field.ToString(sb);
      }
      if((Binary_field != null) && __isset.binary_field)
      {
        sb.Append(", Binary_field: ");
        Binary_field.ToString(sb);
      }
      sb.Append(')');
      return sb.ToString();
    }
  }

}
