//------------------------------------------------------------------------------
// File: bind_Point.cpp
//------------------------------------------------------------------------------
// This is an automatically created binding code file for JewelScript.
// It allows you to easily bind your external C++ code to the script runtime,
// and to use your external functions and classes from within JewelScript.
//
// For more information see: http://blog.jewe.org/?p=29
//------------------------------------------------------------------------------

#include <string>

#include "jilapi.h"
#include "jiltools.h"

// TODO: This assumes your external C++ code is in "CPoint.h" and your native class is "CPoint" (use search/replace to change this if needed)
// TODO: You may have to add more includes before this one to be able to include "CPoint.h"
#include "CPoint.h"

// TODO: This forward declares your new type proc. Copy this line to the top of the file where you initialize the runtime and register your native types.
JILEXTERN JILError bind_Point_proc(NTLInstance*, JILLong, JILLong, JILUnknown*, JILUnknown**);

// TODO: You can use this code to register your new type to the runtime:
// JILError err = JILRegisterNativeType( pVM, bind_Point_proc );

//-----------------------------------------------------------------------------------
// type name macros
//-----------------------------------------------------------------------------------
// This is a list of names of other types this native binding is using. You might
// want to move this list to an include file where you collect ALL type names from
// ALL your native bindings. Then you can include the file in every native binding
// and be sure they all reference the same type names. This will make it easier
// if you ever want to change the name of a class or move it to another namespace.

#define TYPENAME_System_Drawing_Rect        "System::Drawing::Rect"

//-----------------------------------------------------------------------------------
// function enumeration - this must be kept in sync with the class declaration below.
//-----------------------------------------------------------------------------------

enum {
    fn_Point,
    fn_Point2,
    fn_Point3,
    fn_IsInside,
    fn_X,
    fn_Y
};

//--------------------------------------------------------------------------------------------
// class declaration string - order of declarations must be kept in sync with the enumeration.
//--------------------------------------------------------------------------------------------

static const JILChar* kClassDeclaration =
    TAG("Represents a two-dimensional coordinate on the screen.")
    "method Point ();" TAG("Constructs a point at coordinates (0,0).")
    "method Point (const Point);" TAG("Constructs a copy of the given point.")
    "method Point (int x, int y);" TAG("Constructs a point at the given coordinates.")
    "method int IsInside (const Rect r);" TAG("Returns true if this point is inside the rectangle.")
    "accessor int X ();" TAG("Returns this point's X-coordinate.")
    "accessor int Y ();" TAG("Returns this point's Y-coordinate.")
;

//------------------------------------------------------------------------------
// class info constants
//------------------------------------------------------------------------------

static const JILChar*   kClassName      =   "System::Drawing::Point"; // The class name that will be used in JewelScript.
static const JILChar*   kPackageList    =   TYPENAME_System_Drawing_Rect;
static const JILChar*   kAuthorName     =   "YOUR NAME HERE"; // TODO: You can enter your name here
static const JILChar*   kAuthorString   =   "Represents a two-dimensional coordinate on the screen."; // TODO: You can enter a description of your native type here
static const JILChar*   kTimeStamp      =   "2014-05-31 23:58:46"; // TODO: You can enter a build time stamp here
static const JILChar*   kAuthorVersion  =   "1.0.0.0"; // TODO: You can change the version number here

//------------------------------------------------------------------------------
// forward declare internal functions
//------------------------------------------------------------------------------

static JILError bind_Point_Register    (JILState* pVM);
static JILError bind_Point_GetDecl     (JILUnknown* pDataIn);
static JILError bind_Point_New         (NTLInstance* pInst, CPoint** ppObject);
static JILError bind_Point_Delete      (NTLInstance* pInst, CPoint* _this);
static JILError bind_Point_Mark        (NTLInstance* pInst, CPoint* _this);
static JILError bind_Point_CallStatic  (NTLInstance* pInst, JILLong funcID);
static JILError bind_Point_CallMember  (NTLInstance* pInst, JILLong funcID, CPoint* _this);

//------------------------------------------------------------------------------
// native type proc
//------------------------------------------------------------------------------
// This is the function you need to register with the script runtime.

JILEXTERN JILError bind_Point_proc(NTLInstance* pInst, JILLong msg, JILLong param, JILUnknown* pDataIn, JILUnknown** ppDataOut)
{
    int result = JIL_No_Exception;
    switch( msg )
    {
        // runtime messages
        case NTL_Register:              return bind_Point_Register((JILState*) pDataIn);
        case NTL_Initialize:            break;
        case NTL_NewObject:             return bind_Point_New(pInst, (CPoint**) ppDataOut);
        case NTL_DestroyObject:         return bind_Point_Delete(pInst, (CPoint*) pDataIn);
        case NTL_MarkHandles:           return bind_Point_Mark(pInst, (CPoint*) pDataIn);
        case NTL_CallStatic:            return bind_Point_CallStatic(pInst, param);
        case NTL_CallMember:            return bind_Point_CallMember(pInst, param, (CPoint*) pDataIn);
        case NTL_Terminate:             break;
        case NTL_Unregister:            break;
        // class information queries
        case NTL_GetInterfaceVersion:   return NTLRevisionToLong(JIL_TYPE_INTERFACE_VERSION);
        case NTL_GetAuthorVersion:      return NTLRevisionToLong(kAuthorVersion);
        case NTL_GetClassName:          (*(const JILChar**) ppDataOut) = kClassName; break;
        case NTL_GetPackageString:      (*(const JILChar**) ppDataOut) = kPackageList; break;
        case NTL_GetDeclString:         return bind_Point_GetDecl(pDataIn);
        case NTL_GetBuildTimeStamp:     (*(const JILChar**) ppDataOut) = kTimeStamp; break;
        case NTL_GetAuthorName:         (*(const JILChar**) ppDataOut) = kAuthorName; break;
        case NTL_GetAuthorString:       (*(const JILChar**) ppDataOut) = kAuthorString; break;
        // return error on unknown messages
        default:                        result = JIL_ERR_Unsupported_Native_Call; break;
    }
    return result;
}

