/**
 * 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 Thrift5320.Task
{
  public partial class Task
  {
    [ServiceContract(Namespace="")]
    public interface IAsync
    {
      [OperationContract]
      [FaultContract(typeof(global::Thrift5320.exceptions.TaskFault))]
      global::System.Threading.Tasks.Task<global::Thrift5320.enums.Task> TaskAsync(global::Thrift5320.structs.Task foo, global::Thrift5320.Task.Foobar bar, CancellationToken cancellationToken = default);

    }


    public class Client : TBaseClient, IDisposable, IAsync
    {
      public Client(TProtocol protocol) : this(protocol, protocol)
      {
      }

      public Client(TProtocol inputProtocol, TProtocol outputProtocol) : base(inputProtocol, outputProtocol)      {
      }
      public async global::System.Threading.Tasks.Task<global::Thrift5320.enums.Task> TaskAsync(global::Thrift5320.structs.Task foo, global::Thrift5320.Task.Foobar bar, CancellationToken cancellationToken = default)
      {
        await OutputProtocol.WriteMessageBeginAsync(new TMessage("Task", TMessageType.Call, SeqId), cancellationToken);
        
        var args = new InternalStructs.TaskArgs() {
          Foo = foo,
          Bar = bar,
        };
        
        await args.WriteAsync(OutputProtocol, cancellationToken);
        await OutputProtocol.WriteMessageEndAsync(cancellationToken);
        await OutputProtocol.Transport.FlushAsync(cancellationToken);
        
        var msg = await InputProtocol.ReadMessageBeginAsync(cancellationToken);
        if (msg.Type == TMessageType.Exception)
        {
          var x = await TApplicationException.ReadAsync(InputProtocol, cancellationToken);
          await InputProtocol.ReadMessageEndAsync(cancellationToken);
          throw x;
        }

        var result = new InternalStructs.TaskResult();
        await result.ReadAsync(InputProtocol, cancellationToken);
        await InputProtocol.ReadMessageEndAsync(cancellationToken);
        if (result.__isset.success)
        {
          return result.Success;
        }
        if (result.__isset.error)
        {
          throw result.Error;
        }
        throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, "Task failed: unknown result");
      }

    }

    public class AsyncProcessor : ITAsyncProcessor
    {
      private readonly IAsync _iAsync;
      private readonly ILogger<AsyncProcessor> _logger;

      public AsyncProcessor(IAsync iAsync, ILogger<AsyncProcessor> logger = default)
      {
        _iAsync = iAsync ?? throw new ArgumentNullException(nameof(iAsync));
        _logger = logger;
        processMap_["Task"] = Task_ProcessAsync;
      }

      protected delegate global::System.Threading.Tasks.Task ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken);
      protected Dictionary<string, ProcessFunction> processMap_ = new Dictionary<string, ProcessFunction>();

      public async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot)
      {
        return await ProcessAsync(iprot, oprot, CancellationToken.None);
      }

      public async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)
      {
        try
        {
          var msg = await iprot.ReadMessageBeginAsync(cancellationToken);

          processMap_.TryGetValue(msg.Name, out ProcessFunction fn);

          if (fn == null)
          {
            await TProtocolUtil.SkipAsync(iprot, TType.Struct, cancellationToken);
            await iprot.ReadMessageEndAsync(cancellationToken);
            var x = new TApplicationException (TApplicationException.ExceptionType.UnknownMethod, "Invalid method name: '" + msg.Name + "'");
            await oprot.WriteMessageBeginAsync(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID), cancellationToken);
            await x.WriteAsync(oprot, cancellationToken);
            await oprot.WriteMessageEndAsync(cancellationToken);
            await oprot.Transport.FlushAsync(cancellationToken);
            return true;
          }

          await fn(msg.SeqID, iprot, oprot, cancellationToken);

        }
        catch (IOException)
        {
          return false;
        }

        return true;
      }

      public async global::System.Threading.Tasks.Task Task_ProcessAsync(int seqid, TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)
      {
        var args = new InternalStructs.TaskArgs();
        await args.ReadAsync(iprot, cancellationToken);
        await iprot.ReadMessageEndAsync(cancellationToken);
        var result = new InternalStructs.TaskResult();
        try
        {
          try
          {
            result.Success = await _iAsync.TaskAsync(args.Foo, args.Bar, cancellationToken);
          }
          catch (global::Thrift5320.exceptions.Task error)
          {
            result.Error = error;
          }
          await oprot.WriteMessageBeginAsync(new TMessage("Task", TMessageType.Reply, seqid), cancellationToken); 
          await result.WriteAsync(oprot, cancellationToken);
        }
        catch (TTransportException)
        {
          throw;
        }
        catch (Exception ex)
        {
          var sErr = $"Error occurred in {GetType().FullName}: {ex.Message}";
          if(_logger != null)
            _logger.LogError(ex, sErr);
          else
            Console.Error.WriteLine(sErr);
          var x = new TApplicationException(TApplicationException.ExceptionType.InternalError," Internal error.");
          await oprot.WriteMessageBeginAsync(new TMessage("Task", TMessageType.Exception, seqid), cancellationToken);
          await x.WriteAsync(oprot, cancellationToken);
        }
        await oprot.WriteMessageEndAsync(cancellationToken);
        await oprot.Transport.FlushAsync(cancellationToken);
      }

    }

    public class InternalStructs
    {

      [DataContract(Namespace="")]
      public partial class TaskArgs : TBase
      {
        private global::Thrift5320.structs.Task _foo;
        private global::Thrift5320.Task.Foobar _bar;

        [DataMember(Order = 0)]
        public global::Thrift5320.structs.Task Foo
        {
          get
          {
            return _foo;
          }
          set
          {
            __isset.foo = true;
            this._foo = value;
          }
        }

        /// <summary>
        /// 
        /// <seealso cref="global::Thrift5320.Task.Foobar"/>
        /// </summary>
        [DataMember(Order = 0)]
        public global::Thrift5320.Task.Foobar Bar
        {
          get
          {
            return _bar;
          }
          set
          {
            __isset.bar = true;
            this._bar = value;
          }
        }


        [DataMember(Order = 1)]
        public Isset __isset;
        [DataContract]
        public struct Isset
        {
          [DataMember]
          public bool foo;
          [DataMember]
          public bool bar;
        }

        #region XmlSerializer support

        public bool ShouldSerializeFoo()
        {
          return __isset.foo;
        }

        public bool ShouldSerializeBar()
        {
          return __isset.bar;
        }

        #endregion XmlSerializer support

        public TaskArgs()
        {
        }

        public TaskArgs DeepCopy()
        {
          var tmp0 = new TaskArgs();
          if((Foo != null) && __isset.foo)
          {
            tmp0.Foo = (global::Thrift5320.structs.Task)this.Foo.DeepCopy();
          }
          tmp0.__isset.foo = this.__isset.foo;
          if(__isset.bar)
          {
            tmp0.Bar = this.Bar;
          }
          tmp0.__isset.bar = this.__isset.bar;
          return tmp0;
        }

        public async global::System.Threading.Tasks.Task ReadAsync(TProtocol iprot, CancellationToken cancellationToken)
        {
          iprot.IncrementRecursionDepth();
          try
          {
            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.Struct)
                  {
                    Foo = new global::Thrift5320.structs.Task();
                    await Foo.ReadAsync(iprot, cancellationToken);
                  }
                  else
                  {
                    await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
                  }
                  break;
                case 2:
                  if (field.Type == TType.I32)
                  {
                    Bar = (global::Thrift5320.Task.Foobar)await iprot.ReadI32Async(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);
          }
          finally
          {
            iprot.DecrementRecursionDepth();
          }
        }

        public async global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)
        {
          oprot.IncrementRecursionDepth();
          try
          {
            var struc = new TStruct("Task_args");
            await oprot.WriteStructBeginAsync(struc, cancellationToken);
            var field = new TField();
            if((Foo != null) && __isset.foo)
            {
              field.Name = "foo";
              field.Type = TType.Struct;
              field.ID = 1;
              await oprot.WriteFieldBeginAsync(field, cancellationToken);
              await Foo.WriteAsync(oprot, cancellationToken);
              await oprot.WriteFieldEndAsync(cancellationToken);
            }
            if(__isset.bar)
            {
              field.Name = "bar";
              field.Type = TType.I32;
              field.ID = 2;
              await oprot.WriteFieldBeginAsync(field, cancellationToken);
              await oprot.WriteI32Async((int)Bar, 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 TaskArgs other)) return false;
          if (ReferenceEquals(this, other)) return true;
          return ((__isset.foo == other.__isset.foo) && ((!__isset.foo) || (System.Object.Equals(Foo, other.Foo))))
            && ((__isset.bar == other.__isset.bar) && ((!__isset.bar) || (System.Object.Equals(Bar, other.Bar))));
        }

        public override int GetHashCode() {
          int hashcode = 157;
          unchecked {
            if((Foo != null) && __isset.foo)
            {
              hashcode = (hashcode * 397) + Foo.GetHashCode();
            }
            if(__isset.bar)
            {
              hashcode = (hashcode * 397) + Bar.GetHashCode();
            }
          }
          return hashcode;
        }

        public override string ToString()
        {
          var sb = new StringBuilder("Task_args(");
          int tmp1 = 0;
          if((Foo != null) && __isset.foo)
          {
            if(0 < tmp1++) { sb.Append(", "); }
            sb.Append("Foo: ");
            Foo.ToString(sb);
          }
          if(__isset.bar)
          {
            if(0 < tmp1++) { sb.Append(", "); }
            sb.Append("Bar: ");
            Bar.ToString(sb);
          }
          sb.Append(')');
          return sb.ToString();
        }
      }


      [DataContract(Namespace="")]
      public partial class TaskResult : TBase
      {
        private global::Thrift5320.enums.Task _success;
        private global::Thrift5320.exceptions.Task _error;

        /// <summary>
        /// 
        /// <seealso cref="global::Thrift5320.enums.Task"/>
        /// </summary>
        [DataMember(Order = 0)]
        public global::Thrift5320.enums.Task Success
        {
          get
          {
            return _success;
          }
          set
          {
            __isset.success = true;
            this._success = value;
          }
        }

        [DataMember(Order = 0)]
        public global::Thrift5320.exceptions.Task Error
        {
          get
          {
            return _error;
          }
          set
          {
            __isset.error = true;
            this._error = value;
          }
        }


        [DataMember(Order = 1)]
        public Isset __isset;
        [DataContract]
        public struct Isset
        {
          [DataMember]
          public bool success;
          [DataMember]
          public bool error;
        }

        #region XmlSerializer support

        public bool ShouldSerializeSuccess()
        {
          return __isset.success;
        }

        public bool ShouldSerializeError()
        {
          return __isset.error;
        }

        #endregion XmlSerializer support

        public TaskResult()
        {
        }

        public TaskResult DeepCopy()
        {
          var tmp2 = new TaskResult();
          if(__isset.success)
          {
            tmp2.Success = this.Success;
          }
          tmp2.__isset.success = this.__isset.success;
          if((Error != null) && __isset.error)
          {
            tmp2.Error = (global::Thrift5320.exceptions.Task)this.Error.DeepCopy();
          }
          tmp2.__isset.error = this.__isset.error;
          return tmp2;
        }

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

              switch (field.ID)
              {
                case 0:
                  if (field.Type == TType.I32)
                  {
                    Success = (global::Thrift5320.enums.Task)await iprot.ReadI32Async(cancellationToken);
                  }
                  else
                  {
                    await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);
                  }
                  break;
                case 1:
                  if (field.Type == TType.Struct)
                  {
                    Error = new global::Thrift5320.exceptions.Task();
                    await Error.ReadAsync(iprot, 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);
          }
          finally
          {
            iprot.DecrementRecursionDepth();
          }
        }

        public async global::System.Threading.Tasks.Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)
        {
          oprot.IncrementRecursionDepth();
          try
          {
            var struc = new TStruct("Task_result");
            await oprot.WriteStructBeginAsync(struc, cancellationToken);
            var field = new TField();

            if(this.__isset.success)
            {
              field.Name = "Success";
              field.Type = TType.I32;
              field.ID = 0;
              await oprot.WriteFieldBeginAsync(field, cancellationToken);
              await oprot.WriteI32Async((int)Success, cancellationToken);
              await oprot.WriteFieldEndAsync(cancellationToken);
            }
            else if(this.__isset.error)
            {
              if (Error != null)
              {
                field.Name = "Error";
                field.Type = TType.Struct;
                field.ID = 1;
                await oprot.WriteFieldBeginAsync(field, cancellationToken);
                await Error.WriteAsync(oprot, 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 TaskResult other)) return false;
          if (ReferenceEquals(this, other)) return true;
          return ((__isset.success == other.__isset.success) && ((!__isset.success) || (System.Object.Equals(Success, other.Success))))
            && ((__isset.error == other.__isset.error) && ((!__isset.error) || (System.Object.Equals(Error, other.Error))));
        }

        public override int GetHashCode() {
          int hashcode = 157;
          unchecked {
            if(__isset.success)
            {
              hashcode = (hashcode * 397) + Success.GetHashCode();
            }
            if((Error != null) && __isset.error)
            {
              hashcode = (hashcode * 397) + Error.GetHashCode();
            }
          }
          return hashcode;
        }

        public override string ToString()
        {
          var sb = new StringBuilder("Task_result(");
          int tmp3 = 0;
          if(__isset.success)
          {
            if(0 < tmp3++) { sb.Append(", "); }
            sb.Append("Success: ");
            Success.ToString(sb);
          }
          if((Error != null) && __isset.error)
          {
            if(0 < tmp3++) { sb.Append(", "); }
            sb.Append("Error: ");
            Error.ToString(sb);
          }
          sb.Append(')');
          return sb.ToString();
        }
      }

    }

  }
}
