/* 
 * © 2008-2009 Sun Microsystems, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#ifndef _WF_BASE_H_
#define _WF_BASE_H_

#include <string>
#include <mforms/base.h>
#include <mforms/view.h>
#include "ConvUtils.h"

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

namespace MySQL {
  
// Callback definitions.
public ref class MCallback
{
public:
  ~MCallback() {};
};

template<typename R> public ref class MCallback0 : public MCallback
{
public:
  delegate R ManagedPtr();
  typedef R (__stdcall *UnmanagedPtr)();

  MCallback0(ManagedPtr ^ptr)
    :deleg(ptr)
  {
  }

  UnmanagedPtr get_pointer() 
  {
    wrap_deleg= gcnew WrapperDelegate(this, &MCallback0::cpp_callback);
    return static_cast<UnmanagedPtr>(Marshal::GetFunctionPointerForDelegate(wrap_deleg).ToPointer()); 
  }

private:  
  delegate R WrapperDelegate();

  ManagedPtr^ deleg;
  WrapperDelegate ^wrap_deleg;

  R cpp_callback()
  {
    return deleg();
  }
};

template<typename R,typename T1> public ref class MCallback1 : public MCallback
{
public:
  delegate R ManagedPtr(T1);
  typedef R (__stdcall *UnmanagedPtr)(T1);

  MCallback1(ManagedPtr ^ptr)
    :deleg(ptr)
  {
  }

  UnmanagedPtr get_pointer() 
  {
    wrap_deleg= gcnew WrapperDelegate(this, &MCallback1::cpp_callback);
    return static_cast<UnmanagedPtr>(Marshal::GetFunctionPointerForDelegate(wrap_deleg).ToPointer()); 
  }

private:  
  delegate R WrapperDelegate(T1);

  ManagedPtr^ deleg;
  WrapperDelegate ^wrap_deleg;

  R cpp_callback(T1 arg1)
  {
    return deleg(arg1);
  }
};

template<typename R,typename T1,typename T2> public ref class MCallback2 : public MCallback
{
public:
  delegate R ManagedPtr(T1, T2);
  typedef R (__stdcall *UnmanagedPtr)(T1,T2);

  MCallback2(ManagedPtr ^ptr)
    :deleg(ptr)
  {
  }

  UnmanagedPtr get_pointer() 
  { 
    wrap_deleg= gcnew WrapperDelegate(this, &MCallback2::cpp_callback);
    return static_cast<UnmanagedPtr>(Marshal::GetFunctionPointerForDelegate(wrap_deleg).ToPointer()); 
  }

private:  
  delegate R WrapperDelegate(T1 a1, T2 a2);

  ManagedPtr^ deleg;
  WrapperDelegate^ wrap_deleg;

  R cpp_callback(T1 a1, T2 a2)
  {
    return deleg(a1, a2);
  }
};


template<typename T1,typename T2> public ref class MCallback2<void,T1,T2> : public MCallback
{
public:
  delegate void ManagedPtr(T1, T2);
  typedef void (__stdcall *UnmanagedPtr)(T1,T2);

  MCallback2(ManagedPtr ^ptr)
    :deleg(ptr)
  {
  }

  UnmanagedPtr get_pointer() 
  { 
    wrap_deleg= gcnew WrapperDelegate(this, &MCallback2::cpp_callback);
    return static_cast<UnmanagedPtr>(Marshal::GetFunctionPointerForDelegate(wrap_deleg).ToPointer()); 
  }

private:  
  delegate void WrapperDelegate(T1, T2);

  ManagedPtr^ deleg;
  WrapperDelegate^ wrap_deleg;

  void cpp_callback(T1 a1, T2 a2)
  {
    deleg(a1, a2);
  }
};



template<typename R,typename T1,typename T2,typename T3> public ref class MCallback3 : public MCallback
{
public:
  delegate R ManagedPtr(T1, T2, T3);
  typedef R (__stdcall *UnmanagedPtr)(T1,T2,T3);

  MCallback3(ManagedPtr ^ptr)
    :deleg(ptr)
  {
  }

  UnmanagedPtr get_pointer() 
  { 
    wrap_deleg= gcnew WrapperDelegate(this, &MCallback3::cpp_callback);
    return static_cast<UnmanagedPtr>(Marshal::GetFunctionPointerForDelegate(wrap_deleg).ToPointer()); 
  }

private:  
  delegate R WrapperDelegate(T1 a1, T2 a2, T3 a3);

  ManagedPtr^ deleg;
  WrapperDelegate^ wrap_deleg;

  R cpp_callback(T1 a1, T2 a2, T3 a3)
  {
    return deleg(a1, a2, a3);
  }
};


template<typename R,typename T1,typename T2,typename T3,typename T4> public ref class MCallback4 : public MCallback
{
public:
  delegate R ManagedPtr(T1, T2, T3, T4);
  typedef R (__stdcall *UnmanagedPtr)(T1,T2,T3,T4);

  MCallback4(ManagedPtr ^ptr)
    :deleg(ptr)
  {
  }

  UnmanagedPtr get_pointer() 
  { 
    wrap_deleg= gcnew WrapperDelegate(this, &MCallback4::cpp_callback);
    return static_cast<UnmanagedPtr>(Marshal::GetFunctionPointerForDelegate(wrap_deleg).ToPointer()); 
  }

private:  
  delegate R WrapperDelegate(T1 a1, T2 a2, T3 a3, T4 a4);

  ManagedPtr^ deleg;
  WrapperDelegate^ wrap_deleg;

  R cpp_callback(T1 a1, T2 a2, T3 a3, T4 a4)
  {
    return deleg(a1, a2, a3, a4);
  }
};


template<typename R,typename T1,typename T2,typename T3,typename T4,typename T5> public ref class MCallback5 : public MCallback
{
public:
  delegate R ManagedPtr(T1, T2, T3, T4, T5);
  typedef R (__stdcall *UnmanagedPtr)(T1,T2,T3,T4,T5);

  MCallback5(ManagedPtr ^ptr)
    :deleg(ptr)
  {
  }

  UnmanagedPtr get_pointer() 
  { 
    wrap_deleg= gcnew WrapperDelegate(this, &MCallback5::cpp_callback);
    return static_cast<UnmanagedPtr>(Marshal::GetFunctionPointerForDelegate(wrap_deleg).ToPointer());
  }

private:  
  delegate R WrapperDelegate(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);

  ManagedPtr^ deleg;
  WrapperDelegate^ wrap_deleg;

  R cpp_callback(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
  {
    return deleg(a1, a2, a3, a4, a5);
  }
};

template<typename R,typename T1,typename T2,typename T3,typename T4,typename T5, typename T6> 
public ref class MCallback6 : public MCallback
{
public:
  delegate R ManagedPtr(T1, T2, T3, T4, T5, T6);
  typedef R (__stdcall *UnmanagedPtr)(T1, T2, T3, T4, T5, T6);

  MCallback6(ManagedPtr ^ptr)
    :deleg(ptr)
  {
  }

  UnmanagedPtr get_pointer() 
  { 
    wrap_deleg= gcnew WrapperDelegate(this, &MCallback6::cpp_callback);
    return static_cast<UnmanagedPtr>(Marshal::GetFunctionPointerForDelegate(wrap_deleg).ToPointer());
  }

private:  
  delegate R WrapperDelegate(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6);

  ManagedPtr^ deleg;
  WrapperDelegate^ wrap_deleg;

  R cpp_callback(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
  {
    return deleg(a1, a2, a3, a4, a5, a6);
  }
};

template<typename R,typename T1,typename T2,typename T3,typename T4,typename T5, typename T6, typename T7> 
public ref class MCallback7 : public MCallback
{
public:
  delegate R ManagedPtr(T1, T2, T3, T4, T5, T6, T7);
  typedef R (__stdcall *UnmanagedPtr)(T1, T2, T3, T4, T5, T6, T7);

  MCallback7(ManagedPtr ^ptr)
    :deleg(ptr)
  {
  }

  UnmanagedPtr get_pointer() 
  { 
    wrap_deleg= gcnew WrapperDelegate(this, &MCallback7::cpp_callback);
    return static_cast<UnmanagedPtr>(Marshal::GetFunctionPointerForDelegate(wrap_deleg).ToPointer());
  }

private:  
  delegate R WrapperDelegate(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7);

  ManagedPtr^ deleg;
  WrapperDelegate^ wrap_deleg;

  R cpp_callback(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7)
  {
    return deleg(a1, a2, a3, a4, a5, a6, a7);
  }
};

#define DEF_CALLBACK0(R, mgr, strukt, klass, method) do {\
  MCallback0<R> ^method= gcnew MCallback0<R>(gcnew MCallback0<R>::ManagedPtr(klass::method));\
  mgr->keep_callback(method);\
  strukt.method= method->get_pointer();\
} while (0)

#define DEF_CALLBACK1(R,T1,mgr,strukt,klass,method) do {\
  MCallback1<R,T1> ^method= gcnew MCallback1<R,T1>(gcnew MCallback1<R,T1>::ManagedPtr(klass::method));\
  mgr->keep_callback(method);\
  strukt.method= method->get_pointer();\
} while (0)

#define DEF_CALLBACK2(R,T1,T2,mgr,strukt,klass,method) do {\
  MCallback2<R,T1,T2> ^method= gcnew MCallback2<R,T1,T2>(gcnew MCallback2<R,T1,T2>::ManagedPtr(klass::method));\
  mgr->keep_callback(method);\
  strukt.method= method->get_pointer();\
} while (0)

#define DEF_CALLBACK3(R,T1,T2,T3,mgr,strukt,klass,method) do {\
  MCallback3<R,T1,T2,T3> ^method= gcnew MCallback3<R,T1,T2,T3>(gcnew MCallback3<R,T1,T2,T3>::ManagedPtr(klass::method));\
  mgr->keep_callback(method);\
  strukt.method= method->get_pointer();\
} while (0)

#define DEF_CALLBACK4(R,T1,T2,T3,T4,mgr,strukt,klass,method) do {\
  MCallback4<R,T1,T2,T3,T4> ^method= gcnew MCallback4<R,T1,T2,T3,T4>(gcnew MCallback4<R,T1,T2,T3,T4>::ManagedPtr(klass::method));\
  mgr->keep_callback(method);\
  strukt.method= method->get_pointer();\
} while (0)

#define DEF_CALLBACK5(R,T1,T2,T3,T4,T5,mgr,strukt,klass,method) do {\
  MCallback5<R,T1,T2,T3,T4,T5> ^method= gcnew MCallback5<R,T1,T2,T3,T4,T5>(gcnew MCallback5<R,T1,T2,T3,T4,T5>::ManagedPtr(klass::method));\
  mgr->keep_callback(method);\
  strukt.method= method->get_pointer();\
} while (0)

#define DEF_CALLBACK6(R, T1, T2, T3, T4, T5, T6, mgr, strukt, klass, method) do {\
  MCallback6<R, T1, T2, T3, T4, T5, T6> ^method= gcnew MCallback6<R, T1, T2, T3, T4, T5, T6>(\
  gcnew MCallback6<R, T1, T2, T3, T4, T5, T6>::ManagedPtr(klass::method));\
  mgr->keep_callback(method);\
  strukt.method= method->get_pointer();\
} while (0)

#define DEF_CALLBACK7(R, T1, T2, T3, T4, T5, T6, T7, mgr, strukt, klass, method) do {\
  MCallback7<R, T1, T2, T3, T4, T5, T6, T7> ^method= gcnew MCallback7<R, T1, T2, T3, T4, T5, T6, T7>(\
  gcnew MCallback7<R, T1, T2, T3, T4, T5, T6, T7>::ManagedPtr(klass::method));\
  mgr->keep_callback(method);\
  strukt.method= method->get_pointer();\
} while (0)

namespace Forms {
  public ref class ObjectImpl
  {
    GCHandle m_gch;

    // Returns a fixed pointer to this object that will not be modified by the GC
    IntPtr GetFixedId()
    {
      if (!m_gch.IsAllocated)
         m_gch = GCHandle::Alloc( this );
       return GCHandle::ToIntPtr( m_gch );
    }

    // Needs to be called when destroying the object
    void ReleaseHandle()
    {
      m_gch.Free();
    }

  protected:
    ObjectImpl(::mforms::Object *object)
    {
      // get a fixed pointer to this object
      IntPtr ip = this->GetFixedId();
      // set it as the user data
      object->set_data((void*)(intptr_t)ip);
    }

    virtual ~ObjectImpl()
    {
      ReleaseHandle();
    }

    // Returns the object based on the fixed pointer retrieved by GetFixedId()
    static ObjectImpl^ GetFromFixedId( IntPtr ip )
    {
      GCHandle gcHandle = GCHandle::FromIntPtr( ip );
      return (ObjectImpl^)gcHandle.Target;
    }

    static ObjectImpl^ FromUnmanaged(::mforms::Object *object)
    {
      return GetFromFixedId((IntPtr)object->get_data_ptr());
    }
  };
};


};


#endif
