#ifndef __SIGCSLOT_H__
#define __SIGCSLOT_H__

using namespace System;
using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;

namespace MySQL {
namespace Grt {

  inline int nativeToManaged(int input)
  {
    return input;
  }

  inline long long nativeToManaged(long long input)
  {
    return input;
  }

  inline float nativeToManaged(float input)
  {
    return input;
  }

  inline bool nativeToManaged(bool input)
  {
    return input;
  }

  inline String^ nativeToManaged(const char *input)
  { return CppStringToNative(input); }

  inline String^ nativeToManaged(const std::string &input)
  { return CppStringToNative(input); }


  inline int managedToNative(int input)
  {
    return input;
  }

  inline bool managedToNative(bool input)
  {
    return input;
  }

  inline std::string managedToNative(String^ input)
  {
    return NativeToCppString(input);
  }


  template<typename RN, typename RM>
  public ref class DelegateSlot0
  {
  public:
    delegate RM ManagedDelegate();
  private:
    delegate RN WrapperDelegate();
    typedef RN (*NativeCBType)();

    ManagedDelegate^ managed_delegate;
    WrapperDelegate^ wrapper_delegate;

    RN cpp_callback()
    {
      RM ret= managed_delegate();
      return managedToNative(ret);
    }

  public:
    DelegateSlot0(ManagedDelegate^ deleg)
      : managed_delegate(deleg)
    {
    }

    sigc::slot<RN> get_slot() 
    {
      wrapper_delegate= gcnew WrapperDelegate(this, &DelegateSlot0::cpp_callback);
      IntPtr ip = Marshal::GetFunctionPointerForDelegate(wrapper_delegate);
      NativeCBType cb = static_cast<NativeCBType>(ip.ToPointer());
      return sigc::ptr_fun(cb);
    }
  };

  template<>
  public ref class DelegateSlot0<void,void>
  {
  public:
    typedef void RM;
    typedef void RN;
    delegate RM ManagedDelegate();
  private:
    delegate RN WrapperDelegate();
    typedef RN (*NativeCBType)();

    ManagedDelegate^ managed_delegate;
    WrapperDelegate^ wrapper_delegate;

    RN cpp_callback()
    {
      managed_delegate();
    }

  public:
    DelegateSlot0(ManagedDelegate^ deleg)
      : managed_delegate(deleg)
    {
    }

    sigc::slot<RN> get_slot() 
    {
      wrapper_delegate= gcnew WrapperDelegate(this, &DelegateSlot0::cpp_callback);
      IntPtr ip = Marshal::GetFunctionPointerForDelegate(wrapper_delegate);
      NativeCBType cb = static_cast<NativeCBType>(ip.ToPointer());
      return sigc::ptr_fun(cb);
    }
  };



  template<typename RN, typename RM, typename A1N, typename A1M>
  public ref class DelegateSlot1
  {
  public:
    delegate RM ManagedDelegate(A1M a1);
  private:
    delegate RN WrapperDelegate(const A1N &a1);
    typedef RN (*NativeCBType)(const A1N &a1);

    ManagedDelegate^ managed_delegate;
    WrapperDelegate^ wrapper_delegate;

    RN cpp_callback(const A1N &a1)
    {
      RM ret= managed_delegate(nativeToManaged(a1));
      return managedToNative(ret);
    }

  public:
    DelegateSlot1(ManagedDelegate^ deleg)
      : managed_delegate(deleg)
    {
    }

    sigc::slot<RN,A1N> get_slot() 
    {
      wrapper_delegate= gcnew WrapperDelegate(this, &DelegateSlot1::cpp_callback);
      IntPtr ip = Marshal::GetFunctionPointerForDelegate(wrapper_delegate);
      NativeCBType cb = static_cast<NativeCBType>(ip.ToPointer());
      return sigc::ptr_fun(cb);
    }
  };


