/*
 * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
 * http://www.gnu.org/licenses/lgpl-3.0.html
 *
 * $Revision: 12491 $
 * $Id: sc_wxtypes.cpp 12491 2021-08-05 23:50:26Z fuscated $
 * $HeadURL: https://svn.code.sf.net/p/codeblocks/code/trunk/src/sdk/scripting/bindings/sc_wxtypes.cpp $
 */

#include "sdk_precomp.h"
#ifndef CB_PRECOMP
    #include <wx/gdicmn.h>
    #include <wx/intl.h>
    #include <wx/string.h>
#endif

#include "scripting/bindings/sc_utils.h"
#include "scripting/bindings/sc_typeinfo_all.h"

#include <wx/filename.h>

using namespace cb;

namespace ScriptBindings
{

/// The _T() function for scripts.
/// Returns new wxString squirrel instance which wraps the passed string as parameter.
SQInteger static_T(HSQUIRRELVM v)
{
    // The first parameter is a environment table, because this is a global function.
    // We don't care about it, so we skip it.
    ExtractParams2<SkipParam, const SQChar*> extractor(v);
    if (!extractor.Process("_T"))
        return extractor.ErrorMessage();

    return ConstructAndReturnInstance(v, cbC2U(extractor.p1));
}

/// The _() function for scripts
SQInteger static_(HSQUIRRELVM v)
{
    // The first parameter is a environment table, because this is a global function.
    // We don't care about it, so we skip it.
    ExtractParams2<SkipParam, const SQChar*> extractor(v);
    if (!extractor.Process("_T"))
        return extractor.ErrorMessage();

    return ConstructAndReturnInstance(v, wxGetTranslation(cbC2U(extractor.p1)));
}

SQInteger wxString_ctor(HSQUIRRELVM v)
{
    ExtractParamsBase extractor(v);
    if (!extractor.CheckNumArguments(1, 2, "wxString_ctor"))
        return extractor.ErrorMessage();
    const int numArgs = sq_gettop(v);

    if (numArgs == 1) // empty ctor
    {
        UserDataForType<wxString> *data;
        data = SetupUserPointer<wxString, InstanceAllocationMode::InstanceIsInline>(v, 1);
        if (!data)
            return -1; // SetupUserPointer should have called sq_throwerror!
        new (&(data->userdata)) wxString();
        return 0;
    }
    else
    {
        // 1 argument ctor
        const SQObjectType type = sq_gettype(v, 2);
        switch (type)
        {
            case OT_STRING:
            {
                // Construct from Squirrel string
                const SQChar *value = extractor.GetParamString(2);
                cbAssert(value);
                UserDataForType<wxString> *data;
                data = SetupUserPointer<wxString, InstanceAllocationMode::InstanceIsInline>(v, 1);
                if (!data)
                    return -1; // SetupUserPointer should have called sq_throwerror!
                new (&(data->userdata)) wxString(value);
                return 0;
            }
            case OT_INSTANCE:
            {
                // Construct from wxString
                wxString *value;
                if (!extractor.ProcessParam(value, 2, "wxString_ctor"))
                    return extractor.ErrorMessage();
                UserDataForType<wxString> *data;
                data = SetupUserPointer<wxString, InstanceAllocationMode::InstanceIsInline>(v, 1);
                if (!data)
                    return -1; // SetupUserPointer should have called sq_throwerror!
                new (&(data->userdata)) wxString(*value);
                return 0;
            }
            default:
                return sq_throwerror(v, _SC("Unsupported argument type passed to wxString constructor!"));
        }
    }
}

SQInteger wxString_OpAdd(HSQUIRRELVM v)
{
    // TODO: Optional Args
    ExtractParamsBase extractor(v);
    if (!extractor.CheckNumArguments(2, "wxString_OpAdd"))
        return extractor.ErrorMessage();

    // Squirrel doesn't call us, the first parameter is not a wxString.
    const wxString *s1 = nullptr;
    if (!extractor.ProcessParam(s1, 1, "wxString_OpAdd"))
        return extractor.ErrorMessage();

    wxString result = *s1;
    const SQObjectType type2 = sq_gettype(v, 2);
    switch (type2)
    {
        case OT_INSTANCE:
        {
            const wxString *s2 = nullptr;
            if (!extractor.ProcessParam(s2, 2, "wxString_OpAdd"))
                return extractor.ErrorMessage();
            result += *s2;
            break;
        }
        case OT_STRING:
        {
            const SQChar *s2 = nullptr;
            if (!extractor.ProcessParam(s2, 2, "wxString_OpAdd"))
                return extractor.ErrorMessage();
            result << s2;
            break;
        }
        case OT_INTEGER:
        {
            SQInteger s2;
            if (!extractor.ProcessParam(s2, 2, "wxString_OpAdd"))
                return extractor.ErrorMessage();
            result << s2;
            break;
        }
        case OT_FLOAT:
        {
            SQFloat s2;
            if (!extractor.ProcessParam(s2, 2, "wxString_OpAdd"))
                return extractor.ErrorMessage();
            result << s2;
            break;
        }
        default:
            return sq_throwerror(v, _SC("Unknown type"));
    }

    return ConstructAndReturnInstance(v, result);
}

SQInteger wxString_OpCompare(HSQUIRRELVM v)
{
    // TODO: Optional Args
    ExtractParamsBase extractor(v);
    if (!extractor.CheckNumArguments(2, "wxString_OpCompare"))
    {
        extractor.ErrorMessage();
        return false;
    }

    const SQObjectType type1 = sq_gettype(v, 1);
    const SQObjectType type2 = sq_gettype(v, 2);

    if (type1 == OT_STRING && type2 == OT_INSTANCE)
    {
        const SQChar *s1;
        const wxString *s2;
        if (extractor.ProcessParam(s1, 1, "wxString_OpCompare")
            && extractor.ProcessParam(s2, 2, "wxString_OpCompare"))
        {
            wxString temp1(s1);
            sq_pushinteger(v, temp1.Cmp(*s2));
            return 1;
        }
        else
            return extractor.ErrorMessage();
    }

    // At least one of the parameters is a wxString. It is not the seconds, so at least the first
    // one is a wxString.
    const wxString *s1 = nullptr;
    if (!extractor.ProcessParam(s1, 1, "wxString_OpCompare"))
        return extractor.ErrorMessage();

    if (type2 == OT_STRING)
    {
        const SQChar *s2;
        if (!extractor.ProcessParam(s2, 2, "wxString_OpCompare"))
            return extractor.ErrorMessage();
        sq_pushinteger(v, s1->Cmp(wxString(s2)));
        return 1;
    }

    const wxString *s2;
    if (!extractor.ProcessParam(s2, 2, "wxString_OpCompare"))
        return extractor.ErrorMessage();
    sq_pushinteger(v, s1->Cmp(*s2));
    return 1;
}

SQInteger wxString_OpToString(HSQUIRRELVM v)
{
    ExtractParams1<const wxString*> extractor(v);
    if (!extractor.Process("wxString::_tostring"))
        return extractor.ErrorMessage();

    sq_pushstring(v, extractor.p0->utf8_str().data(), -1);
    return 1;
}

SQInteger wxString_Find(HSQUIRRELVM v)
{
    ExtractParams2<const wxString*, const wxString*> extractor(v);
    if (!extractor.Process("wxString_Find"))
        return extractor.ErrorMessage();

    sq_pushinteger(v, extractor.p0->Find(*extractor.p1));
    return 1;
}

SQInteger wxString_Matches(HSQUIRRELVM v)
{
    ExtractParams2<const wxString*, const wxString*> extractor(v);
    if (!extractor.Process("wxString_Matches"))
        return extractor.ErrorMessage();

    sq_pushbool(v, extractor.p0->Matches(*extractor.p1));
    return 1;
}

SQInteger wxString_AddChar(HSQUIRRELVM v)
{
    ExtractParams2<wxString*, SQInteger> extractor(v);
    if (!extractor.Process("wxString_AddChar"))
        return extractor.ErrorMessage();
     char tmp[8];
    snprintf(tmp, 8, "%c", char(extractor.p1));
    *extractor.p0 += cbC2U(tmp);
    return 0;
}

SQInteger wxString_GetChar(HSQUIRRELVM v)
{
    ExtractParams2<const wxString*, SQInteger> extractor(v);
    if (!extractor.Process("wxString_GetChar"))
        return extractor.ErrorMessage();
    if (extractor.p1 < 0 || wxString::size_type(extractor.p1) >= extractor.p0->length())
        return sq_throwerror(v, _SC("wxString_GetChar: Index outside of valid range!"));
    sq_pushinteger(v, extractor.p0->GetChar(extractor.p1));
    return 1;
}

SQInteger wxString_Set(HSQUIRRELVM v)
{
    ExtractParams2<wxString*, const wxString*> extractor(v);
    if (!extractor.Process("wxString_Set"))
        return extractor.ErrorMessage();
    *extractor.p0 = *extractor.p1;
    return 0;
}

SQInteger wxString_IsEmpty(HSQUIRRELVM v)
{
    ExtractParams1<const wxString*> extractor(v);
    if (!extractor.Process("wxString::IsEmpty"))
        return extractor.ErrorMessage();

    sq_pushbool(v, extractor.p0->empty());
    return 1;
}

SQInteger wxString_Length(HSQUIRRELVM v)
{
    ExtractParams1<const wxString*> extractor(v);
    if (!extractor.Process("wxString_Length"))
        return extractor.ErrorMessage();

    sq_pushinteger(v, extractor.p0->Length());
    return 1;
}

using wxStringMakeFunc = wxString& (wxString::*)();

template<wxStringMakeFunc func>
SQInteger wxString_Make(HSQUIRRELVM v)
{
    ExtractParams1<wxString*> extractor(v);
    if (!extractor.Process("wxString_Make"))
        return extractor.ErrorMessage();
    wxString &ref = (extractor.p0->*func)();
    return ConstructAndReturnNonOwnedPtr(v, &ref);
}

using wxStringCaseFunc = wxString (wxString::*)() const;

template<wxStringCaseFunc func>
SQInteger wxString_Case(HSQUIRRELVM v)
{
    ExtractParams1<wxString*> extractor(v);
    if (!extractor.Process("wxString_Case"))
        return extractor.ErrorMessage();

    return ConstructAndReturnInstance(v, (extractor.p0->*func)());
}

using wxStringDoSomethingNoReturnFunc = void (wxString::*)();

template<wxStringDoSomethingNoReturnFunc func>
SQInteger wxString_NoParamNoReturn(HSQUIRRELVM v)
{
    ExtractParams1<wxString*> extractor(v);
    if (!extractor.Process("wxString_NoParamNoReturn"))
        return extractor.ErrorMessage();
    (extractor.p0->*func)();
    return 0;
}

SQInteger wxString_Mid(HSQUIRRELVM v)
{
    ExtractParams3<const wxString*, SQInteger, SQInteger> extractor(v);
    if (!extractor.Process("wxString_Mid"))
        return extractor.ErrorMessage();

    return ConstructAndReturnInstance(v, extractor.p0->Mid(extractor.p1, extractor.p2));
}

SQInteger wxString_Remove(HSQUIRRELVM v)
{
    ExtractParams3<wxString*, SQInteger, SQInteger> extractor(v);
    if (!extractor.Process("wxString_Remove"))
        return extractor.ErrorMessage();
    if (extractor.p1 < 0)
        return sq_throwerror(v, _SC("wxString::Remove: Parameter nStart needs to be non-negative!"));
    if (extractor.p2 < 0)
        return sq_throwerror(v, _SC("wxString::Remove: Parameter nLen needs to be non-negative!"));
    wxString &res = extractor.p0->Remove(extractor.p1, extractor.p2);
    assert(&res == extractor.p0);

    DuplicateInstance(v, 1);

    return 1;
}

SQInteger wxString_RemoveLast(HSQUIRRELVM v)
{
    ExtractParams2<wxString*, SQInteger> extractor(v);
    if (!extractor.Process("wxString_RemoveLast"))
        return extractor.ErrorMessage();
    if (extractor.p1 < 0)
        return sq_throwerror(v, _SC("wxString::RemoveLast: Parameter n needs to be non-negative!"));
    wxString &res = extractor.p0->RemoveLast(extractor.p1);
    assert(&res == extractor.p0);

    DuplicateInstance(v, 1);

    return 1;
}

SQInteger wxString_Replace(HSQUIRRELVM v)
{
    SQInteger result = -1;

    // TODO: Optional Args
    const int numArgs = sq_gettop(v);
    if (numArgs == 3)
    {
        ExtractParams3<wxString*, const wxString*, const wxString*> extractor(v);
        if (!extractor.Process("wxString_Replace"))
            return extractor.ErrorMessage();
        result = extractor.p0->Replace(*extractor.p1, *extractor.p2);
    }
    else if (numArgs == 4)
    {
        ExtractParams4<wxString*, const wxString*, const wxString*, bool> extractor(v);
        if (!extractor.Process("wxString_Replace"))
            return extractor.ErrorMessage();
        result = extractor.p0->Replace(*extractor.p1, *extractor.p2, extractor.p3);
    }

    DuplicateInstance(v, 1);
    sq_pushinteger(v, result);

    return 1;
}

using wxStringLeftRightFunc = wxString (wxString::*)(size_t) const;

template<wxStringLeftRightFunc func>
SQInteger wxString_LeftRight(HSQUIRRELVM v)
{
    ExtractParams2<const wxString*, SQInteger> extractor(v);
    if (!extractor.Process("wxString_LeftRight"))
        return extractor.ErrorMessage();
    if (extractor.p1 < 0)
        return sq_throwerror(v, _SC("wxString_LeftRight: nCount should be non-negative integer!"));

    return ConstructAndReturnInstance(v, (extractor.p0->*func)(extractor.p1));
}

/// Extract parameters for a call to Before/After-First/Last kind of function.
/// The first parameter is this/self wxString.
/// The second parameter is the search character. Currently we support an int (for some kind of
/// ascii, untested), const wxString*, const string. For both kind of strings we extract the first
/// character.
bool SetupFirstLastParams(HSQUIRRELVM v, const wxString *&self, wxUniChar &searchChar)
{
    // TODO: Optional Args
    ExtractParamsBase extractor(v);
    if (!extractor.CheckNumArguments(2, "SetupFirstLastParams"))
    {
        extractor.ErrorMessage();
        return false;
    }

    self = nullptr;
    if (!extractor.ProcessParam(self, 1, "SetupFirstLastParams"))
    {
        extractor.ErrorMessage();
        return false;
    }

    const SQObjectType charParamType = sq_gettype(v, 2);
    switch (charParamType)
    {
    case OT_INTEGER:
        {
            SQInteger temp;
            if (!extractor.ProcessParam(temp, 2, "SetupFirstLastParams"))
            {
                extractor.ErrorMessage();
                return false;
            }
            searchChar = temp;
            return true;
        }
    case OT_INSTANCE:
        {
            const wxString *search = nullptr;
            if (!extractor.ProcessParam(search, 2, "SetupFirstLastParams"))
            {
                extractor.ErrorMessage();
                return false;
            }
            if (search->length() < 1)
            {
                sq_throwerror(v, _SC("SetupFirstLastParams: String length too short!"));
                return false;
            }
            searchChar = search->GetChar(0);
            return true;
        }
    case OT_STRING:
        {
            const SQChar *search = nullptr;
            if (!extractor.ProcessParam(search, 2, "SetupFirstLastParams"))
            {
                extractor.ErrorMessage();
                return false;
            }
            if (search && search[0] != _SC('\0'))
                searchChar = search[0];
            else
            {
                sq_throwerror(v, _SC("SetupFirstLastParams: Invalid searchChar parameter!"));
                return false;
            }
            return true;
        }
    default:
        sq_throwerror(v, _SC("SetupFirstLastParams: Invalid searchChar parameter!"));
        return false;
    }
}

using wxStringDoAfterFirstLastFunc = wxString (wxString::*)(wxUniChar) const;

template<wxStringDoAfterFirstLastFunc func>
SQInteger wxString_DoAfterFirstLast(HSQUIRRELVM v)
{
    const wxString *self;
    wxUniChar searchChar;
    if (!SetupFirstLastParams(v, self, searchChar))
        return -1; // An error should have been logged already.

    return ConstructAndReturnInstance(v, (self->*func)(searchChar));
}

using wxStringDoBeforeFirstLastFunc = wxString (wxString::*)(wxUniChar, wxString *) const;

template<wxStringDoBeforeFirstLastFunc func>
SQInteger wxString_DoBeforeFirstLast(HSQUIRRELVM v)
{
    const wxString *self;
    wxUniChar searchChar;
    if (!SetupFirstLastParams(v, self, searchChar))
        return -1; // An error should have been logged already.

    return ConstructAndReturnInstance(v, (self->*func)(searchChar, nullptr));
}

SQInteger wxString_ToLong(HSQUIRRELVM v)
{
    // env table, string
    ExtractParams2<SkipParam, const wxString*> extractor(v);
    if (!extractor.Process("wxString_ToLong"))
        return extractor.ErrorMessage();

    long value;
    if (!extractor.p1->ToLong(&value))
        value = -1;
    sq_pushinteger(v, value);
    return 1;
}

SQInteger wxColour_ctor(HSQUIRRELVM v)
{
    ExtractParamsBase extractor(v);
    if (!extractor.CheckNumArguments(1, 5, "wxColour_ctor"))
        return extractor.ErrorMessage();

    const int numArgs = sq_gettop(v);
    switch (numArgs)
    {
        case 1: // empty ctor
        {
            UserDataForType<wxColour> *data;
            data = SetupUserPointer<wxColour, InstanceAllocationMode::InstanceIsInline>(v, 1);
            if (!data)
                return -1; // SetupUserPointer should have called sq_throwerror!
            new (&(data->userdata)) wxColour();
            return 0;
        }
        case 4: // 3 ints
        {
            // env table, red, green, blue
            ExtractParams4<SkipParam, SQInteger, SQInteger, SQInteger> extractor(v);
            if (!extractor.Process("wxColour_ctor(3 ints)"))
                return extractor.ErrorMessage();
            UserDataForType<wxColour> *data;
            data = SetupUserPointer<wxColour, InstanceAllocationMode::InstanceIsInline>(v, 1);
            if (!data)
                return -1; // SetupUserPointer should have called sq_throwerror!
            new (&(data->userdata)) wxColour(extractor.p1, extractor.p2, extractor.p3);
            return 0;
        }
        case 5: // 4 ints
        {
            // env table, red, green, blue, alpha
            ExtractParams5<SkipParam, SQInteger, SQInteger, SQInteger, SQInteger> extractor(v);
            if (!extractor.Process("wxColour_ctor(4 ints)"))
                return extractor.ErrorMessage();
            UserDataForType<wxColour> *data;
            data = SetupUserPointer<wxColour, InstanceAllocationMode::InstanceIsInline>(v, 1);
            if (!data)
                return -1; // SetupUserPointer should have called sq_throwerror!
            new (&(data->userdata)) wxColour(extractor.p1, extractor.p2, extractor.p3, extractor.p4);
            return 0;
        }
        default:
            return sq_throwerror(v, _SC("Unsupported number of arguments passed wxString()!"));
    }
}


SQInteger wxColour_Set(HSQUIRRELVM v)
{
    // this, red, green, blue, alpha
    ExtractParams5<wxColour*, SQInteger, SQInteger, SQInteger, SQInteger> extractor(v);
    if (!extractor.Process("wxColour_Set"))
        return extractor.ErrorMessage();
    extractor.p0->Set(extractor.p1, extractor.p2, extractor.p3, extractor.p4);
    return 0;
}

SQInteger wxColour_IsOk(HSQUIRRELVM v)
{
    ExtractParams1<const wxColour*> extractor(v);
    if (!extractor.Process("wxColour_IsOk"))
        return extractor.ErrorMessage();
    sq_pushbool(v, extractor.p0->IsOk());

    return 1;
}

SQInteger wxColour_ToString(HSQUIRRELVM v)
{
    ExtractParams1<const wxColour*> extractor(v);
    if (!extractor.Process("wxColour_ToString"))
        return extractor.ErrorMessage();

    SQChar buf[100];
    scsprintf(buf, 100, _SC("[r=%d, g=%d, b=%d, a=%d]"), extractor.p0->Red(), extractor.p0->Green(),
              extractor.p0->Blue(), extractor.p0->Alpha());
    sq_pushstring(v, buf, -1);
    return 1;
}

SQInteger wxPoint_get(HSQUIRRELVM v)
{
    ExtractParams2<const wxPoint*, const SQChar*> extractor(v);
    if (!extractor.Process("wxPoint_get"))
        return extractor.ErrorMessage();

    const SQChar *fieldName = extractor.p1;
    if (scstrcmp(fieldName, _SC("x")) == 0)
    {
        sq_pushinteger(v, extractor.p0->x);
        return 1;
    }
    if (scstrcmp(fieldName, _SC("y")) == 0)
    {
        sq_pushinteger(v, extractor.p0->y);
        return 1;
    }
    return sq_throwerror(v, _SC("wxPoint_get: Unknown field"));
}

SQInteger wxPoint_set(HSQUIRRELVM v)
{
    ExtractParams3<wxPoint*, const SQChar*, SQInteger> extractor(v);
    if (!extractor.Process("wxPoint_set"))
        return extractor.ErrorMessage();

    const SQChar *fieldName = extractor.p1;
    if (scstrcmp(fieldName, _SC("x")) == 0)
    {
        extractor.p0->x = extractor.p2;
        return 0;
    }
    if (scstrcmp(fieldName, _SC("y")) == 0)
    {
        extractor.p0->y = extractor.p2;
        return 0;
    }
    return sq_throwerror(v, _SC("wxPoint_set: Unknown field"));
}

SQInteger wxPoint_cmp(HSQUIRRELVM v)
{
    ExtractParams2<const wxPoint*, const wxPoint*> extractor(v);
    if (!extractor.Process("wxPoint_cmp"))
        return extractor.ErrorMessage();

    int res;
    if (extractor.p0->x < extractor.p1->x)
        res = -1;
    else if (extractor.p0->x > extractor.p1->x)
        res = 1;
    else
    {
        if (extractor.p0->y < extractor.p1->y)
            res = -1;
        else if (extractor.p0->y > extractor.p1->y)
            res = 1;
        else
            res = 0;
    }
    sq_pushinteger(v, res);
    return 1;
}

template<typename Type>
SQInteger wxPointSize_tostring(HSQUIRRELVM v)
{
    ExtractParams1<const Type*> extractor(v);
    if (!extractor.Process("wxPointSize_tostring"))
        return extractor.ErrorMessage();

    SQChar buf[100];
    scsprintf(buf, 100, _SC("[%d,%d]"), extractor.p0->x, extractor.p0->y);
    sq_pushstring(v, buf, -1);
    return 1;
}

SQInteger wxSize_Set(HSQUIRRELVM v)
{
    ExtractParams3<wxSize*, SQInteger, SQInteger> extractor(v);
    if (!extractor.Process("wxSize_Set"))
        return extractor.ErrorMessage();
    extractor.p0->Set(extractor.p1, extractor.p2);
    return 0;
}

template<void (wxSize::*func)(int)>
SQInteger wxSize_SetWidthHeight(HSQUIRRELVM v)
{
    ExtractParams2<wxSize*, SQInteger> extractor(v);
    if (!extractor.Process("wxSize_SetWidthHeight"))
        return extractor.ErrorMessage();
    (extractor.p0->*func)(extractor.p1);
    return 0;
}

SQInteger wxArrayString_Add(HSQUIRRELVM v)
{
    ExtractParams3<wxArrayString*, const wxString*, SQInteger> extractor(v);
    if (!extractor.Process("wxArrayString_Add"))
        return extractor.ErrorMessage();
    sq_pushinteger(v, extractor.p0->Add(*extractor.p1, extractor.p2));
    return 1;
}

SQInteger wxArrayString_Clear(HSQUIRRELVM v)
{
    ExtractParams1<wxArrayString*> extractor(v);
    if (!extractor.Process("wxArrayString_Clear"))
        return extractor.ErrorMessage();
    extractor.p0->Clear();
    return 0;
}

SQInteger wxArrayString_Index(HSQUIRRELVM v)
{
    // TODO: Optional Args
    ExtractParamsBase extractor(v);
    if (!extractor.CheckNumArguments(2, 4, "wxArrayString_Index"))
        return extractor.ErrorMessage();

    wxArrayString *self = nullptr;
    if (!extractor.ProcessParam(self, 1, "wxArrayString_Index"))
        return extractor.ErrorMessage();

    const wxString *str = nullptr;
    if (!extractor.ProcessParam(str, 2, "wxArrayString_Index"))
        return extractor.ErrorMessage();

    bool bCase = true;
    bool bFromEnd = false;
    const int numArgs = sq_gettop(v);
    if (numArgs >= 3)
    {
        if (!extractor.ProcessParam(bCase, 3, "wxArrayString_Index"))
            return extractor.ErrorMessage();
    }
    if (numArgs == 4)
    {
        if (!extractor.ProcessParam(bFromEnd, 4, "wxArrayString_Index"))
            return extractor.ErrorMessage();
    }

    sq_pushinteger(v, self->Index(*str, bCase, bFromEnd));
    return 1;
}

SQInteger wxArrayString_GetCount(HSQUIRRELVM v)
{
    ExtractParams1<const wxArrayString*> extractor(v);
    if (!extractor.Process("wxArrayString_GetCount"))
        return extractor.ErrorMessage();
    sq_pushinteger(v, extractor.p0->GetCount());
    return 1;
}

SQInteger wxArrayString_Item(HSQUIRRELVM v)
{
    ExtractParams2<wxArrayString*, SQInteger> extractor(v);
    if (!extractor.Process("wxArrayString_Item"))
        return extractor.ErrorMessage();
    const SQInteger index = extractor.p1;
    if (index < 0 || size_t(index) >= extractor.p0->GetCount())
        return sq_throwerror(v, _SC("wxArrayString_Item: index out of bounds!"));

    // Create an instance for the return value.
    wxString *ref = &((*extractor.p0)[index]);
    return ConstructAndReturnNonOwnedPtr(v, ref);
}

SQInteger wxArrayString_SetItem(HSQUIRRELVM v)
{
    ExtractParams3<wxArrayString*, SQInteger, const wxString*> extractor(v);
    if (!extractor.Process("wxArrayString_SetItem"))
        return extractor.ErrorMessage();

    const SQInteger index = extractor.p1;
    if (index < 0 || size_t(index) >= extractor.p0->GetCount())
        return sq_throwerror(v, _SC("wxArrayString_SetItem: index out of bounds!"));

    (*extractor.p0)[index] = *extractor.p2;
    return 0;
}

SQInteger wxFileName_Assign(HSQUIRRELVM v)
{
    ExtractParams3<wxFileName*, const wxString *, SQInteger> extractor(v);
    if (!extractor.Process("wxFileName_Assign"))
        return extractor.ErrorMessage();

    if (extractor.p2 < wxPATH_NATIVE || extractor.p2 >= wxPATH_MAX)
        return sq_throwerror(v, _SC("wxFileName_Assign: format out of range!"));

    extractor.p0->Assign(*extractor.p1, wxPathFormat(extractor.p2));
    return 0;
}

template<void (wxFileName::*func)(const wxString&)>
SQInteger wxFileName_SetWxString(HSQUIRRELVM v)
{
    ExtractParams2<wxFileName*, const wxString *> extractor(v);
    if (!extractor.Process("wxFileName_SetWxString"))
        return extractor.ErrorMessage();
    (extractor.p0->*func)(*extractor.p1);
    return 0;
}

SQInteger wxFileName_AssignDir(HSQUIRRELVM v)
{
    ExtractParams3<wxFileName*, const wxString *, SQInteger> extractor(v);
    if (!extractor.Process("wxFileName_AssignDir"))
        return extractor.ErrorMessage();

    if (extractor.p2 < wxPATH_NATIVE || extractor.p2 >= wxPATH_MAX)
        return sq_throwerror(v, _SC("wxFileName_Assign: format out of range!"));

    extractor.p0->AssignDir(*extractor.p1, wxPathFormat(extractor.p2));
    return 0;
}

template<void (wxFileName::*func)()>
SQInteger wxFileName_Action(HSQUIRRELVM v)
{
    ExtractParams1<wxFileName*> extractor(v);
    if (!extractor.Process("wxFileName_Action"))
        return extractor.ErrorMessage();
    (extractor.p0->*func)();
    return 0;
}

SQInteger wxFileName_GetCwd(HSQUIRRELVM v)
{
    ExtractParams2<SkipParam, const wxString *> extractor(v);
    if (!extractor.Process("wxFileName_GetCwd"))
        return extractor.ErrorMessage();

    return ConstructAndReturnInstance(v, wxFileName::GetCwd(*extractor.p1));
}

SQInteger wxFileName_tostring(HSQUIRRELVM v)
{
    ExtractParams1<const wxFileName*> extractor(v);
    if (!extractor.Process("wxFileName_tostring"))
        return extractor.ErrorMessage();
    sq_pushstring(v, (const SQChar*)extractor.p0->GetFullPath().mb_str(wxConvUTF8), -1);
    return 1;
}

SQInteger wxFileName_GetDirs(HSQUIRRELVM v)
{
    ExtractParams1<const wxFileName*> extractor(v);
    if (!extractor.Process("wxFileName_GetDirs"))
        return extractor.ErrorMessage();

    // FIXME (squirrel) This doesn't matter much, because squirrel doesn't care for constness.
    wxArrayString *dirs = &const_cast<wxArrayString&>(extractor.p0->GetDirs());
    return ConstructAndReturnNonOwnedPtr(v, dirs);
}

/// TODO: Probably simplify by removing the generic ClassType support.
template<typename ReturnType, typename ClassType, ReturnType (ClassType::*func)() const>
SQInteger NoParamReturnWxString(HSQUIRRELVM v)
{
    ExtractParams1<const ClassType*> extractor(v);
    if (!extractor.Process("NoParamReturnWxString"))
        return extractor.ErrorMessage();

    return ConstructAndReturnInstance(v, (extractor.p0->*func)());
}

SQInteger wxFileName_GetFullPath(HSQUIRRELVM v)
{
    ExtractParams2<const wxFileName*, SQInteger> extractor(v);
    if (!extractor.Process("wxFileName_GetFullPath"))
        return extractor.ErrorMessage();

    if (extractor.p1 < wxPATH_NATIVE || extractor.p1 >= wxPATH_MAX)
        return sq_throwerror(v, _SC("wxFileName_GetFullPath: format out of range!"));

    return ConstructAndReturnInstance(v, extractor.p0->GetFullPath(wxPathFormat(extractor.p1)));
}

SQInteger wxFileName_GetPath(HSQUIRRELVM v)
{
    ExtractParams3<const wxFileName*, SQInteger, SQInteger> extractor(v);
    if (!extractor.Process("wxFileName_GetPath"))
        return extractor.ErrorMessage();

    if (extractor.p2 < wxPATH_NATIVE || extractor.p2 >= wxPATH_MAX)
        return sq_throwerror(v, _SC("wxFileName_GetPath: format out of range!"));

    return ConstructAndReturnInstance(v, extractor.p0->GetPath(int(extractor.p1),
                                                               wxPathFormat(extractor.p2)));
}

SQInteger wxFileName_InsertDir(HSQUIRRELVM v)
{
    ExtractParams3<wxFileName*, SQInteger, const wxString *> extractor(v);
    if (!extractor.Process("wxFileName_InsertDir"))
        return extractor.ErrorMessage();

    if (extractor.p1 < 0)
        return sq_throwerror(v, _SC("wxFileName_InsertDir: parameter before must be non-negative!"));

    sq_pushbool(v, extractor.p0->InsertDir(extractor.p1, *extractor.p2));
    return 1;
}

template<bool (wxFileName::*func)(wxPathFormat) const>
SQInteger wxFileName_Is(HSQUIRRELVM v)
{
    /// TODO: Consider adding a modifier which checks for wxPathFormat range.
    ExtractParams2<const wxFileName*, SQInteger> extractor(v);
    if (!extractor.Process("wxFileName_Is"))
        return extractor.ErrorMessage();

    if (extractor.p1 < wxPATH_NATIVE || extractor.p1 >= wxPATH_MAX)
        return sq_throwerror(v, _SC("wxFileName_Is: format out of range!"));

    sq_pushbool(v, (extractor.p0->*func)(wxPathFormat(extractor.p1)));
    return 1;
}

template<bool (wxFileName::*func)() const>
SQInteger wxFileName_ReturnBool(HSQUIRRELVM v)
{
    ExtractParams1<const wxFileName*> extractor(v);
    if (!extractor.Process("wxFileName_ReturnBool"))
        return extractor.ErrorMessage();
    sq_pushbool(v, (extractor.p0->*func)());
    return 1;
}

template<bool (wxFileName::*func)(const wxString &, wxPathFormat)>
SQInteger wxFileName_Make(HSQUIRRELVM v)
{
    /// TODO: Consider adding a modifier which checks for wxPathFormat range.
    ExtractParams3<wxFileName*, const wxString *, SQInteger> extractor(v);
    if (!extractor.Process("wxFileName_Make"))
        return extractor.ErrorMessage();

    if (extractor.p2 < wxPATH_NATIVE || extractor.p2 >= wxPATH_MAX)
        return sq_throwerror(v, _SC("wxFileName_Make: format out of range!"));

    sq_pushbool(v, (extractor.p0->*func)(*extractor.p1, wxPathFormat(extractor.p2)));
    return 1;
}

SQInteger wxFileName_Normalize(HSQUIRRELVM v)
{
    /// TODO: Consider adding a modifier which checks for wxPathFormat range.
    ExtractParams4<wxFileName*, SQInteger, const wxString *, SQInteger> extractor(v);
    if (!extractor.Process("wxFileName_MakeRelativeTo"))
        return extractor.ErrorMessage();

    if (extractor.p3 < wxPATH_NATIVE || extractor.p3 >= wxPATH_MAX)
        return sq_throwerror(v, _SC("wxFileName_MakeRelativeTo: format out of range!"));

    sq_pushbool(v, extractor.p0->Normalize(extractor.p1, *extractor.p2,
                                           wxPathFormat(extractor.p3)));
    return 1;
}

SQInteger wxFileName_AppendDir(HSQUIRRELVM v)
{
    ExtractParams2<wxFileName*, const wxString *> extractor(v);
    if (!extractor.Process("wxFileName_AppendDir"))
        return extractor.ErrorMessage();
    sq_pushbool(v, extractor.p0->AppendDir(*extractor.p1));
    return 1;
}

SQInteger wxFileName_RemoveDir(HSQUIRRELVM v)
{
    ExtractParams2<wxFileName*, SQInteger> extractor(v);
    if (!extractor.Process("wxFileName_RemoveDir"))
        return extractor.ErrorMessage();
    extractor.p0->RemoveDir(extractor.p1);
    return 0;
}

SQInteger wxFileName_RemoveLastDir(HSQUIRRELVM v)
{
    ExtractParams1<wxFileName*> extractor(v);
    if (!extractor.Process("wxFileName_RemoveLastDir"))
        return extractor.ErrorMessage();
    extractor.p0->RemoveLastDir();
    return 0;
}

SQInteger wxFileName_SameAs(HSQUIRRELVM v)
{
    ExtractParams3<wxFileName*, const wxFileName*, SQInteger> extractor(v);
    if (!extractor.Process("wxFileName_SameAs"))
        return extractor.ErrorMessage();

    if (extractor.p2 < wxPATH_NATIVE || extractor.p2 >= wxPATH_MAX)
        return sq_throwerror(v, _SC("wxFileName_MakeRelativeTo: format out of range!"));

    sq_pushbool(v, extractor.p0->SameAs(*extractor.p1, wxPathFormat(extractor.p2)));
    return 1;
}

void Register_wxTypes(HSQUIRRELVM v)
{
    PreserveTop preserveTop(v);
    sq_pushroottable(v);
    {
        // register wxString
        const SQInteger classDecl = CreateClassDecl<wxString>(v);
        BindMethod(v, _SC("constructor"), wxString_ctor, _SC("wxString::constructor"));
        BindDefaultClone<wxString>(v);
        BindMethod(v, _SC("_add"), wxString_OpAdd, _SC("wxString::operator+"));
        BindMethod(v, _SC("_cmp"), wxString_OpCompare, _SC("wxString::operator=="));
        BindMethod(v, _SC("Compare"), wxString_OpCompare, _SC("wxString::Compare"));
        BindMethod(v, _SC("_tostring"), wxString_OpToString, _SC("wxString::_tostring"));
        BindMethod(v, _SC("Find"), wxString_Find, _SC("wxString::Find"));
        BindMethod(v, _SC("Matches"), wxString_Matches, _SC("wxString::Matches"));
        BindMethod(v, _SC("AddChar"), wxString_AddChar, _SC("wxString::AddChar"));
        BindMethod(v, _SC("GetChar"), wxString_GetChar, _SC("wxString::GetChar"));
        BindMethod(v, _SC("Set"), wxString_Set, _SC("wxString::Set"));
        BindMethod(v, _SC("IsEmpty"), wxString_IsEmpty, _SC("wxString::IsEmpty"));
        BindMethod(v, _SC("Length"), wxString_Length, _SC("wxString::Length"));
        BindMethod(v, _SC("length"), wxString_Length, _SC("wxString::length"));
        BindMethod(v, _SC("len"), wxString_Length, _SC("wxString::len"));
        BindMethod(v, _SC("size"), wxString_Length, _SC("wxString::size"));

        BindMethod(v, _SC("Lower"), wxString_Case<&wxString::Lower>,
                   _SC("wxString::Lower"));
        BindMethod(v, _SC("MakeLower"), wxString_Make<&wxString::MakeLower>,
                   _SC("wxString::MakeLower"));
        BindMethod(v, _SC("LowerCase"), wxString_NoParamNoReturn<&wxString::LowerCase>,
                   _SC("wxString::LowerCase"));

        BindMethod(v, _SC("Upper"), wxString_Case<&wxString::Upper>,
                   _SC("wxString::Upper"));
        BindMethod(v, _SC("MakeUpper"), wxString_Make<&wxString::MakeUpper>,
                   _SC("wxString::MakeUpper"));
        BindMethod(v, _SC("UpperCase"), wxString_NoParamNoReturn<&wxString::UpperCase>,
                   _SC("wxString::UpperCase"));

        BindMethod(v, _SC("Mid"), wxString_Mid, _SC("wxString::Mid"));
        BindMethod(v, _SC("Remove"), wxString_Remove, _SC("wxString::Remove"));
        BindMethod(v, _SC("RemoveLast"), wxString_RemoveLast, _SC("wxString::RemoveLast"));
        BindMethod(v, _SC("Replace"), wxString_Replace, _SC("wxString::Replace"));
        BindMethod(v, _SC("Left"), wxString_LeftRight<&wxString::Left>, _SC("wxString::Left"));
        BindMethod(v, _SC("Right"), wxString_LeftRight<&wxString::Right>, _SC("wxString::Right"));

        BindMethod(v, _SC("AfterFirst"), wxString_DoAfterFirstLast<&wxString::AfterFirst>,
                   _SC("wxString::AfterFirst"));
        BindMethod(v, _SC("AfterLast"), wxString_DoAfterFirstLast<&wxString::AfterLast>,
                   _SC("wxString::AfterLast"));
        BindMethod(v, _SC("BeforeFirst"), wxString_DoBeforeFirstLast<&wxString::BeforeFirst>,
                   _SC("wxString::BeforeFirst"));
        BindMethod(v, _SC("BeforeLast"), wxString_DoBeforeFirstLast<&wxString::BeforeLast>,
                   _SC("wxString::BeforeLast"));

        sq_newslot(v, classDecl, SQFalse); // Put the class in the root table. This must be last!
    }

    BindMethod(v, _SC("_T"), static_T, nullptr);
    BindMethod(v, _SC("_"), static_, nullptr);
    BindMethod(v, _SC("wxString_ToLong"), wxString_ToLong, nullptr);

    {
        // Register wxColour
        const SQInteger classDecl = CreateClassDecl<wxColour>(v);
        BindMethod(v, _SC("constructor"), wxColour_ctor, _SC("wxColour::constructor"));
        BindDefaultClone<wxColour>(v);

        BindMethod(v, _SC("_tostring"), wxColour_ToString, _SC("wxColour::_tostring"));
        BindMethod(v, _SC("Blue"), NoParamGetterInt<wxColour::ChannelType, wxColour, &wxColour::Blue>, _SC("wxColour::Blue"));
        BindMethod(v, _SC("Green"), NoParamGetterInt<wxColour::ChannelType, wxColour, &wxColour::Green>, _SC("wxColour::Green"));
        BindMethod(v, _SC("Red"), NoParamGetterInt<wxColour::ChannelType, wxColour, &wxColour::Red>, _SC("wxColour::Red"));
        BindMethod(v, _SC("Alpha"), NoParamGetterInt<wxColour::ChannelType, wxColour, &wxColour::Alpha>, _SC("wxColour::Alpha"));
        BindMethod(v, _SC("IsOk"), wxColour_IsOk, _SC("wxColour::IsOk"));
        BindMethod(v, _SC("Set"), wxColour_Set, _SC("wxColour::Set"));

        sq_newslot(v, classDecl, SQFalse); // Put the class in the root table. This must be last!
    }

    {
        // Register wxPoint
        const SQInteger classDecl = CreateClassDecl<wxPoint>(v);
        BindEmptyCtor<wxPoint>(v);
        BindDefaultClone<wxPoint>(v);
        BindMethod(v, _SC("_tostring"), wxPointSize_tostring<wxPoint>, _SC("wxPoint::_tostring"));
        BindMethod(v, _SC("_cmp"), wxPoint_cmp, _SC("wxPoint::_cmp"));
        BindMethod(v, _SC("_get"), wxPoint_get, _SC("wxPoint::_get"));
        BindMethod(v, _SC("_set"), wxPoint_set, _SC("wxPoint::_set"));

        sq_newslot(v, classDecl, SQFalse); // Put the class in the root table. This must be last!
    }

    {
        // Register wxSize
        const SQInteger classDecl = CreateClassDecl<wxSize>(v);
        BindEmptyCtor<wxSize>(v);
        BindDefaultClone<wxSize>(v);
        BindMethod(v, _SC("_tostring"), wxPointSize_tostring<wxSize>, _SC("wxSize::_tostring"));
        BindMethod(v, _SC("GetWidth"), NoParamGetterInt<int, wxSize, &wxSize::GetWidth>,
                   _SC("wxSize::GetWidth"));
        BindMethod(v, _SC("GetHeight"), NoParamGetterInt<int, wxSize, &wxSize::GetHeight>,
                   _SC("wxSize::GetHeight"));
        BindMethod(v, _SC("Set"), wxSize_Set, _SC("wxSize::Set"));
        BindMethod(v, _SC("SetHeight"), wxSize_SetWidthHeight<&wxSize::SetHeight>,
                   _SC("wxSize::SetHeight"));
        BindMethod(v, _SC("SetWidth"), wxSize_SetWidthHeight<&wxSize::SetWidth>,
                   _SC("wxSize::SetWidth"));

        sq_newslot(v, classDecl, SQFalse); // Put the class in the root table. This must be last!
    }

    {
        // Register wxSize
        const SQInteger classDecl = CreateClassDecl<wxArrayString>(v);
        BindEmptyCtor<wxArrayString>(v);
        BindDefaultClone<wxArrayString>(v);
        BindMethod(v, _SC("Add"), wxArrayString_Add, _SC("wxArrayString::Add"));
        BindMethod(v, _SC("Clear"), wxArrayString_Clear, _SC("wxArrayString::Clear"));
        BindMethod(v, _SC("Index"), wxArrayString_Index, _SC("wxArrayString::Index"));
        BindMethod(v, _SC("GetCount"), wxArrayString_GetCount, _SC("wxArrayString::GetCount"));
        BindMethod(v, _SC("Item"), wxArrayString_Item, _SC("wxArrayString::Item"));
        BindMethod(v, _SC("SetItem"), wxArrayString_SetItem, _SC("wxArrayString::SetItem"));

        sq_newslot(v, classDecl, SQFalse); // Put the class in the root table. This must be last!
    }

    {
        // Register wxFileName
        const SQInteger classDecl = CreateClassDecl<wxFileName>(v);
        BindEmptyCtor<wxFileName>(v);
        BindDefaultClone<wxFileName>(v);
        BindMethod(v, _SC("_tostring"), wxFileName_tostring, _SC("wxFileName::_tostring"));
        BindMethod(v, _SC("Assign"), wxFileName_Assign, _SC("wxFileName::Assign"));
        BindMethod(v, _SC("AssignCwd"), wxFileName_SetWxString<&wxFileName::AssignCwd>,
                   _SC("wxFileName::AssignCwd"));
        BindMethod(v, _SC("AssignDir"), wxFileName_AssignDir, _SC("wxFileName::AssignDir"));
        BindMethod(v, _SC("AssignHomeDir"), wxFileName_Action<&wxFileName::AssignHomeDir>,
                   _SC("wxFileName::AssignHomeDir"));
        BindMethod(v, _SC("Clear"), wxFileName_Action<&wxFileName::Clear>, _SC("wxFileName::Clear"));
        BindMethod(v, _SC("ClearExt"), wxFileName_Action<&wxFileName::ClearExt>, _SC("wxFileName::ClearExt"));
        BindStaticMethod(v, _SC("GetCwd"), wxFileName_GetCwd, _SC("wxFileName::GetCwd"));
        BindMethod(v, _SC("GetDirCount"),
                   NoParamGetterInt<size_t, wxFileName, &wxFileName::GetDirCount>,
                   _SC("wxFileName::GetDirCount"));
        BindMethod(v, _SC("GetDirs"), wxFileName_GetDirs, _SC("wxFileName::GetDirs"));
        BindMethod(v, _SC("GetExt"),
                   NoParamReturnWxString<wxString, wxFileName, &wxFileName::GetExt>,
                   _SC("wxFileName::GetExt"));
        BindMethod(v, _SC("GetFullName"),
                   NoParamReturnWxString<wxString, wxFileName, &wxFileName::GetFullName>,
                   _SC("wxFileName::GetFullName"));
        BindMethod(v, _SC("GetFullPath"), wxFileName_GetFullPath, _SC("wxFileName::GetFullPath"));
        BindMethod(v, _SC("GetLongPath"),
                   NoParamReturnWxString<wxString, wxFileName, &wxFileName::GetLongPath>,
                   _SC("wxFileName::GetLongPath"));
        BindMethod(v, _SC("GetName"),
                   NoParamReturnWxString<wxString, wxFileName, &wxFileName::GetName>,
                   _SC("wxFileName::GetName"));
        BindMethod(v, _SC("GetPath"), wxFileName_GetPath, _SC("wxFileName::GetPath"));
        BindMethod(v, _SC("GetShortPath"),
                   NoParamReturnWxString<wxString, wxFileName, &wxFileName::GetShortPath>,
                   _SC("wxFileName::GetShortPath"));
        BindMethod(v, _SC("GetVolume"),
                   NoParamReturnWxString<wxString, wxFileName, &wxFileName::GetVolume>,
                   _SC("wxFileName::GetVolume"));
        BindMethod(v, _SC("HasExt"), wxFileName_ReturnBool<&wxFileName::HasExt>,
                   _SC("wxFileName::HasExt"));
        BindMethod(v, _SC("HasName"), wxFileName_ReturnBool<&wxFileName::HasName>,
                   _SC("wxFileName::HasName"));
        BindMethod(v, _SC("HasVolume"), wxFileName_ReturnBool<&wxFileName::HasVolume>,
                   _SC("wxFileName::HasVolume"));
        BindMethod(v, _SC("InsertDir"), wxFileName_InsertDir, _SC("wxFileName::InsertDir"));
        BindMethod(v, _SC("IsAbsolute"), wxFileName_Is<&wxFileName::IsAbsolute>,
                   _SC("wxFileName::IsAbsolute"));
        BindMethod(v, _SC("IsOk"), wxFileName_ReturnBool<&wxFileName::IsOk>,
                   _SC("wxFileName::IsOk"));
        BindMethod(v, _SC("IsRelative"), wxFileName_Is<&wxFileName::IsRelative>,
                   _SC("wxFileName::IsRelative"));
        BindMethod(v, _SC("IsDir"), wxFileName_ReturnBool<&wxFileName::IsDir>,
                   _SC("wxFileName::IsDir"));
        BindMethod(v, _SC("MakeAbsolute"), wxFileName_Make<&wxFileName::MakeAbsolute>,
                   _SC("wxFileName::MakeAbsolute"));
        BindMethod(v, _SC("MakeRelativeTo"), wxFileName_Make<&wxFileName::MakeRelativeTo>,
                   _SC("wxFileName::MakeRelativeTo"));
        BindMethod(v, _SC("Normalize"), wxFileName_Normalize, _SC("wxFileName::Normalize"));
        BindMethod(v, _SC("AppendDir"), wxFileName_AppendDir, _SC("wxFileName::AppendDir"));
        BindMethod(v, _SC("PrependDir"), wxFileName_SetWxString<&wxFileName::PrependDir>,
                   _SC("wxFileName::PrependDir"));
        BindMethod(v, _SC("RemoveDir"), wxFileName_RemoveDir, _SC("wxFileName::RemoveDir"));
        BindMethod(v, _SC("RemoveLastDir"), wxFileName_RemoveLastDir,
                   _SC("wxFileName::RemoveLastDir"));
        BindMethod(v, _SC("SameAs"), wxFileName_SameAs, _SC("wxFileName::SameAs"));
        BindMethod(v, _SC("SetCwd"), wxFileName_ReturnBool<&wxFileName::SetCwd>,
                   _SC("wxFileName::SetCwd"));
        BindMethod(v, _SC("SetExt"), wxFileName_SetWxString<&wxFileName::SetExt>,
                   _SC("wxFileName::SetExt"));
        BindMethod(v, _SC("SetEmptyExt"), wxFileName_Action<&wxFileName::SetEmptyExt>, _SC("wxFileName::SetEmptyExt"));
        BindMethod(v, _SC("SetFullName"), wxFileName_SetWxString<&wxFileName::SetFullName>,
                   _SC("wxFileName::SetFullName"));
        BindMethod(v, _SC("SetName"), wxFileName_SetWxString<&wxFileName::SetName>,
                   _SC("wxFileName::SetName"));
        BindMethod(v, _SC("SetVolume"), wxFileName_SetWxString<&wxFileName::SetVolume>,
                   _SC("wxFileName::SetVolume"));

        BindMethod(v, _SC("IsFileWritable"), wxFileName_ReturnBool<&wxFileName::IsFileWritable>,
                   _SC("wxFileName::IsFileWritable"));
        BindMethod(v, _SC("IsFileReadable"), wxFileName_ReturnBool<&wxFileName::IsFileReadable>,
                   _SC("wxFileName::IsFileReadable"));
        BindMethod(v, _SC("IsFileExecutable"), wxFileName_ReturnBool<&wxFileName::IsFileExecutable>,
                   _SC("wxFileName::IsFileExecutable"));

        BindMethod(v, _SC("IsDirWritable"), wxFileName_ReturnBool<&wxFileName::IsDirWritable>,
                   _SC("wxFileName::IsDirWritable"));
        BindMethod(v, _SC("IsDirReadable"), wxFileName_ReturnBool<&wxFileName::IsDirReadable>,
                   _SC("wxFileName::IsDirReadable"));

        sq_newslot(v, classDecl, SQFalse); // Put the class in the root table. This must be last!
    }

    sq_pop(v, 1); // Pop root table.
}

} // namespace ScriptBindings