//------------------------------------------------------------------------------
// bind_Point_Register
//------------------------------------------------------------------------------

static JILError bind_Point_Register(JILState* pVM)
{
    // If your type library consists of multiple related classes, you could register any helper classes here.
    // That way your application only needs to register the main class to the script runtime.
    // JILError err = JILRegisterNativeType(pVM, bind_MyHelperClass_proc);
    return JIL_No_Exception;
}

//------------------------------------------------------------------------------
// bind_Point_GetDecl
//------------------------------------------------------------------------------

static JILError bind_Point_GetDecl(JILUnknown* pDataIn)
{
    // Dynamically build the class declaration
    NTLDeclareVerbatim(pDataIn, kClassDeclaration); // add the static part of the class declaration
    return JIL_No_Exception;
}

//------------------------------------------------------------------------------
// bind_Point_New
//------------------------------------------------------------------------------

static JILError bind_Point_New(NTLInstance* pInst, CPoint** ppObject)
{
    // Allocate memory and write the pointer to ppObject
    *ppObject = (CPoint*)operator new(sizeof(CPoint));
    return JIL_No_Exception;
}

//------------------------------------------------------------------------------
// bind_Point_Delete
//------------------------------------------------------------------------------

static JILError bind_Point_Delete(NTLInstance* pInst, CPoint* _this)
{
    // Destroy native instance
    delete _this;
    return JIL_No_Exception;
}

//------------------------------------------------------------------------------
// bind_Point_Mark
//------------------------------------------------------------------------------

static JILError bind_Point_Mark(NTLInstance* pInst, CPoint* _this)
{
    // TODO: Add the function below to your class if you want to use the garbage collector.
    // The garbage collector will call this to mark all objects that are not garbage.
    // Call NTLMarkHandle() for all JILHandle pointers your class owns.

    // _this->MarkHandles(NTLInstanceGetVM(pInst));  // TODO: Uncomment and implement if you want to use GC.
    return JIL_No_Exception;
}

//------------------------------------------------------------------------------
// bind_Point_CallStatic
//------------------------------------------------------------------------------

static JILError bind_Point_CallStatic(NTLInstance* pInst, JILLong funcID)
{
    return JIL_ERR_Invalid_Function_Index;
}

//------------------------------------------------------------------------------
// bind_Point_CallMember
//------------------------------------------------------------------------------

static JILError bind_Point_CallMember(NTLInstance* pInst, JILLong funcID, CPoint* _this)
{
    JILError error = JIL_No_Exception;
    JILState* ps = NTLInstanceGetVM(pInst);     // get pointer to VM
    JILLong thisID = NTLInstanceTypeID(pInst);  // get the type-id of this class
    switch( funcID )
    {
        case fn_Point: // method Point ()
        {
            new (_this) CPoint(); // using placement new to instantiate into '_this'
            break;
        }
        case fn_Point2: // method Point (const Point)
        {
            JILHandle* h_arg_0 = NTLGetArgHandle(ps, 0);
            CPoint* arg_0 = (CPoint*)NTLHandleToObject(ps, thisID, h_arg_0);
            new (_this) CPoint(*arg_0); // TODO: Make sure your C++ class implements the copy-constructor correctly
            NTLFreeHandle(ps, h_arg_0);
            break;
        }
        case fn_Point3: // method Point (int x, int y)
        {
            JILLong arg_0 = NTLGetArgInt(ps, 0);
            JILLong arg_1 = NTLGetArgInt(ps, 1);
            new (_this) CPoint(arg_0, arg_1); // using placement new to instantiate into '_this'
            break;
        }
        case fn_IsInside: // method int IsInside (const Rect r)
        {
            JILHandle* h_arg_0 = NTLGetArgHandle(ps, 0);
            CRect* arg_0 = (CRect*)NTLHandleToObject(ps, NTLTypeNameToTypeID(ps, TYPENAME_System_Drawing_Rect), h_arg_0);
            JILLong result = _this->IsInside(*arg_0);
            NTLReturnInt(ps, result);
            NTLFreeHandle(ps, h_arg_0);
            break;
        }
        case fn_X: // accessor int X ()
        {
            JILLong result = _this->X();
            NTLReturnInt(ps, result);
            break;
        }
        case fn_Y: // accessor int Y ()
        {
            JILLong result = _this->Y();
            NTLReturnInt(ps, result);
            break;
        }
        default:
        {
            error = JIL_ERR_Invalid_Function_Index;
            break;
        }
    }
    return error;
}