context: namespace TradeMagic.Pats
  {
      using System;
      using System.Collections;
      using System.Collections.Specialized;
      using System.Diagnostics;
      using System.Globalization;
      using System.Runtime.CompilerServices;
      using System.Runtime.InteropServices;
      using System.Text;
      using System.Threading;
      using iTrading.Core.Kernel;
  
      public class Adapter : IAdapter, IMarketData, IMarketDepth, IOrder, IOrderChange
      {
          internal ASCIIEncoding asciiEncoding = new ASCIIEncoding();
          private Callback callback;
          internal Connection connection;
          private PatsApi.ContractCallback contractAddCallback;
          private PatsApi.ContractCallback contractDeleteCallback;
          internal static Adapter currentAdapter = null;
          private PatsApi.PatsCallback dataDLCompleteCallback;
          private static bool demoInitialised = false;
          internal Hashtable exchange2OrderTypes = new Hashtable();
          private PatsApi.FillCallback fillCallback;
          private PatsApi.PatsCallback forcedLogoutCallback;
          private PatsApi.LinkCallback hostLinkStateCallback;
          private static bool liveInitialised = false;
          private PatsApi.PatsCallback logonStatusCallback;
          private PatsApi.MsgCallback messageCallback;
          internal NumberFormatInfo numberFormatInfo = new NumberFormatInfo();
          private PatsApi.OrderCallback orderCallback;
          internal ArrayList orders2Cancel = new ArrayList();
          internal ArrayList orderStubs = new ArrayList();
          internal PatsApi patsApi;
          private PatsApi.LinkCallback priceLinkStateCallback;
          private PatsApi.PriceUpdateCallback priceUpdateCallback;
          internal ArrayList subscribedPriceData = new ArrayList();
          private ArrayList symbols = new ArrayList();
          internal object[] syncOrderStatusEvent = new object[0];
          private static bool testInitialised = false;
  
          internal Adapter(Connection connection)
          {
              currentAdapter = this;
              this.connection = connection;
              this.callback = new Callback(this);
              this.numberFormatInfo.NumberDecimalSeparator = ".";
              this.patsApi = new PatsApi(this);
              this.contractAddCallback = new PatsApi.ContractCallback(this.callback.ContractAdded);
              this.contractDeleteCallback = new PatsApi.ContractCallback(this.callback.ContractDeleted);
              this.dataDLCompleteCallback = new PatsApi.PatsCallback(this.callback.DataDLComplete);
              this.fillCallback = new PatsApi.FillCallback(this.callback.Fill);
              this.forcedLogoutCallback = new PatsApi.PatsCallback(this.callback.ForcedLogout);
              this.hostLinkStateCallback = new PatsApi.LinkCallback(this.callback.HostLinkStateCallback);
              this.logonStatusCallback = new PatsApi.PatsCallback(this.callback.LogonStatus);
              this.messageCallback = new PatsApi.MsgCallback(this.callback.MessageCallback);
              this.orderCallback = new PatsApi.OrderCallback(this.callback.Order);
              this.priceLinkStateCallback = new PatsApi.LinkCallback(this.callback.PriceLinkStateCallback);
              this.priceUpdateCallback = new PatsApi.PriceUpdateCallback(this.callback.PriceUpdate);
          }
  
          public void Cancel(iTrading.Core.Kernel.Order order)
          {
              lock (this.syncOrderStatusEvent)
              {
                  if (Globals.TraceSwitch.Order)
                  {
                      Trace.WriteLine("(" + this.connection.IdPlus + ") Pats.Adapter.Cancel0: " + order.ToString());
                  }
                  OrderStub adapterLink = (OrderStub) order.AdapterLink;
                  if ((adapterLink == null) || (adapterLink.orderId.Length == 0))
                  {
                      this.connection.ProcessEventArgs(new ITradingErrorEventArgs(this.connection, iTrading.Core.Kernel.ErrorCode.UnableToCancelOrder, "", "Unable to cancel order now. Please try again later"));
                  }
                  else
                  {
                      ArrayList list;
                      if (order.OrderState.Id == OrderStateId.PendingChange)
                      {
                          lock ((list = this.orders2Cancel))
                          {
                              if (!this.orders2Cancel.Contains(adapterLink))
                              {
                                  if (Globals.TraceSwitch.Order)
                                  {
                                      Trace.WriteLine("(" + this.connection.IdPlus + ") Pats.Adapter.Cancel1: " + order.ToString());
                                  }
                                  this.orders2Cancel.Add(adapterLink);
                              }
                          }
                      }
                      else
                      {
                          TradeMagic.Pats.ErrorCode code = this.patsApi.CancelOrder(adapterLink.orderId);
                          if ((code == TradeMagic.Pats.ErrorCode.ErrInvalidState) || (((code == TradeMagic.Pats.ErrorCode.ErrUnknownOrder) && (order.OrderState.Id != OrderStateId.Working)) && ((order.OrderState.Id != OrderStateId.PendingCancel) && (order.OrderState.Id != OrderStateId.PartFilled))))
                          {
                              lock ((list = this.orders2Cancel))
                              {
                                  if (!this.orders2Cancel.Contains(adapterLink))
                                  {
                                      if (Globals.TraceSwitch.Order)
                                      {
                                          Trace.WriteLine("(" + this.connection.IdPlus + ") Pats.Adapter.Cancel2: " + order.ToString());
                                      }
                                      this.orders2Cancel.Add(adapterLink);
                                  }
                                  goto Label_0306;
                              }
                          }
                          if (code == TradeMagic.Pats.ErrorCode.ErrUnknownOrder)
                          {
                              this.connection.ProcessEventArgs(new OrderStatusEventArgs(order, iTrading.Core.Kernel.ErrorCode.UnableToCancelOrder, "Unknown order: unable to cancel order '" + order.OrderId + "'", order.OrderId, order.LimitPrice, order.StopPrice, order.Quantity, order.AvgFillPrice, order.Filled, order.OrderState, this.connection.Now));
                          }
                          else if (code != TradeMagic.Pats.ErrorCode.Success)
                          {
                              this.connection.ProcessEventArgs(new OrderStatusEventArgs(order, iTrading.Core.Kernel.ErrorCode.UnableToCancelOrder, "Unable to cancel order '" + order.OrderId + "': (" + code.ToString() + ")", order.OrderId, order.LimitPrice, order.StopPrice, order.Quantity, order.AvgFillPrice, order.Filled, order.OrderState, this.connection.Now));
                          }
                          else
                          {
                              this.connection.ProcessEventArgs(new OrderStatusEventArgs(order, iTrading.Core.Kernel.ErrorCode.NoError, "", order.OrderId, order.LimitPrice, order.StopPrice, order.Quantity, order.AvgFillPrice, order.Filled, this.connection.OrderStates[OrderStateId.PendingCancel], this.connection.Now));
                          }
                      Label_0306:;
                      }
                  }
              }
          }
  
          public void Change(iTrading.Core.Kernel.Order order)
          {
              lock (this.syncOrderStatusEvent)
              {
                  if (Globals.TraceSwitch.Order)
                  {
                      Trace.WriteLine("(" + this.connection.IdPlus + ") Pats.Adapter.Change0: " + order.ToString());
                  }
                  OrderStub adapterLink = (OrderStub) order.AdapterLink;
                  if ((adapterLink == null) || (adapterLink.orderId.Length == 0))
                  {
                      this.connection.ProcessEventArgs(new ITradingErrorEventArgs(this.connection, iTrading.Core.Kernel.ErrorCode.UnableToChangeOrder, "", "Unable to update order now. Please try again later."));
                  }
                  else
                  {
                      iTrading.Core.Kernel.OrderType currentOrderType = this.GetCurrentOrderType(order);
                      if (currentOrderType == null)
                      {
                          this.connection.ProcessEventArgs(new OrderStatusEventArgs(order, iTrading.Core.Kernel.ErrorCode.UnableToChangeOrder, "Pats.Adapter.Change.GetCurrentOrderType failed", order.OrderId, order.LimitPrice, order.StopPrice, order.Quantity, order.AvgFillPrice, order.Filled, order.OrderState, order.Connection.Now));
                      }
                      else
                      {
                          PatsApi.AmendOrderStruct amendOrder = new PatsApi.AmendOrderStruct();
                          amendOrder.trader = adapterLink.patsOrder.traderAccount;
                          amendOrder.price = new char[0x15];
                          amendOrder.price2 = new char[0x15];
                          amendOrder.linkedOrder = new char[11];
                          if (currentOrderType.Id == OrderTypeId.Limit)
                          {
                              PatsApi.PriceToChars(this.numberFormatInfo, order.Symbol, order.LimitPrice, amendOrder.price);
                          }
                          else if (currentOrderType.Id == OrderTypeId.Stop)
                          {
                              PatsApi.PriceToChars(this.numberFormatInfo, order.Symbol, order.StopPrice, amendOrder.price);
                          }
                          else if (currentOrderType.Id == OrderTypeId.StopLimit)
                          {
                              PatsApi.PriceToChars(this.numberFormatInfo, order.Symbol, order.LimitPrice, amendOrder.price2);
                              PatsApi.PriceToChars(this.numberFormatInfo, order.Symbol, order.StopPrice, amendOrder.price);
                          }
                          amendOrder.lots = order.Quantity;
                          if ((order.Action.Id == ActionTypeId.Buy) || (order.Action.Id == ActionTypeId.SellShort))
                          {
                              amendOrder.openOrClose = 'O';
                          }
                          else
                          {
                              amendOrder.openOrClose = 'C';
                          }
                          TradeMagic.Pats.ErrorCode code = this.patsApi.AmendOrder(adapterLink.orderId, ref amendOrder);
                          if (code == TradeMagic.Pats.ErrorCode.ErrAmendDisabled)
                          {
                              this.connection.ProcessEventArgs(new OrderStatusEventArgs(order, iTrading.Core.Kernel.ErrorCode.UnableToChangeOrder, "Exchange does not support order changes (" + code.ToString() + ")", order.OrderId, order.LimitPrice, order.StopPrice, order.Quantity, order.AvgFillPrice, order.Filled, order.OrderState, this.connection.Now));
                          }
                          else if (code != TradeMagic.Pats.ErrorCode.Success)
                          {
                              this.connection.ProcessEventArgs(new OrderStatusEventArgs(order, iTrading.Core.Kernel.ErrorCode.UnableToChangeOrder, "Order '" + order.OrderId + "' can't be changed (" + code.ToString() + ")", order.OrderId, order.LimitPrice, order.StopPrice, order.Quantity, order.AvgFillPrice, order.Filled, order.OrderState, this.connection.Now));
                          }
                          else
                          {
                              this.connection.ProcessEventArgs(new OrderStatusEventArgs(order, iTrading.Core.Kernel.ErrorCode.NoError, "", order.OrderId, order.LimitPrice, order.StopPrice, order.Quantity, order.AvgFillPrice, order.Filled, this.connection.OrderStates[OrderStateId.PendingChange], this.connection.Now));
                          }
                      }
                  }
              }
          }
  
          public void Clear()
          {
          }
  
          public void Connect()
          {
              if (Globals.TraceSwitch.Connect)
              {
                  Trace.WriteLine(string.Concat(new object[] { 
                      "(", this.connection.IdPlus, ") Pats.Adapter.Connect0: host='", ((PatsOptions) this.connection.Options).HostAddress, "/", ((PatsOptions) this.connection.Options).HostPort, "' price='", ((PatsOptions) this.connection.Options).PriceAddress, "/", ((PatsOptions) this.connection.Options).PricePort, "' supertas=", ((PatsOptions) this.connection.Options).SuperTas, " enable=", ((PatsOptions) this.connection.Options).Enable, " host-handshake=", ((PatsOptions) this.connection.Options).HostHandShakeInterval, 
                      "/", ((PatsOptions) this.connection.Options).HostHandShakeTimeout, " price-handshake=", ((PatsOptions) this.connection.Options).PriceHandShakeInterval, "/", ((PatsOptions) this.connection.Options).PriceHandShakeTimeout
                   }));
              }
              if (this.connection.Options.Mode.Id == ModeTypeId.Simulation)
              {
                  if (Globals.TraceSwitch.Connect)
                  {
                      Trace.WriteLine("(" + this.connection.IdPlus + ") Pats.Adapter.Connect1");
                  }
                  new Thread(new ThreadStart(this.ConnectSimulation)).Start();
              }
              else
              {
                  this.callback.InitVars();
                  PatsOptions options = (PatsOptions) this.connection.Options;
                  if (this.connection.Options.License.Id != LicenseTypeId.Professional)
                  {
                      this.connection.ProcessEventArgs(new ConnectionStatusEventArgs(this.connection, iTrading.Core.Kernel.ErrorCode.InvalidLicense, "The Patsystems adapter requires professional license", ConnectionStatusId.Disconnected, ConnectionStatusId.Disconnected, 0, ""));
                  }
                  else if (this.connection.Options.Password.Length > 10)
                  {
                      this.connection.ProcessEventArgs(new ConnectionStatusEventArgs(this.connection, iTrading.Core.Kernel.ErrorCode.LoginFailed, "Password string too long, max = " + 10, ConnectionStatusId.Disconnected, ConnectionStatusId.Disconnected, 0, ""));
                  }
                  else if (this.connection.Options.User.Length > 10)
                  {
                      this.connection.ProcessEventArgs(new ConnectionStatusEventArgs(this.connection, iTrading.Core.Kernel.ErrorCode.LoginFailed, "User ID string too long, max = " + 10, ConnectionStatusId.Disconnected, ConnectionStatusId.Disconnected, 0, ""));
                  }
                  else
                  {
                      this.patsApi.Enable(options.Enable);
                      this.patsApi.SetClientPath(Globals.InstallDir + @"\bin\Pats\");
                      TradeMagic.Pats.ErrorCode success = TradeMagic.Pats.ErrorCode.Success;
                      if ((options.Mode.Id == ModeTypeId.Demo) && !demoInitialised)
                      {
                          success = this.patsApi.Initialise(0x44, "v2.8.3", " ", " ", " ");
                          if (success != TradeMagic.Pats.ErrorCode.Success)
                          {
                              this.connection.ProcessEventArgs(new ConnectionStatusEventArgs(this.connection, iTrading.Core.Kernel.ErrorCode.Panic, "Pats.Adapter.Connect.ptInitialise: can't initialise Patsystem (" + success + ")", ConnectionStatusId.Disconnected, ConnectionStatusId.Disconnected, 0, ""));
                              return;
                          }
                          success = this.patsApi.SetInternetUser(false);
                          if (success != TradeMagic.Pats.ErrorCode.Success)
                          {
                              this.connection.ProcessEventArgs(new ConnectionStatusEventArgs(this.connection, iTrading.Core.Kernel.ErrorCode.Panic, "Pats.Adapter.Connect.ptSetInternetUser: error " + success, ConnectionStatusId.Disconnected, ConnectionStatusId.Disconnected, 0, ""));
                              return;
                          }
                          demoInitialised = true;
                      }
                      else if ((options.Mode.Id == ModeTypeId.Test) && !testInitialised)
                      {
                          success = this.patsApi.Initialise(0x54, "v2.8.3", ((PatsOptions) this.connection.Options).ApplicationId, "1.0", ((PatsOptions) this.connection.Options).LicenseKey);
                          if (success != TradeMagic.Pats.ErrorCode.Success)
                          {
                              this.connection.ProcessEventArgs(new ConnectionStatusEventArgs(this.connection, iTrading.Core.Kernel.ErrorCode.Panic, "Pats.Adapter.Connect.ptInitialise: can't initialise Patsystem (" + success + ")", ConnectionStatusId.Disconnected, ConnectionStatusId.Disconnected, 0, ""));
                              return;
                          }
                          success = this.patsApi.SetInternetUser(true);
                          if (success != TradeMagic.Pats.ErrorCode.Success)
                          {
                              this.connection.ProcessEventArgs(new ConnectionStatusEventArgs(this.connection, iTrading.Core.Kernel.ErrorCode.Panic, "Pats.Adapter.Connect.ptSetInternetUser: error " + success, ConnectionStatusId.Disconnected, ConnectionStatusId.Disconnected, 0, ""));
                              return;
                          }
                          testInitialised = true;
                      }
                      else if ((options.Mode.Id == ModeTypeId.Live) && !liveInitialised)
                      {
                          success = this.patsApi.Initialise(0x43, "v2.8.3", ((PatsOptions) this.connection.Options).ApplicationId, "1.0", ((PatsOptions) this.connection.Options).LicenseKey);
                          if (success != TradeMagic.Pats.ErrorCode.Success)
                          {
                              this.connection.ProcessEventArgs(new ConnectionStatusEventArgs(this.connection, iTrading.Core.Kernel.ErrorCode.Panic, "Pats.Adapter.Connect.ptInitialise: can't initialise Patsystem (" + success + ")", ConnectionStatusId.Disconnected, ConnectionStatusId.Disconnected, 0, ""));
                              return;
                          }
                          success = this.patsApi.SetInternetUser(true);
                          if (success != TradeMagic.Pats.ErrorCode.Success)
                          {
                              this.connection.ProcessEventArgs(new ConnectionStatusEventArgs(this.connection, iTrading.Core.Kernel.ErrorCode.Panic, "Pats.Adapter.Connect.ptSetInternetUser: error " + success, ConnectionStatusId.Disconnected, ConnectionStatusId.Disconnected, 0, ""));
                              return;
                          }
                          liveInitialised = true;
                      }
                      if (options.Mode.Id != ModeTypeId.Demo)
                      {
                          success = this.patsApi.SetSuperTAS(options.SuperTas ? 'Y' : 'N');
  
gt:                         if (success != TradeMagic.Pats.ErrorCode.Success)