using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;


namespace Rfc1006Lib
{ 
  public class Rfc1006
  {
    #region Imports aus rfc1006lib.dll
    [DllImport("rfc1006lib.dll")]
    unsafe static extern int Rfc1006Open (string IPAdr,[MarshalAs(UnmanagedType.LPArray)] byte[] SSAP, uint LenSSAP,[MarshalAs(UnmanagedType.LPArray)] byte[] DSAP, uint LenDSAP, uint Port, uint ConnectTimeout);

    [DllImport("rfc1006lib.dll")]
    unsafe static extern int Rfc1006Close (int Ref);

    [DllImport("rfc1006lib.dll")]
    unsafe static extern int Rfc1006Rx (int Ref, void *Buf, uint MaxCnt, uint RxTimeout);

    [DllImport("rfc1006lib.dll")]
    unsafe static extern int Rfc1006Tx (int Ref, void *Buf, uint Cnt, uint Timeout);

    [DllImport("rfc1006lib.dll")]
    unsafe static extern int Rfc1006GetSockErr (int Ref);

    [DllImport("rfc1006lib.dll")]
    unsafe static extern int Rfc1006Connect (int Ref);

    [DllImport("rfc1006lib.dll")]
    unsafe static extern int Rfc1006Disconnect (int Ref);

    [DllImport("rfc1006lib.dll")]
    unsafe static extern int Rfc1006GetStatus (int Ref);

    [DllImport("rfc1006lib.dll")]
    unsafe static extern int Rfc1006StartServer (uint Port, string BindIPAdr, uint MaxCon);

    [DllImport("rfc1006lib.dll")]
    unsafe static extern int Rfc1006OpenServer (string DstIPAdr, [MarshalAs(UnmanagedType.LPArray)] byte[] SSAP, uint LenSSAP, [MarshalAs(UnmanagedType.LPArray)] byte[] DSAP, uint LenDSAP); 

    [DllImport("rfc1006lib.dll")]
    unsafe static extern int
    Rfc1006StopServer ();

    [DllImport("rfc1006lib.dll")]
    unsafe static extern void   Rfc1006CloseAll (); // 1.14

    [DllImport("rfc1006lib.dll")]
    unsafe static extern int  Rfc1006SetKeepAlive (int Ref, uint AliveInterval, uint AliveTime); // 1.18

    [DllImport("rfc1006lib.dll")]
    unsafe static extern int Rfc1006TxUnlocked (int Ref, void *Buf, uint Cnt, uint Timeout); // 1.19

    [DllImport("rfc1006lib.dll")]
    unsafe static extern int Rfc1006SetFastAck(int Ref, uint Mode); // 1.22

    #endregion

    public struct Result
    {
      public const int E_NOERR = 0;
      public const int E_TIMEOUT	=	-1;
      public const int E_NORES_AVAIL = -2; 
      public const int E_REF_NOTOPENED =	-3;
      public const int E_GENERAL = -5;
      public const int E_NOPARTNER = -6;
      public const int E_SOCKERR = -7;
      public const int E_SERVER_YET_RUNNING =	-10;
      public const int E_STARTING_SERVER  =	-11;
      public const int E_SERVER_NOT_RUNNING =	-12;
      public const int E_NOCONNECTION	 = -13;
      public const int E_BUFSIZE =  -14;
      public const int E_BADREF = -99;

      /// <summary>
      /// Der angegebene Speicher des PC ist zu klein (z.B. Array zu klein). (-20)
      /// </summary>
      /// 
      public const int E_PC_BUFSIZE = -20;
      public const int E_ALREADY_OPENED = -21;
      public const int E_DEMOOVER = 0x1234;
    }

    protected int m_Ref;

    public Rfc1006 ()
    {
      m_Ref = -1;
    }

    public int Open (string IPAdr, byte[] SSAP, uint LenSSAP, byte[] DSAP, uint LenDSAP, uint Port, uint ConnectTimeout)
    {
      if (m_Ref >= 0)
        return (Rfc1006.Result.E_ALREADY_OPENED); // Open wurde bereits ausgeführt
      m_Ref = Rfc1006Open (IPAdr, SSAP, LenSSAP, DSAP, LenDSAP, Port, ConnectTimeout);
      return (m_Ref);
    }

    public int OpenServer(string DstIPAdr, byte[] SSAP, uint LenSSAP, byte[] DSAP, uint LenDSAP)
    {
      if (m_Ref >= 0)
        return (Rfc1006.Result.E_ALREADY_OPENED); // Open wurde bereits ausgeführt
      m_Ref = Rfc1006OpenServer(DstIPAdr, SSAP, LenSSAP, DSAP, LenDSAP);
      return (m_Ref);
    }

    public int
    Close()
    {
      int Res;
      Res = Rfc1006Close(m_Ref);
      m_Ref = -1;
      return (Res);
    }

    unsafe public int
    Rx(byte [] Buf, uint Cnt, uint Timeout)
    {
      int L;
      int Res;

      L = Buf.GetLength(0);
      if (L < (int)Cnt)
        return (Result.E_PC_BUFSIZE);
      fixed (void* pB = Buf)
      {
        Res = Rfc1006Rx(m_Ref, pB, Cnt, Timeout);
      }
      return (Res);
    }

        

    unsafe public int
    Tx (byte[] Buf, uint Cnt, uint Timeout)
    {
      int L;
      int Res = 0;
      if (Cnt > 0)
      {
        L = Buf.GetLength(0);
        if (L < (int)Cnt)
          return (Result.E_PC_BUFSIZE);
        fixed (byte* pB = Buf)
        {
          Res = Rfc1006Tx(m_Ref, pB, Cnt, Timeout);
        }
      }
      return (Res);
    }

    public int GetSockErr()
    {
      return (Rfc1006GetSockErr(m_Ref));
    }

    public int Connect()
    {
      return (Rfc1006Connect(m_Ref));
    }

    public int Disconnect()
    {
      return (Rfc1006Disconnect(m_Ref));
    }


    public int GetStatus()
    {
      return (Rfc1006GetStatus(m_Ref));
    }
    
    public int StartServer(uint Port, string BindIPAdr, uint MaxCon)
    {
      return (Rfc1006StartServer(Port, BindIPAdr, MaxCon));
    }
 
    public int SetFastAck (bool bOn)
    {
      return (Rfc1006SetFastAck (m_Ref, bOn?(uint)1:(uint)0));
    }

    public int StopServer()
    {
      return (Rfc1006StopServer());
    }


    public void CloseAll()
    {
      Rfc1006CloseAll();
    }


    public int SetKeepAlive(uint AliveInterval, uint AliveTime)
    {
      return (Rfc1006SetKeepAlive(m_Ref,AliveInterval, AliveTime)); 
    }

    unsafe public int TxUnlocked(byte[] Buf, uint Cnt, uint Timeout) // 1.19
    { 
      int L;
      int Res;
      L = Buf.GetLength(0);
      if (L < (int)Cnt)
        return (Result.E_PC_BUFSIZE);
      fixed (void* pB = Buf)
      {
        Res = Rfc1006TxUnlocked(m_Ref, pB, Cnt, Timeout);
      }
      return (Res);
    }
  }
}
