/**
 * 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 partial class SecondService
{
  [ServiceContract(Namespace="")]
  public interface IAsync
  {
    /// <summary>
    /// Prints 'testString("%s")' with thing as '%s'
    /// @param string thing - the string to print
    /// @return string - returns the string 'thing'
    /// </summary>
    /// <param name="thing"></param>
    [OperationContract]
    global::System.Threading.Tasks.Task<string> secondtestStringAsync(string thing, 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<string> secondtestStringAsync(string thing, CancellationToken cancellationToken = default)
    {
      await OutputProtocol.WriteMessageBeginAsync(new TMessage("secondtestString", TMessageType.Call, SeqId), cancellationToken);
      
      var args = new InternalStructs.secondtestStringArgs() {
        Thing = thing,
      };
      
      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.secondtestStringResult();
      await result.ReadAsync(InputProtocol, cancellationToken);
      await InputProtocol.ReadMessageEndAsync(cancellationToken);
      if (result.__isset.success)
      {
        return result.Success;
      }
      throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, "secondtestString 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_["secondtestString"] = secondtestString_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 secondtestString_ProcessAsync(int seqid, TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)
    {
      var args = new InternalStructs.secondtestStringArgs();
      await args.ReadAsync(iprot, cancellationToken);
      await iprot.ReadMessageEndAsync(cancellationToken);
      var result = new InternalStructs.secondtestStringResult();
      try
      {
        result.Success = await _iAsync.secondtestStringAsync(args.Thing, cancellationToken);
        await oprot.WriteMessageBeginAsync(new TMessage("secondtestString", 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("secondtestString", 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 secondtestStringArgs : TBase
    {
      private string _thing;

      [DataMember(Order = 0)]
      public string Thing
      {
        get
        {
          return _thing;
        }
        set
        {
          __isset.thing = true;
          this._thing = value;
        }
      }


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

      #region XmlSerializer support

      public bool ShouldSerializeThing()
      {
        return __isset.thing;
      }

      #endregion XmlSerializer support

      public secondtestStringArgs()
      {
      }

      public secondtestStringArgs DeepCopy()
      {
        var tmp352 = new secondtestStringArgs();
        if((Thing != null) && __isset.thing)
        {
          tmp352.Thing = this.Thing;
        }
        tmp352.__isset.thing = this.__isset.thing;
        return tmp352;
      }

      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.String)
                {
                  Thing = await iprot.ReadStringAsync(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("secondtestString_args");
          await oprot.WriteStructBeginAsync(struc, cancellationToken);
          var field = new TField();
          if((Thing != null) && __isset.thing)
          {
            field.Name = "thing";
            field.Type = TType.String;
            field.ID = 1;
            await oprot.WriteFieldBeginAsync(field, cancellationToken);
            await oprot.WriteStringAsync(Thing, 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 secondtestStringArgs other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return ((__isset.thing == other.__isset.thing) && ((!__isset.thing) || (System.Object.Equals(Thing, other.Thing))));
      }

      public override int GetHashCode() {
        int hashcode = 157;
        unchecked {
          if((Thing != null) && __isset.thing)
          {
            hashcode = (hashcode * 397) + Thing.GetHashCode();
          }
        }
        return hashcode;
      }

      public override string ToString()
      {
        var sb = new StringBuilder("secondtestString_args(");
        int tmp353 = 0;
        if((Thing != null) && __isset.thing)
        {
          if(0 < tmp353++) { sb.Append(", "); }
          sb.Append("Thing: ");
          Thing.ToString(sb);
        }
        sb.Append(')');
        return sb.ToString();
      }
    }


    [DataContract(Namespace="")]
    public partial class secondtestStringResult : TBase
    {
      private string _success;

      [DataMember(Order = 0)]
      public string Success
      {
        get
        {
          return _success;
        }
        set
        {
          __isset.success = true;
          this._success = value;
        }
      }


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

      #region XmlSerializer support

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

      #endregion XmlSerializer support

      public secondtestStringResult()
      {
      }

      public secondtestStringResult DeepCopy()
      {
        var tmp354 = new secondtestStringResult();
        if((Success != null) && __isset.success)
        {
          tmp354.Success = this.Success;
        }
        tmp354.__isset.success = this.__isset.success;
        return tmp354;
      }

      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.String)
                {
                  Success = await iprot.ReadStringAsync(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("secondtestString_result");
          await oprot.WriteStructBeginAsync(struc, cancellationToken);
          var field = new TField();

          if(this.__isset.success)
          {
            if (Success != null)
            {
              field.Name = "Success";
              field.Type = TType.String;
              field.ID = 0;
              await oprot.WriteFieldBeginAsync(field, cancellationToken);
              await oprot.WriteStringAsync(Success, 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 secondtestStringResult other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return ((__isset.success == other.__isset.success) && ((!__isset.success) || (System.Object.Equals(Success, other.Success))));
      }

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

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

  }

}
}