 template<typename RN, typename RM, typename A1N, typename A1M, typename A2N, typename A2M>
  public ref class DelegateSlot2
  {
  public:
    delegate RM ManagedDelegate(A1M a1, A2M a2);

  private:
    delegate RN WrapperDelegate(const A1N &a1, const A2N &a2);
    typedef RN (*NativeCBType)(const A1N &a1, const A2N &a2);

    ManagedDelegate^ managed_delegate;
    WrapperDelegate^ wrapper_delegate;

    RN cpp_callback(const A1N &a1, const A2N &a2)
    {
      RM ret= managed_delegate(nativeToManaged(a1), nativeToManaged(a2));
      return managedToNative(ret);
    }

  public:
    DelegateSlot2(ManagedDelegate^ deleg)
      : managed_delegate(deleg)
    {
    }

    sigc::slot<RN,A1N,A2N> get_slot() 
    {
      wrapper_delegate= gcnew WrapperDelegate(this, &DelegateSlot2::cpp_callback);
      IntPtr ip = Marshal::GetFunctionPointerForDelegate(wrapper_delegate);
      NativeCBType cb = static_cast<NativeCBType>(ip.ToPointer());
      return sigc::ptr_fun(cb);
    }
  };
  
  
 template<typename RN, typename RM, typename A1N, typename A1M, typename A2N, typename A2M, typename A3N, typename A3M>
  public ref class DelegateSlot3
  {
  public:
    delegate RM ManagedDelegate(A1M a1, A2M a2, A3M a3);

  private:
    delegate RN WrapperDelegate(const A1N &a1, const A2N &a2, const A3N &a3);
    typedef RN (*NativeCBType)(const A1N &a1, const A2N &a2, const A3N &a3);

    ManagedDelegate^ managed_delegate;
    WrapperDelegate^ wrapper_delegate;

    RN cpp_callback(const A1N &a1, const A2N &a2, const A3N &a3)
    {
      RM ret= managed_delegate(nativeToManaged(a1), nativeToManaged(a2), nativeToManaged(a3));
      return managedToNative(ret);
    }

  public:
    DelegateSlot3(ManagedDelegate^ deleg)
      : managed_delegate(deleg)
    {
    }

    sigc::slot<RN,A1N,A2N,A3N> get_slot() 
    {
      wrapper_delegate= gcnew WrapperDelegate(this, &DelegateSlot3::cpp_callback);
      IntPtr ip = Marshal::GetFunctionPointerForDelegate(wrapper_delegate);
      NativeCBType cb = static_cast<NativeCBType>(ip.ToPointer());
      return sigc::ptr_fun(cb);
    }
  };


 template<typename RN, typename RM, typename A1N, typename A1M, typename A2N, typename A2M, typename A3N, typename A3M, typename A4N, typename A4M>
  public ref class DelegateSlot4
  {
  public:
    delegate RM ManagedDelegate(A1M a1, A2M a2, A3M a3, A4M a4);

  private:
    delegate RN WrapperDelegate(const A1N &a1, const A2N &a2, const A3N &a3, const A4N &a4);
    typedef RN (*NativeCBType)(const A1N &a1, const A2N &a2, const A3N &a3, const A4N &a4);

    ManagedDelegate^ managed_delegate;
    WrapperDelegate^ wrapper_delegate;

    RN cpp_callback(const A1N &a1, const A2N &a2, const A3N &a3, const A4N &a4)
    {
      RM ret= managed_delegate(nativeToManaged(a1), nativeToManaged(a2), nativeToManaged(a3), nativeToManaged(a4));
      return managedToNative(ret);
    }

  public:
    DelegateSlot4(ManagedDelegate^ deleg)
      : managed_delegate(deleg)
    {
    }

    sigc::slot<RN,A1N,A2N,A3N,A4N> get_slot() 
    {
      wrapper_delegate= gcnew WrapperDelegate(this, &DelegateSlot4::cpp_callback);
      IntPtr ip = Marshal::GetFunctionPointerForDelegate(wrapper_delegate);
      NativeCBType cb = static_cast<NativeCBType>(ip.ToPointer());
      return sigc::ptr_fun(cb);
    }
  };
}
};

#endif