#include <stdarg.h> 
#include <stdio.h>
#if 0
#include <string>

#define SQPLUS_SUPPORT_SQ_STD_STRING
#endif

#include "sqplus.h"

using namespace SqPlus;

void scprintfunc(HSQUIRRELVM v,const SQChar *s,...) { 
  static SQChar temp[2048];
  va_list vl;
  va_start(vl,s);
  scvsprintf( temp,s,vl);
  SCPUTS(temp);
  va_end(vl);
}

void newtest(void) {
  scprintf(_T("NewTest\n"));
}

SQChar * newtestR1(const SQChar * inString) {
  scprintf(_T("NewTestR1: %s\n"),inString);
  return _T("Returned String");
}

struct Vector3 {
  static float staticVar;
  float x,y,z;
  Vector3() {
    x = 1.f;
    y = 2.f;
    z = 3.f;
  }
  Vector3(float _x,float _y,float _z) : x(_x), y(_y), z(_z) {}
  ~Vector3() {
    scprintf(_T("~Vector()\n"));
  }
  Vector3 Inc(Vector3 & v) {
    x += v.x;
    y += v.y;
    z += v.z;
    return *this;
  } 
  Vector3 operator+(Vector3 & v) {
    return Vector3(x+v.x,y+v.y,z+v.z);
  }
};

float Vector3::staticVar = 898.434f;

#if 0 

#include <typeinfo.h>
template<typename TYPE>
inline const SQChar * GetTypeName(const TYPE & n)            { return typeid(TYPE).name(); }
template<typename TYPE>
inline void Push(HSQUIRRELVM v,const TYPE & value)           { CreateCopyInstance(GetTypeName(value),value); }
template<typename TYPE>
inline bool	Match(TypeWrapper<TYPE &>,HSQUIRRELVM v,int idx) { return  GetInstance<TYPE>(v,idx) != NULL; }
template<typename TYPE>
inline TYPE & Get(TypeWrapper<TYPE &>,HSQUIRRELVM v,int idx) { return *GetInstance<TYPE>(v,idx); }
#endif

DECLARE_INSTANCE_TYPE(Vector3)

Vector3 Add2(Vector3 & a,Vector3 & b) {
  Vector3 c;
  c.x = a.x + b.x;
  c.y = a.y + b.y;
  c.z = a.z + b.z;
  return c;
} 

int Add(HSQUIRRELVM v) {

  Vector3 * self = GetInstance<Vector3,true>(v,1);
  Vector3 * arg  = GetInstance<Vector3,true>(v,2);

#if 0
  SQUserPointer type=0;
  so.GetTypeTag(&type);
  SQUserPointer reqType = ClassType<Vector3>::type();
  if (type != reqType) {
    throw SquirrelError(_T("Invalid class type"));
  } 
#endif

  Vector3 tv;
  tv.x = arg->x + self->x;
  tv.y = arg->y + self->y;
  tv.z = arg->z + self->z;
  return ReturnCopy(v,tv);
}

struct NewTestObj {
  ScriptStringVar64 s1;
  ScriptStringVar32 s2;
  bool b;
  int val;
  int c1;
  ScriptStringVar8 c2; 
  NewTestObj() : val(777) {
    s1 = _T("s1=s1");
    s2 = _T("s2=s2");
    c1 = 996;
    c2 = _T("It's a 997"); 
  }

  NewTestObj(const SQChar * _s1,int _val,bool _b) {
    s1  = _s1;
    val = _val;
    b   = _b;
    s2 = _T("s2=s2");
    c1 = 993;
    c2 = _T("It's a 998"); 
  }

  static int construct(HSQUIRRELVM v) {

    return PostConstruct<NewTestObj>(v,new NewTestObj(),release);
  } 

  SQ_DECLARE_RELEASE(NewTestObj) 

  void newtest(void) {
    scprintf(_T("NewTest: %d\n"),val);
  }
  SQChar * newtestR1(const SQChar * inString) {
    scprintf(_T("NewTestR1: Member var val is %d, function arg is %s\n"),val,inString);
    return _T("Returned String");
  }

  int multiArgs(HSQUIRRELVM v) {
    StackHandler sa(v);
    SquirrelObject so = sa.GetObjectHandle(1);
    int paramCount = sa.GetParamCount();
    int p1 = sa.GetInt(2);
    int p2 = sa.GetInt(3);
    int p3 = sa.GetInt(4);
    return 0;
  } 

  int _set(HSQUIRRELVM v) {
    StackHandler sa(v);
    int paramCount = sa.GetParamCount();
    const SQChar * el = sa.GetString(2);
    val = sa.GetInt(3);
    return sa.Return(val);
  }

  int _get(HSQUIRRELVM v) {
    StackHandler sa(v);
    int paramCount = sa.GetParamCount();
    return sa.Return(val);
  }

};

int releaseNewTestObj(SQUserPointer up,SQInteger size) {
  SQ_DELETE_CLASS(NewTestObj);
} 

int constructNewTestObj(HSQUIRRELVM v) {
  StackHandler sa(v);
  int paramCount = sa.GetParamCount();
  if (paramCount == 1) {
    return PostConstruct<NewTestObj>(v,new NewTestObj(),releaseNewTestObj);
  } else if (paramCount == 4) {
    return PostConstruct<NewTestObj>(v,new NewTestObj(sa.GetString(2),sa.GetInt(3),sa.GetBool(4)?true:false),releaseNewTestObj);
  } 
  return sq_throwerror(v,_T("Invalid Constructor arguments"));
} 

int constructNewTestObjFixedArgs(const SQChar * s,int val,bool b,HSQUIRRELVM v) {
  StackHandler sa(v);
  int paramCount = sa.GetParamCount();
  return PostConstruct<NewTestObj>(v,new NewTestObj(s,val,b),releaseNewTestObj);
} 

void globalFunc(const SQChar * s,int val) {
  scprintf(_T("globalFunc: s: %s val: %d\n"),s,val);
} 

class GlobalClass {
public:
  void func(const SQChar * s,int val) {
    scprintf(_T("globalClassFunc: s: %s val: %d\n"),s,val);
  } 
} globalClass;

struct CustomTestObj {
  ScriptStringVar128 name;
  int val;
  bool state;
  CustomTestObj() : val(0), state(false) { name = _T("empty"); }
  CustomTestObj(const SQChar * _name,int _val,bool _state) : val(_val), state(_state) {
    name = _name;
  }

  static int construct(HSQUIRRELVM v) {
    StackHandler sa(v);
    int paramCount = sa.GetParamCount();
    if (paramCount == 1) {
      return PostConstruct<CustomTestObj>(v,new CustomTestObj(),release);
    } if (paramCount == 4) {
      return PostConstruct<CustomTestObj>(v,new CustomTestObj(sa.GetString(2),sa.GetInt(3),sa.GetBool(4)?true:false),release);
    } 
    return sq_throwerror(v,_T("Invalid Constructor arguments"));
  } 

  SQ_DECLARE_RELEASE(CustomTestObj) 

  int varArgTypes(HSQUIRRELVM v) {
    StackHandler sa(v);
    int paramCount = sa.GetParamCount();
    if (sa.GetType(2) == OT_INTEGER) {
      val = sa.GetInt(2);
    } 
    if (sa.GetType(2) == OT_STRING) {
      name = sa.GetString(2);
    } 
    if (sa.GetType(3) == OT_INTEGER) {
      val = sa.GetInt(3);
    } 
    if (sa.GetType(3) == OT_STRING) {
      name = sa.GetString(3);
    } 

    return 0;
  } 

  int varArgTypesAndCount(HSQUIRRELVM v) {
    StackHandler sa(v);
    int paramCount = sa.GetParamCount();
    SQObjectType type1 = (SQObjectType)sa.GetType(1); 
    SQObjectType type2 = (SQObjectType)sa.GetType(2);
    SQObjectType type3 = (SQObjectType)sa.GetType(3);
    SQObjectType type4 = (SQObjectType)sa.GetType(4);
    int returnCount = 0;
    if (paramCount == 3) {
      sq_pushinteger(v,val);
      returnCount = 1;
    } else if (paramCount == 4) {
      sq_pushinteger(v,val);
      sq_pushstring(v,name,-1);
      returnCount = 2;
    } 
    return returnCount;
  } 

  int noArgsVariableReturn(HSQUIRRELVM v) {
    if (val == 123) {
      val++;
      return 0; 
    } else if (val == 124) {
      sq_pushinteger(v,val); 
      val++;
      return 1;
    } else if (val == 125) {
      sq_pushinteger(v,val);
      name = _T("Case 125");
      sq_pushstring(v,name,-1);
      val = 123; 
      return 2;
    } 
    return 0;
  } 

  const SQChar * variableArgsFixedReturnType(HSQUIRRELVM v) {
    StackHandler sa(v);
    int paramCount = sa.GetParamCount();
    SQObjectType type1 = (SQObjectType)sa.GetType(1); 
    SQObjectType type2 = (SQObjectType)sa.GetType(2);
    SQObjectType type3 = (SQObjectType)sa.GetType(3);
    if (paramCount == 1) {
      return _T("No Args");
    } else if (paramCount == 2) {
      return _T("One Arg");
    } else if (paramCount == 3) {
      return _T("Two Args");
    } 
    return _T("More than two args");
  } 

  void manyArgs(int i,float f,bool b,const SQChar * s) {
    scprintf(_T("i: %d, f: %f, b: %s, s: %s\n"),i,f,b?_T("true"):_T("false"),s);
  } 

  float manyArgsR1(int i,float f,bool b,const SQChar * s)  {
    manyArgs(i,f,b,s);
    return i+f;
  } 

};

int testFunc(HSQUIRRELVM v) {
  StackHandler sa(v);
  int paramCount = sa.GetParamCount();
  scprintf(_T("testFunc: numParams[%d]\n"),paramCount);
  for (int i=1; i <= paramCount; i++) {
    scprintf(_T("param[%d]: "),i);
    switch(sa.GetType(i)) {
    case OT_TABLE:   scprintf(_T("OT_TABLE[0x%x]\n"),sa.GetObjectHandle(i)); break;
    case OT_INTEGER: scprintf(_T("OT_INTEGER[%d]\n"),sa.GetInt(i));    break;
    case OT_FLOAT:   scprintf(_T("OT_FLOAT[%f]\n"),sa.GetFloat(i));    break;
    case OT_STRING:  scprintf(_T("OT_STRING[%s]\n"),sa.GetString(i));  break;
    default:
      scprintf(_T("TYPEID[%d]\n"),sa.GetType(i));
    } 
  } 
  return SQ_OK;
} 

int globalVar = 5551234;

class Creature {
  int health;
public:
  enum {MaxHealth=100};
  Creature() : health(MaxHealth) {}
  int GetMaxHealth(void) {
    return MaxHealth;
  }
  int GetHealth(void) {
    return health;
  }
  void SetHealth(int newHealth) {
    health = newHealth;
  }
};

DECLARE_INSTANCE_TYPE(Creature)

class PlayerManager {
public:
  struct Player {
    ScriptStringVar64 name;
    void printName(void) {
      scprintf(_T("Player.name = %s\n"),name.s);
    }
  };
  Player playerVar; 
  Player players[2];
  Player * GetPlayer(int player) { 
    return &players[player];
  }
  PlayerManager() {
    players[0].name = _T("Player1");
    players[1].name = _T("Player2");
    playerVar.name  = _T("PlayerVar");
  }
} playerManager;

DECLARE_INSTANCE_TYPE(PlayerManager)
DECLARE_INSTANCE_TYPE(PlayerManager::Player)

PlayerManager * getPlayerManager(void) { 
  return &playerManager;
}

class STestScripts {}; 
class TestScripts {
public:
  int Var_ToBind1,Var_ToBind2;

  void InitScript1(void) {
    Var_ToBind1 = 808;
    RegisterGlobal(*this,&TestScripts::Test1,_T("Test1"));
    RegisterGlobal(*this,&TestScripts::Test2,_T("Test2"));
    BindVariable(&Var_ToBind1,_T("Var_ToBind1"));
  } 

  void InitScript2(void) {
    Var_ToBind2 = 909;
    SQClassDef<STestScripts>(_T("STestScripts")).
      staticFunc(*this,&TestScripts::Test1,_T("Test1")).
      staticFunc(*this,&TestScripts::Test2,_T("Test2")).
      staticVar(&Var_ToBind2,_T("Var_ToBind2"));
  } 

  void Test1(void) {
    scprintf(_T("Test1 called.\n"));
  }
  void Test2(void) {
    scprintf(_T("Test2 called.\n"));
  }
} testScripts;

#if 1

template<typename T>
struct Point {
  Point() {}
  Point(T X, T Y) : X(X), Y(Y) {}
  T X, Y;
};

template<typename T>
struct Box {
  Box() {}
  Box(Point<T> UpperLeft, Point<T> LowerRight) : UpperLeft(UpperLeft), LowerRight(LowerRight) {}
  Point<T> UpperLeft, LowerRight;
  void print(void) {
    scprintf(_T("UL.X %f UL.Y %f LR.X %f LR.Y %f\n"),UpperLeft.X,UpperLeft.Y,LowerRight.X,LowerRight.Y);
  }
};

template<typename T>
struct Window {
  int id;
  Box<T> box;
};

typedef Point<float> Pointf;
typedef Box<float> Boxf;
typedef Window<float> Windowf;

#else

struct Pointf {
  float X,Y;
  Pointf() {}
  Pointf(float _X, float _Y) : X(_X), Y(_Y) {}
};

struct Boxf {
  Pointf UpperLeft,LowerRight;
  Boxf() {}
  Boxf(Pointf _UpperLeft,Pointf _LowerRight) : UpperLeft(_UpperLeft), LowerRight(_LowerRight) {}
  void print(void) {
    scprintf(_T("UL.X %f UL.Y %f LR.X %f LR.Y %f\n"),UpperLeft.X,UpperLeft.Y,LowerRight.X,LowerRight.Y);
  }
};

struct Windowf {
  int id;
  Boxf box;
};

#endif

DECLARE_INSTANCE_TYPE(Pointf)
DECLARE_INSTANCE_TYPE(Boxf)
DECLARE_INSTANCE_TYPE(Windowf)

int constructPointf(float X,float Y,HSQUIRRELVM v) {
  return PostConstruct<Pointf>(v,new Pointf(X,Y),ReleaseClassPtr<Pointf>::release);
} 

int constructBoxf(Pointf & UpperLeft,Pointf & LowerRight,HSQUIRRELVM v) {
  return PostConstruct<Boxf>(v,new Boxf(UpperLeft,LowerRight),ReleaseClassPtr<Boxf>::release);
} 

struct WindowHolder {
  static Windowf * currentWindow;
  static Windowf * getWindow(void) {
    return currentWindow;
  } 
};
Windowf * WindowHolder::currentWindow = 0;

void testCompiler(void) {
  SquirrelObject test = SquirrelVM::CompileBuffer(_T("\
    local SceneManager = getSceneManager() ; \n\
\n\
    SceneManager.AddScene(\"Scene1\") ; \n\
    SceneManager.AddScene(\"Scene4\") ; \n\
    SceneManager.ActivateScene(\"Scene1\") ; \n\
  "));
  SquirrelVM::RunScript(test);
}

void testPointfBoxf(void) {

  SQClassDef<Pointf>(_T("Pointf")).
    staticFunc(constructPointf,_T("constructor")).
    var(&Pointf::X,_T("X")).
    var(&Pointf::Y,_T("Y"));

  SQClassDef<Boxf>(_T("Boxf")).
    staticFunc(constructBoxf,_T("constructor")).
    func(&Boxf::print,_T("print")).
    var(&Boxf::UpperLeft,_T("UpperLeft")).
    var(&Boxf::LowerRight,_T("LowerRight"));

  SQClassDef<Windowf>(_T("Windowf")).
    var(&Windowf::id,_T("Id")).
    var(&Windowf::box,_T("Box"));

  RegisterGlobal(WindowHolder::getWindow,_T("getWindow"));
  Windowf myWindow;
  myWindow.id = 42;
  myWindow.box = Boxf(Pointf(1.f,2.f),Pointf(3.f,4.f));
  WindowHolder::currentWindow = &myWindow;

  SquirrelObject test = SquirrelVM::CompileBuffer(_T("\
    local MyWindow = Windowf(); \n\
    MyWindow.Box = Boxf(Pointf(11.,22.),Pointf(33.,44.)); \n\
    print(MyWindow.Box.LowerRight.Y); \n\
    MyWindow.Box.LowerRight.Y += 1.; \n\
    local MyWindow2 = Windowf(); \n\
    MyWindow2 = MyWindow; \n\
    print(MyWindow2.Box.LowerRight.Y); \n\
    local MyBox = Boxf(Pointf(10.,20.),Pointf(30.,40.)); \n\
    MyBox.UpperLeft = Pointf(1000.,1000.); \n\
    MyBox.UpperLeft.X = 5000. \n\
    print(MyBox.UpperLeft.X) \n\
    print(MyBox.UpperLeft.Y) \n\
    MyWindow2.Box = MyBox; \n\
    MyWindow2.Box.print(); \n\
    MyWindow2 = getWindow(); \n\
    print(\"MyWindow2: \"+MyWindow2.Id); \n\
    MyWindow2.Box.print(); \n\
    function createWindow(name,instance) { \n\
      ::rawset(name,instance); \n\
    } \n\
  "));
  SquirrelVM::RunScript(test);

  Windowf window = myWindow;
  window.id = 54;
  window.box.UpperLeft.X  += 1;
  window.box.UpperLeft.Y  += 1;
  window.box.LowerRight.X += 1;
  window.box.LowerRight.Y += 1;

  SquirrelFunction<void>(_T("createWindow"))(_T("NewWindow"),&window);

  SquirrelObject test2 = SquirrelVM::CompileBuffer(_T("\
    print(\"NewWindow: \"+NewWindow.Id); \n\
    NewWindow.Box.print(); \n\
  "));
  SquirrelVM::RunScript(test2);

} 

SQInteger debug_hook(HSQUIRRELVM v) {
  SQUserPointer up;
  int event_type,line;
  const SQChar *src,*func;
  sq_getinteger(v,2,&event_type);
  sq_getstring(v,3,&src);
  sq_getinteger(v,4,&line);
  sq_getstring(v,5,&func);
  sq_getuserpointer(v,-1,&up);
  return 0;
} 

struct NamespaceClass {
};

class TestBase {
public:
  int x;
  TestBase() : x(0) {
    printf("Constructing TestBase[0x%x]\n",(size_t)this);
  }
  void print(void) {
    printf("TestBase[0x%x], x[%d]\n",(size_t)this,x);
  }
};

DECLARE_INSTANCE_TYPE(TestBase)

class TestDerivedCPP : public TestBase {
public:
  int y;
  TestDerivedCPP() {
    x = 121;
  }
};

typedef void (TestDerivedCPP::*TestDerivedCPP_print)(void);

void testInhertianceCase(void) {

  SQClassDef<TestBase>(_T("TestBase")).
    var(&TestBase::x,_T("x")).
    func(&TestBase::print,_T("print"));

  SQClassDef<TestDerivedCPP>(_T("TestDerivedCPP")).
    func((TestDerivedCPP_print)&TestDerivedCPP::print,_T("print"));

  SquirrelObject testInheritance2 = SquirrelVM::CompileBuffer(_T("\
    class TestDerived extends TestBase { \n\
      function print() {                 \n\
        ::TestBase.print();              \n\
        ::print(\"Derived: \"+x);        \n\
      }                                  \n\
      constructor() {                    \n\
        TestBase.constructor();          \n\
      }                                  \n\
    }                                    \n\
    local a = TestDerived();             \n\
    local b = TestDerived();             \n\
    a.x = 1;                             \n\
    b.x = 2;                             \n\
    print(\"a.x = \"+a.x);               \n\
    print(\"b.x = \"+b.x);               \n\
    a.print();                           \n\
    b.print();                           \n\
    local c = TestDerivedCPP();          \n\
    c.print();                           \n\
  "));
  SquirrelVM::RunScript(testInheritance2);
}

namespace Scripting {
  class ScriptEntity {
  public:
    ScriptEntity() {
      Bind();
    }
    static void Bind() {
      SqPlus::SQClassDef<ScriptEntity>(_T("ScriptEntity")).
        var(&ScriptEntity::m_strName,_T("name"));
    } 
    SqPlus::ScriptStringVar64 m_strName;
  };
}

DECLARE_INSTANCE_TYPE_NAME(Scripting::ScriptEntity,ScriptEntity)

void testScriptingTypeName(void) {
  try {
    Scripting::ScriptEntity entity ;
    SqPlus::BindVariable(&entity,_T("instance"));
    SquirrelObject sqObj = SquirrelVM::CompileBuffer(_T("instance.name = \"Testing an instance variable bind: member assignment.\"; print(instance.name);"));
    SquirrelVM::RunScript(sqObj);
  } 
  catch (SquirrelError e) {
    scprintf(_T("testScriptingTypeName: %s\n"),e.desc);
  } 
}

class PureInterface {
public:
  virtual void pureFunc1(void)=0;
  virtual void pureFunc2(void)=0;
};

class MyImp : public PureInterface {
public:
  PureInterface * getInterface(void) { return (PureInterface *)this; }
  void pureFunc1(void) {
    scprintf(_T("PureFunc1 called [0x%p].\n"),this);
  }
  void pureFunc2(void) {
    scprintf(_T("PureFunc2 called [0x%p].\n"),this);
  }
};

class InterfaceHolder {
public:
  PureInterface * theInterface;
  void setInterface(PureInterface * pureInterface) {
    theInterface = pureInterface;
  }
  PureInterface * getInterface(void) {
    return theInterface;
  }
};

DECLARE_INSTANCE_TYPE(PureInterface)
DECLARE_INSTANCE_TYPE(MyImp)
DECLARE_INSTANCE_TYPE(InterfaceHolder)

void testPureVirtualInterface(void) {
  SQClassDefNoConstructor<PureInterface>(_T("PureInterface")).
    func(&PureInterface::pureFunc1,_T("pureFunc1")).
    func(&PureInterface::pureFunc2,_T("pureFunc2"));

  SQClassDef<InterfaceHolder>(_T("InterfaceHolder")).
    func(&InterfaceHolder::setInterface,_T("setInterface")).
    func(&InterfaceHolder::getInterface,_T("getInterface"));

  SQClassDef<MyImp>(_T("MyImp")).
    func(&MyImp::getInterface,_T("getInterface"));

  MyImp myImp;

  SquirrelObject test = SquirrelVM::CompileBuffer(_T("ih <- InterfaceHolder();"));
  SquirrelVM::RunScript(test);

  SquirrelObject root = SquirrelVM::GetRootTable();
  SquirrelObject ih = root.GetValue(_T("ih"));
  InterfaceHolder * ihp = (InterfaceHolder * )ih.GetInstanceUP(ClassType<InterfaceHolder>::type());
  ihp->setInterface(&myImp);

  test = SquirrelVM::CompileBuffer(_T("\
                                      ih.getInterface().pureFunc1(); \n\
                                      ih.getInterface().pureFunc2(); \n\
                                      ihp <- ih.getInterface(); \n\
                                      ihp.pureFunc1(); \n\
                                      ihp.pureFunc2(); \n\
                                      myIh <- MyImp(); \n\
                                      ih.setInterface(myIh.getInterface()); \n\
                                      ih.getInterface().pureFunc1(); \n\
                                      ih.getInterface().pureFunc2(); \n\
                                      "));
   SquirrelVM::RunScript(test);

} 

void testSquirrelObjectSetGet(void) {

  SquirrelObject tc(5.678f); 
  float valc = tc.Get<float>();

  scprintf(_T("Valc is: %f\n"),valc);

  float val = 1.234f;
  SquirrelObject t(val); 

  float val2 = t.Get<float>();

  scprintf(_T("Val2 is: %f\n"),val2);

  if (1) {
    SquirrelObject v(Vector3(1.f,2.f,3.f)); 

    Vector3 * pv = v.Get<Vector3 *>();
    scprintf(_T("Vector3 is: %f %f %f\n"),pv->x,pv->y,pv->z);
    pv->z += 1.f;

    if (1) {
      SquirrelObject v2p(pv); 

      pv = v2p.Get<Vector3 *>();
      scprintf(_T("Vector3 is: %f %f %f\n"),pv->x,pv->y,pv->z);
    } 

  } 

  scprintf(_T("Vector3() instance has been released.\n\n"));

} 

#define SQDBG_DEBUG_HOOK _T("_sqdebughook_")

class TestSqPlus {
public:

  enum {SQ_ENUM_TEST=1234321};

  void init(void) {
    SquirrelVM::Init();
    HSQUIRRELVM _v = SquirrelVM::GetVMPtr();

#if 1
    sq_pushregistrytable(_v);
    sq_pushstring(_v,SQDBG_DEBUG_HOOK,-1);
    sq_pushuserpointer(_v,this);
    sq_newclosure(_v,debug_hook,1);
    sq_createslot(_v,-3);

    sq_pushstring(_v,SQDBG_DEBUG_HOOK,-1);
    sq_rawget(_v,-2);
    sq_setdebughook(_v);
    sq_pop(_v,1);

#endif

    sq_enabledebuginfo(_v,SQTrue);

  } 

  TestSqPlus() {
    init();

    testPureVirtualInterface();

    testScriptingTypeName();

    try {
      HSQUIRRELVM v = SquirrelVM::GetVMPtr();
      SquirrelObject root = SquirrelVM::GetRootTable();

      testPointfBoxf();

      testScripts.InitScript1();
      testScripts.InitScript2();
      SquirrelObject testScriptBinding = SquirrelVM::CompileBuffer(_T("\
        local testScripts = STestScripts(); \n\
        testScripts.Test1(); \n\
        testScripts.Test2(); \n\
        print(testScripts.Var_ToBind2); \n\
        Test1(); \n\
        Test2(); \n\
        print(Var_ToBind1); \n\
      "));
      SquirrelVM::RunScript(testScriptBinding);

      SquirrelVM::CreateFunctionGlobal(testFunc,_T("testFunc0"));
      SquirrelVM::CreateFunctionGlobal(testFunc,_T("testFuncN"),_T("n"));
      SquirrelVM::CreateFunctionGlobal(testFunc,_T("testFuncS"),_T("s"));
#if 0
      SquirrelObject testStandardFuncs = SquirrelVM::CompileBuffer(_T(" testFunc0(); testFuncN(1.); testFuncS(\"Hello\"); "));
      SquirrelVM::RunScript(testStandardFuncs);
#endif

      RegisterGlobal(v,newtest,_T("test"));
      RegisterGlobal(v,newtestR1,_T("testR1"));

      NewTestObj t1,t2,t3;
      t1.val = 123;
      t2.val = 456;
      t3.val = 789;
      RegisterGlobal(v,t1,&NewTestObj::newtest,_T("testObj_newtest1"));
      RegisterGlobal(v,t2,&NewTestObj::newtest,_T("testObj_newtest2")); 
      SquirrelObject tr = SquirrelVM::GetRootTable(); 
      Register(v,tr.GetObjectHandle(),t3,&NewTestObj::newtestR1,_T("testObj_newtestR1")); 

      SquirrelObject nameSpaceTable = SquirrelVM::CreateTable();
      root.SetValue(_T("Namespace1"),nameSpaceTable);
      Register(v,nameSpaceTable.GetObjectHandle(),globalFunc,_T("namespaceFunc"));

      SQClassDef<NamespaceClass>(_T("Namespace2")).
        staticFunc(globalFunc,_T("namespaceFunc"));

      SquirrelObject testNameSpace = SquirrelVM::CompileBuffer(_T("\
        Namespace1.namespaceFunc(\"Hello Namespace1 (table),\",321); \n\
        Namespace2.namespaceFunc(\"Hello Namespace2 (class),\",654); \n\
        local Namespace3 = Namespace2(); \n\
        Namespace3.namespaceFunc(\"Hello Namespace3 (instance),\",987); \n\
      "));

      SquirrelVM::RunScript(testNameSpace);

#if 0
      SQClassDef<NewTestObj> sqClass(_T("NewTestObj"));
      sqClass.func(NewTestObj::newtestR1,_T("newtestR1"));
      sqClass.var(&NewTestObj::val,_T("val"));
      sqClass.var(&NewTestObj::s1,_T("s1"));
      sqClass.var(&NewTestObj::s2,_T("s2"));
      sqClass.var(&NewTestObj::c1,_T("c1"),VAR_ACCESS_READ_ONLY);
      sqClass.var(&NewTestObj::c2,_T("c2"),VAR_ACCESS_READ_ONLY);
      sqClass.funcVarArgs(NewTestObj::multiArgs,_T("multiArgs"));
#else
      SQClassDef<NewTestObj>(_T("NewTestObj")).                         

        staticFuncVarArgs(constructNewTestObj,_T("constructor"),_T("*")).   

        staticFunc(globalFunc,_T("globalFunc")).                        
        staticFunc(globalClass,&GlobalClass::func,_T("globalClassFunc")).
        func(&NewTestObj::newtestR1,_T("newtestR1")).
        var(&NewTestObj::val,_T("val")).
        var(&NewTestObj::s1,_T("s1")).
        var(&NewTestObj::s2,_T("s2")).
        var(&NewTestObj::c1,_T("c1"),VAR_ACCESS_READ_ONLY).
        var(&NewTestObj::c2,_T("c2"),VAR_ACCESS_READ_ONLY).
        funcVarArgs(&NewTestObj::multiArgs,_T("multiArgs"));

#define SQ_10 10
#define SQ_E 2.71828182845904523536f
#define SQ_PI 3.14159265358979323846264338327950288f
#define SQ_CONST_STRING _T("A constant string")
      const int intConstant     = 7;
      const float floatConstant = 8.765f;
      const bool boolConstant   = true;
#if 1
      SQClassDef<Vector3>(_T("Vector3")).
        var(&Vector3::x,_T("x")).
        var(&Vector3::y,_T("y")).
        var(&Vector3::z,_T("z")).
        func(&Vector3::Inc,_T("Inc")).
        func(&Vector3::operator+,_T("_add")).
        staticFunc(&Add2,_T("Add2")).
        staticFuncVarArgs(&Add,_T("Add")).
#if 1
        staticVar(&Vector3::staticVar,_T("staticVar")).
#else
        staticVar(&Vector3::staticVar,_T("staticVar"),VAR_ACCESS_READ_ONLY).
#endif
        staticVar(&globalVar,_T("globalVar")).
        constant(SQ_10,_T("SQ_10")).
        constant(SQ_E,_T("SQ_E")).
        constant(SQ_PI,_T("SQ_PI")).
        constant(SQ_CONST_STRING,_T("SQ_CONST_STRING")).
        enumInt(SQ_ENUM_TEST,_T("SQ_ENUM_TEST")).
        constant(intConstant,_T("intConstant")).
        constant(floatConstant,_T("floatConstant")).
        constant(true,_T("boolTrue")).
        constant(false,_T("boolFalse")).
        constant(boolConstant,_T("boolConstant"));
#endif

#endif

      testSquirrelObjectSetGet(); 

      BindConstant(SQ_PI*2,_T("SQ_PI_2"));
      BindConstant(SQ_10*2,_T("SQ_10_2"));
      BindConstant(_T("Global String"),_T("GLOBAL_STRING"));

      SquirrelObject testStaticVars = SquirrelVM::CompileBuffer(_T(" local v = Vector3(); local v2 = Vector3(); local v3 = v+v2; v3 += v2; print(\"v3.x: \"+v3.x); print(\"Vector3::staticVar: \"+v.staticVar+\" Vector3::globalVar: \"+v.globalVar); v.staticVar = 0; "));
      SquirrelVM::RunScript(testStaticVars);

      SquirrelObject testConstants0 = SquirrelVM::CompileBuffer(_T(" print(\"SQ_PI*2: \"+SQ_PI_2+\" SQ_10_2: \"+SQ_10_2+\" GLOBAL_STRING: \"+GLOBAL_STRING); "));
      SquirrelVM::RunScript(testConstants0);

      SquirrelObject testConstants1 = SquirrelVM::CompileBuffer(_T("local v = Vector3(); print(\"SQ_10: \"+v.SQ_10+\" SQ_E: \"+v.SQ_E+\" SQ_PI: \"+v.SQ_PI+\" SQ_CONST_STRING: \"+v.SQ_CONST_STRING+\" SQ_ENUM_TEST: \"+v.SQ_ENUM_TEST);" ));
      SquirrelVM::RunScript(testConstants1);
      SquirrelObject testConstants2 = SquirrelVM::CompileBuffer(_T("local v = Vector3(); print(\"intConstant: \"+v.intConstant+\" floatConstant: \"+v.floatConstant+\" boolTrue: \"+(v.boolTrue?\"True\":\"False\")+\" boolFalse: \"+(v.boolFalse?\"True\":\"False\")+\" boolConstant: \"+(v.boolConstant?\"True\":\"False\"));" ));
      SquirrelVM::RunScript(testConstants2);

      SquirrelObject scriptedBase = SquirrelVM::CompileBuffer(_T(" class ScriptedBase { sbval = 5551212; function multiArgs(a,...) { print(\"SBase: \"+a+val); } \n } \n ")); 
      SquirrelVM::RunScript(scriptedBase);

      SQClassDef<PlayerManager::Player>(_T("PlayerManager::Player")).
        func(&PlayerManager::Player::printName,_T("printName")).
        var(&PlayerManager::Player::name,_T("name"));

      SQClassDef<PlayerManager>(_T("PlayerManager")).
        func(&PlayerManager::GetPlayer,_T("GetPlayer")).
        var(&PlayerManager::playerVar,_T("playerVar"));

      RegisterGlobal(getPlayerManager,_T("getPlayerManager"));
      BindVariable(&playerManager,_T("playerManagerVar"));

      SquirrelObject testGetInstance = SquirrelVM::CompileBuffer(_T("\
        local PlayerManager = getPlayerManager(); \n\
        local oPlayer = PlayerManager.GetPlayer(0); \n\
        print(typeof oPlayer); \n\
        oPlayer.printName(); \n\
        PlayerManager.playerVar.printName(); \n\
        print(PlayerManager.playerVar.name); \n\
        oPlayer = PlayerManager.playerVar; \n\
        oPlayer.name = \"New_Name1\"; \n\
        playerManagerVar.playerVar.printName(); \n\
        oPlayer.name = \"New_Name2\"; \n\
      "));
      SquirrelVM::RunScript(testGetInstance);
      scprintf(_T("playerManager.playerVar.name: %s\n"),playerManager.playerVar.name.s);

      SQClassDef<Creature>(_T("Creature")).
        func(&Creature::GetMaxHealth,_T("GetMaxHealth")).
        func(&Creature::GetHealth,_T("GetHealth")).
        func(&Creature::SetHealth,_T("SetHealth"));

      SquirrelObject testClass = SquirrelVM::CompileBuffer( _T("function HealthPotionUse(Target) { \n\
                                                               local curHealth = Target.GetHealth(); \n\
                                                               local maxHealth = Target.GetMaxHealth(); \n\
                                                               if ((maxHealth - curHealth) > 15) { \n\
                                                                 curHealth += 15; \n\
                                                               } else { \n\
                                                                 curHealth = maxHealth; \n\
                                                               } \n\
                                                               Target.SetHealth(curHealth); \n\
                                                               print(typeof Target); \n\
                                                               return Target; \n\
                                                             }"));
      Creature frodo;
      frodo.SetHealth(frodo.GetMaxHealth()/2);

      SquirrelVM::RunScript(testClass);

      Creature newFrodo = SquirrelFunction<Creature &>(_T("HealthPotionUse"))(frodo); 
      SquirrelFunction<void>(_T("HealthPotionUse"))(&frodo);                          
      scprintf(_T("Frodo's health: %d %d\n"),frodo.GetHealth(),newFrodo.GetHealth());

#ifdef SQ_USE_CLASS_INHERITANCE

      SQClassDef<CustomTestObj> customClass(_T("CustomTestObj"),_T("ScriptedBase"));

      customClass.staticFuncVarArgs(&CustomTestObj::construct,_T("constructor"),_T("*"));                  

      customClass.funcVarArgs(&CustomTestObj::varArgTypesAndCount,_T("multiArgs"),_T("*"));                
      customClass.funcVarArgs(&CustomTestObj::varArgTypesAndCount,_T("varArgTypesAndCount"),_T("*"));      
#else
      SQClassDef<CustomTestObj> customClass(_T("CustomTestObj"));
      customClass.staticFuncVarArgs(&CustomTestObj::construct,_T("constructor"),_T("snb"));                
      customClass.funcVarArgs(&CustomTestObj::varArgTypesAndCount,_T("varArgTypesAndCount"),_T("*"));      
#endif
      customClass.funcVarArgs(&CustomTestObj::varArgTypes,_T("varArgTypes"),_T("s|ns|ns|ns|n"));           
      customClass.funcVarArgs(&CustomTestObj::noArgsVariableReturn,_T("noArgsVariableReturn"));        
      customClass.func(&CustomTestObj::variableArgsFixedReturnType,_T("variableArgsFixedReturnType")); 
      customClass.func(&CustomTestObj::manyArgs,_T("manyArgs"));                                       
      customClass.func(&CustomTestObj::manyArgsR1,_T("manyArgsR1"));                                   

#ifdef SQ_USE_CLASS_INHERITANCE

      SquirrelObject testInheritance = SquirrelVM::CompileBuffer(_T(" class Derived extends CustomTestObj { val = 888; \n function multiArgs(a,...) { print(a+val); \n print(sbval); ::CustomTestObj.multiArgs(4); ::ScriptedBase.multiArgs(5,6,7); \n }\n } \n local x = Derived(); print(\"x.val \"+x.val); x.multiArgs(1,2,3); "));

      printf("=== BEGIN INHERITANCE ===\n");
      testInhertianceCase();
      SquirrelVM::RunScript(testInheritance);
      printf("===  END INHERITANCE  ===\n");
#endif

      SquirrelObject testRegV = SquirrelVM::CompileBuffer(_T(" local vec = Vector3(); print(vec.x); vec = vec.Add(vec); print(vec.x); vec = vec.Add(vec); print(vec.x); vec = vec.Add2(vec,vec); print(vec.x); local v2 = Vector3(); vec = v2.Inc(vec); print(vec.x); print(v2.x); "));
      SquirrelVM::RunScript(testRegV);

#ifdef SQ_USE_CLASS_INHERITANCE
      SquirrelObject testReg0 = SquirrelVM::CompileBuffer(_T(" co <- CustomTestObj(\"hello\",123,true); co.varArgTypes(\"str\",123,123,\"str\"); co.varArgTypes(123,\"str\",\"str\",123); "));
      SquirrelVM::RunScript(testReg0);

      SquirrelObject testReg0a = SquirrelVM::CompileBuffer(_T(" print(co.varArgTypesAndCount(1,true)); print(co.varArgTypesAndCount(2,false,3.)); print(\"\\n\"); "));
      SquirrelVM::RunScript(testReg0a);

      SquirrelObject testReg0b = SquirrelVM::CompileBuffer(_T(" print(co.noArgsVariableReturn()); print(co.noArgsVariableReturn()); print(co.noArgsVariableReturn()); print(\"\\n\"); "));
      SquirrelVM::RunScript(testReg0b);

      SquirrelObject testReg0c = SquirrelVM::CompileBuffer(_T(" print(co.variableArgsFixedReturnType(1)); print(co.variableArgsFixedReturnType(1,2)); print(co.variableArgsFixedReturnType(1,2,3)); print(\"\\n\"); "));
      SquirrelVM::RunScript(testReg0c);

      SquirrelObject testReg0d = SquirrelVM::CompileBuffer(_T(" co.manyArgs(111,222.2,true,\"Hello\"); print(co.manyArgsR1(333,444.3,false,\"World\")); print(\"\\n\"); "));
      SquirrelVM::RunScript(testReg0d);

      SquirrelObject testReg1a = SquirrelVM::CompileBuffer(_T(" co <- CustomTestObj(\"hello\",123,true); co.noArgsVariableReturn(); local t = NewTestObj(\"S1in\",369,true); print(\"C1: \"+t.c1); print(\"C2: \"+t.c2); 
      SquirrelVM::RunScript(testReg1a);

      try {
        SquirrelObject testRegConstant = SquirrelVM::CompileBuffer(_T(" local t = NewTestObj(); t.c1 = 123; "));
        SquirrelVM::RunScript(testRegConstant);
      } 
      catch (SquirrelError & e) {
        scprintf(_T("Error: %s, %s\n"),e.desc,_T("Squirrel::TestConstant"));
      } 

      SquirrelObject testReg1 = SquirrelVM::CompileBuffer(_T(" local t = NewTestObj(); t.newtestR1(\"Hello\"); t.val = 789; print(t.val); print(t.s1); print(t.s2); t.s1 = \"New S1\"; print(t.s1); "));
      SquirrelVM::RunScript(testReg1);

      SquirrelObject testReg2 = SquirrelVM::CompileBuffer(_T(" local t = NewTestObj(); t.val = 789; print(t.val); t.val = 876; print(t.val); t.multiArgs(1,2,3); t.multiArgs(1,2,3,4); t.globalFunc(\"Hola\",5150,false); t.globalClassFunc(\"Bueno\",5151,true); "));
      SquirrelVM::RunScript(testReg2);
      SquirrelObject testReg3 = SquirrelVM::CompileBuffer(_T(" test(); local rv = testR1(\"Hello\"); print(rv); "));
      SquirrelVM::RunScript(testReg3);     
      SquirrelObject testReg4 = SquirrelVM::CompileBuffer(_T(" print(\"\\nMembers:\"); testObj_newtest1(); testObj_newtest2(); print(testObj_newtestR1(\"Hello Again\")); "));
      SquirrelVM::RunScript(testReg4);

      SquirrelObject defCallFunc = SquirrelVM::CompileBuffer(_T(" function callMe(var) { print(\"I was called by: \"+var); return 123; }"));
      SquirrelVM::RunScript(defCallFunc);

      SquirrelObject defCallFuncStrRet = SquirrelVM::CompileBuffer(_T(" function callMeStrRet(var) { print(\"I was called by: \"+var); return var; }"));
      SquirrelVM::RunScript(defCallFuncStrRet);

      SquirrelFunction<void>(_T("callMe"))(_T("Squirrel 1"));

#if 1
      SquirrelFunction<int> callFunc(_T("callMe"));
      int ival = callFunc(_T("Squirrel"));
      scprintf(_T("IVal: %d\n"),ival);

      SquirrelFunction<const SQChar *> callFuncStrRet(_T("callMeStrRet"));
      const SQChar * sval = callFuncStrRet(_T("Squirrel StrRet"));
      scprintf(_T("SVal: %s\n"),sval);
#endif
      ival = 0;

      SquirrelFunction<int> callFunc2(root.GetObjectHandle(),_T("callMe"));
      ival = callFunc(456); 

      SquirrelObject main = SquirrelVM::CompileBuffer(_T("table1 <- {key1=\"keyVal\",key2 = 123};\n if (\"key1\" in table1)\n print(\"Sq: Found it\");\n else\n print(\"Sq: Not found\");"));
      SquirrelVM::RunScript(main);
      SquirrelObject table1 = root.GetValue(_T("table1"));
      if (table1.Exists(_T("key1"))) {
        scprintf(_T("C++: Found it.\n"));
      } else {
        scprintf(_T("C++: Did not find it.\n"));
      } 

      int iVar = 777;
      float fVar = 88.99f;
      bool bVar = true;
      BindVariable(root,&iVar,_T("iVar"));
      BindVariable(root,&fVar,_T("fVar"));
      BindVariable(root,&bVar,_T("bVar"));

      static ScriptStringVar128 testString;
      scsprintf(testString,_T("This is a test string"));
      BindVariable(root,&testString,_T("testString"));

      SquirrelObject array = SquirrelVM::CreateArray(10);
      int i;
      for (i = 0; i < 10; i++) array.SetValue(i,i);
      array.ArrayAppend(123);          
      array.ArrayAppend(true);         
      array.ArrayAppend(false);        
      array.ArrayAppend(123.456f);     
      array.ArrayAppend(_T("string")); 
      array.ArrayAppend(456);          
      array.ArrayAppend((SQUserPointer)0);

      array.ArrayPop(SQFalse);                 
      SquirrelObject so1 = array.ArrayPop();   
      const SQChar * val1 = so1.ToString();      
      float val2 = array.ArrayPop().ToFloat(); 
      scprintf(_T("[Popped values] Val1: %s, Val2: %f\n"),val1,val2);

      int startIndex = array.Len();
      array.ArrayExtend(10); 
      for (i = startIndex; i < array.Len(); i++) array.SetValue(i,i*10);
      root.SetValue(_T("array"),array);

      SquirrelObject arrayr = array.Clone(); 
      arrayr.ArrayReverse();
      root.SetValue(_T("arrayr"),arrayr);

      SquirrelObject define_printArray = SquirrelVM::CompileBuffer(_T(" function printArray(name,array) { print(name+\".len() = \"+array.len()); foreach(i, v in array) if (v != null) { if (typeof v == \"bool\") v = v ? \"true\" : \"false\"; print(\"[\"+i+\"]: \"+v); } } "));
      SquirrelVM::RunScript(define_printArray);
      SquirrelObject test = SquirrelVM::CompileBuffer(_T(" printArray(\"array\",array); printArray(\"arrayr\",arrayr); "));

      SquirrelVM::RunScript(test);
#endif
    } 
    catch (SquirrelError & e) {
      scprintf(_T("Error: %s, in %s\n"),e.desc,_T("TestSqPlus"));
    } 

  }

  ~TestSqPlus() {
    SquirrelVM::Shutdown();
  }

};

void doTest(void) {
  TestSqPlus testSqPlus;
} 

int main(int argc,char * argv[]) {

  SCPUTS(_T("Start Pass 1\n"));
  doTest();
#if 0
  SCPUTS(_T("Start Pass 2\n"));
  doTest();
#endif
  SCPUTS(_T("Done.\n"));

  scprintf(_T("Press RETURN to exit."));
  getchar();

	return 0;
}
// testSqPlus2.cpp
// Created by John Schultz 9/21/2005
// Free for any use.

// Step through the code with a debugger (setting breakpoints in functions)
// to get an idea how everything works.

#include <stdarg.h> 
#include <stdio.h>
#if 0
#include <string>
//#define SQPLUS_SUPPORT_STD_STRING
#define SQPLUS_SUPPORT_SQ_STD_STRING
#endif
//#define SQPLUS_CONST_OPT
#include "sqplus.h"

using namespace SqPlus;

void scprintfunc(HSQUIRRELVM v,const SQChar *s,...) { 
  static SQChar temp[2048];
  va_list vl;
  va_start(vl,s);
  scvsprintf( temp,s,vl);
  SCPUTS(temp);
  va_end(vl);
}

void newtest(void) {
  scprintf(_T("NewTest\n"));
}

SQChar * newtestR1(const SQChar * inString) {
  scprintf(_T("NewTestR1: %s\n"),inString);
  return _T("Returned String");
}

struct Vector3 {
  static float staticVar;
  float x,y,z;
  Vector3() {
    x = 1.f;
    y = 2.f;
    z = 3.f;
  }
  Vector3(float _x,float _y,float _z) : x(_x), y(_y), z(_z) {}
  ~Vector3() {
    scprintf(_T("~Vector()\n"));
  }
  Vector3 Inc(Vector3 & v) {
    x += v.x;
    y += v.y;
    z += v.z;
    return *this;
  } // Inc
  Vector3 operator+(Vector3 & v) {
    return Vector3(x+v.x,y+v.y,z+v.z);
  }
};


float Vector3::staticVar = 898.434f;

#if 0 // It may be possible to make this method work in the future. If so, the DECLARE_INSTANCE_FUNCS() macro
      // would not be needed. The issue is duplicate compiler matching for const SQChar * and Push():
      // Push(const SQChar * &) and Push(const SQChar *) both match.
      // The typeid() compiler function may not be portable to other compilers.
#include <typeinfo.h>
template<typename TYPE>
inline const SQChar * GetTypeName(const TYPE & n)            { return typeid(TYPE).name(); }
template<typename TYPE>
inline void Push(HSQUIRRELVM v,const TYPE & value)           { CreateCopyInstance(GetTypeName(value),value); }
template<typename TYPE>
inline bool	Match(TypeWrapper<TYPE &>,HSQUIRRELVM v,int idx) { return  GetInstance<TYPE>(v,idx) != NULL; }
template<typename TYPE>
inline TYPE & Get(TypeWrapper<TYPE &>,HSQUIRRELVM v,int idx) { return *GetInstance<TYPE>(v,idx); }
#endif

DECLARE_INSTANCE_TYPE(Vector3)

Vector3 Add2(Vector3 & a,Vector3 & b) {
  Vector3 c;
  c.x = a.x + b.x;
  c.y = a.y + b.y;
  c.z = a.z + b.z;
  return c;
} // Add2

int Add(HSQUIRRELVM v) {
//  StackHandler sa(v);
  Vector3 * self = GetInstance<Vector3,true>(v,1);
  Vector3 * arg  = GetInstance<Vector3,true>(v,2);
//  SquirrelObject so = sa.GetObjectHandle(1);
#if 0
  SQUserPointer type=0;
  so.GetTypeTag(&type);
  SQUserPointer reqType = ClassType<Vector3>::type();
  if (type != reqType) {
    throw SquirrelError(_T("Invalid class type"));
  } // if
#endif
//  Vector3 * self = (Vector3 *)so.GetInstanceUP(ClassType<Vector3>::type());
//  if (!self) throw SquirrelError(_T("Invalid class type"));
  Vector3 tv;
  tv.x = arg->x + self->x;
  tv.y = arg->y + self->y;
  tv.z = arg->z + self->z;
  return ReturnCopy(v,tv);
}

struct NewTestObj {
  ScriptStringVar64 s1;
  ScriptStringVar32 s2;
  bool b;
  int val;
  int c1;
  ScriptStringVar8 c2; // 8 char plus null (max string is 8 printable chars).
  NewTestObj() : val(777) {
    s1 = _T("s1=s1");
    s2 = _T("s2=s2");
    c1 = 996;
    c2 = _T("It's a 997"); // Prints: "It's a 9", as only 8 chars in static buffer (plus null).
  }

  NewTestObj(const SQChar * _s1,int _val,bool _b) {
    s1  = _s1;
    val = _val;
    b   = _b;
    s2 = _T("s2=s2");
    c1 = 993;
    c2 = _T("It's a 998"); // Prints: "It's a 9", as only 8 chars in static buffer (plus null).
  }

  static int construct(HSQUIRRELVM v) {
//    StackHandler sa(v);
//    SquirrelObject so = sa.GetObjectHandle(1);
    return PostConstruct<NewTestObj>(v,new NewTestObj(),release);
  } // construct

  SQ_DECLARE_RELEASE(NewTestObj) // Required when using a custom constructor.

  void newtest(void) {
    scprintf(_T("NewTest: %d\n"),val);
  }
  SQChar * newtestR1(const SQChar * inString) {
    scprintf(_T("NewTestR1: Member var val is %d, function arg is %s\n"),val,inString);
    return _T("Returned String");
  }

  int multiArgs(HSQUIRRELVM v) {
    StackHandler sa(v);
    SquirrelObject so = sa.GetObjectHandle(1);
    int paramCount = sa.GetParamCount();
    int p1 = sa.GetInt(2);
    int p2 = sa.GetInt(3);
    int p3 = sa.GetInt(4);
    return 0;
  } // multiArgs

  int _set(HSQUIRRELVM v) {
    StackHandler sa(v);
    int paramCount = sa.GetParamCount();
    const SQChar * el = sa.GetString(2);
    val = sa.GetInt(3);
    return sa.Return(val);
  }

  int _get(HSQUIRRELVM v) {
    StackHandler sa(v);
    int paramCount = sa.GetParamCount();
    return sa.Return(val);
  }

};

// Using global functions to construct and release classes.
int releaseNewTestObj(SQUserPointer up,SQInteger size) {
  SQ_DELETE_CLASS(NewTestObj);
} // releaseNewTestObj

int constructNewTestObj(HSQUIRRELVM v) {
  StackHandler sa(v);
  int paramCount = sa.GetParamCount();
  if (paramCount == 1) {
    return PostConstruct<NewTestObj>(v,new NewTestObj(),releaseNewTestObj);
  } else if (paramCount == 4) {
    return PostConstruct<NewTestObj>(v,new NewTestObj(sa.GetString(2),sa.GetInt(3),sa.GetBool(4)?true:false),releaseNewTestObj);
  } // if
  return sq_throwerror(v,_T("Invalid Constructor arguments"));
} // constructNewTestObj

// Using fixed args with auto-marshaling. Note that the HSQUIRRELVM must be last in the argument list (and must be present to send to PostConstruct).
// SquirrelVM::GetVMPtr() could also be used with PostConstruct(): no HSQUIRRELVM argument would be required.
int constructNewTestObjFixedArgs(const SQChar * s,int val,bool b,HSQUIRRELVM v) {
  StackHandler sa(v);
  int paramCount = sa.GetParamCount();
  return PostConstruct<NewTestObj>(v,new NewTestObj(s,val,b),releaseNewTestObj);
} // constructNewTestObj

// Will be registered in a class namespace.
void globalFunc(const SQChar * s,int val) {
  scprintf(_T("globalFunc: s: %s val: %d\n"),s,val);
} // globalFunc

class GlobalClass {
public:
  void func(const SQChar * s,int val) {
    scprintf(_T("globalClassFunc: s: %s val: %d\n"),s,val);
  } // func
} globalClass;

struct CustomTestObj {
  ScriptStringVar128 name;
  int val;
  bool state;
  CustomTestObj() : val(0), state(false) { name = _T("empty"); }
  CustomTestObj(const SQChar * _name,int _val,bool _state) : val(_val), state(_state) {
    name = _name;
  }

  // Custom variable argument constructor
  static int construct(HSQUIRRELVM v) {
    StackHandler sa(v);
    int paramCount = sa.GetParamCount();
    if (paramCount == 1) {
      return PostConstruct<CustomTestObj>(v,new CustomTestObj(),release);
    } if (paramCount == 4) {
      return PostConstruct<CustomTestObj>(v,new CustomTestObj(sa.GetString(2),sa.GetInt(3),sa.GetBool(4)?true:false),release);
    } // if
    return sq_throwerror(v,_T("Invalid Constructor arguments"));
  } // construct

  SQ_DECLARE_RELEASE(CustomTestObj) // Required when using a custom constructor.

  // Member function that handles variable types.
  int varArgTypes(HSQUIRRELVM v) {
    StackHandler sa(v);
    int paramCount = sa.GetParamCount();
    if (sa.GetType(2) == OT_INTEGER) {
      val = sa.GetInt(2);
    } // if
    if (sa.GetType(2) == OT_STRING) {
      name = sa.GetString(2);
    } // if
    if (sa.GetType(3) == OT_INTEGER) {
      val = sa.GetInt(3);
    } // if
    if (sa.GetType(3) == OT_STRING) {
      name = sa.GetString(3);
    } // if
//    return sa.ThrowError(_T("varArgTypes() error"));
    return 0;
  } // varArgTypes

  // Member function that handles variable types and has variable return types+count.
  int varArgTypesAndCount(HSQUIRRELVM v) {
    StackHandler sa(v);
    int paramCount = sa.GetParamCount();
    SQObjectType type1 = (SQObjectType)sa.GetType(1); // Always OT_INSTANCE
    SQObjectType type2 = (SQObjectType)sa.GetType(2);
    SQObjectType type3 = (SQObjectType)sa.GetType(3);
    SQObjectType type4 = (SQObjectType)sa.GetType(4);
    int returnCount = 0;
    if (paramCount == 3) {
      sq_pushinteger(v,val);
      returnCount = 1;
    } else if (paramCount == 4) {
      sq_pushinteger(v,val);
      sq_pushstring(v,name,-1);
      returnCount = 2;
    } // if
    return returnCount;
  } //

  int noArgsVariableReturn(HSQUIRRELVM v) {
    if (val == 123) {
      val++;
      return 0; // This will print (null).
    } else if (val == 124) {
      sq_pushinteger(v,val); // Will return int:124.
      val++;
      return 1;
    } else if (val == 125) {
      sq_pushinteger(v,val);
      name = _T("Case 125");
      sq_pushstring(v,name,-1);
      val = 123; // reset
      return 2;
    } // if
    return 0;
  } // noArgsVariableReturn

  // Registered with func() instead of funcVarArgs(): fixed (single) return type.
  const SQChar * variableArgsFixedReturnType(HSQUIRRELVM v) {
    StackHandler sa(v);
    int paramCount = sa.GetParamCount();
    SQObjectType type1 = (SQObjectType)sa.GetType(1); // Always OT_INSTANCE
    SQObjectType type2 = (SQObjectType)sa.GetType(2);
    SQObjectType type3 = (SQObjectType)sa.GetType(3);
    if (paramCount == 1) {
      return _T("No Args");
    } else if (paramCount == 2) {
      return _T("One Arg");
    } else if (paramCount == 3) {
      return _T("Two Args");
    } // if
    return _T("More than two args");
  } // variableArgsFixedReturnType

  void manyArgs(int i,float f,bool b,const SQChar * s) {
    scprintf(_T("i: %d, f: %f, b: %s, s: %s\n"),i,f,b?_T("true"):_T("false"),s);
  } // manyArgs

  float manyArgsR1(int i,float f,bool b,const SQChar * s)  {
    manyArgs(i,f,b,s);
    return i+f;
  } // manyArgsR1

};

// === Standard (non member) function ===
int testFunc(HSQUIRRELVM v) {
  StackHandler sa(v);
  int paramCount = sa.GetParamCount();
  scprintf(_T("testFunc: numParams[%d]\n"),paramCount);
  for (int i=1; i <= paramCount; i++) {
    scprintf(_T("param[%d]: "),i);
    switch(sa.GetType(i)) {
    case OT_TABLE:   scprintf(_T("OT_TABLE[0x%x]\n"),sa.GetObjectHandle(i)); break;
    case OT_INTEGER: scprintf(_T("OT_INTEGER[%d]\n"),sa.GetInt(i));    break;
    case OT_FLOAT:   scprintf(_T("OT_FLOAT[%f]\n"),sa.GetFloat(i));    break;
    case OT_STRING:  scprintf(_T("OT_STRING[%s]\n"),sa.GetString(i));  break;
    default:
      scprintf(_T("TYPEID[%d]\n"),sa.GetType(i));
    } // switch
  } // for
  return SQ_OK;
} // testFunc

int globalVar = 5551234;

class Creature {
  int health;
public:
  enum {MaxHealth=100};
  Creature() : health(MaxHealth) {}
  int GetMaxHealth(void) {
    return MaxHealth;
  }
  int GetHealth(void) {
    return health;
  }
  void SetHealth(int newHealth) {
    health = newHealth;
  }
};

DECLARE_INSTANCE_TYPE(Creature)

// === BEGIN Class Instance Test ===

class PlayerManager {
public:
  struct Player {
    ScriptStringVar64 name;
    void printName(void) {
      scprintf(_T("Player.name = %s\n"),name.s);
    }
  };
  Player playerVar; // Will be accessed directly.
  Player players[2];
  Player * GetPlayer(int player) { // Must return pointer: a returned reference will behave the same as return by value.
    return &players[player];
  }
  PlayerManager() {
    players[0].name = _T("Player1");
    players[1].name = _T("Player2");
    playerVar.name  = _T("PlayerVar");
  }
} playerManager;

DECLARE_INSTANCE_TYPE(PlayerManager)
DECLARE_INSTANCE_TYPE(PlayerManager::Player)

PlayerManager * getPlayerManager(void) { // Must return pointer: a returned reference will behave the same as return by value.
  return &playerManager;
}

// Example from forum post question:
class STestScripts {}; // Proxy class
class TestScripts {
public:
  int Var_ToBind1,Var_ToBind2;

  void InitScript1(void) {
    Var_ToBind1 = 808;
    RegisterGlobal(*this,&TestScripts::Test1,_T("Test1"));
    RegisterGlobal(*this,&TestScripts::Test2,_T("Test2"));
    BindVariable(&Var_ToBind1,_T("Var_ToBind1"));
  } // InitScript1

  void InitScript2(void) {
    Var_ToBind2 = 909;
    SQClassDef<STestScripts>(_T("STestScripts")).
      staticFunc(*this,&TestScripts::Test1,_T("Test1")).
      staticFunc(*this,&TestScripts::Test2,_T("Test2")).
      staticVar(&Var_ToBind2,_T("Var_ToBind2"));
  } // InitScript2

  void Test1(void) {
    scprintf(_T("Test1 called.\n"));
  }
  void Test2(void) {
    scprintf(_T("Test2 called.\n"));
  }
} testScripts;

// From forum questions

#if 1

template<typename T>
struct Point {
  Point() {}
  Point(T X, T Y) : X(X), Y(Y) {}
  T X, Y;
};

template<typename T>
struct Box {
  Box() {}
  Box(Point<T> UpperLeft, Point<T> LowerRight) : UpperLeft(UpperLeft), LowerRight(LowerRight) {}
  Point<T> UpperLeft, LowerRight;
  void print(void) {
    scprintf(_T("UL.X %f UL.Y %f LR.X %f LR.Y %f\n"),UpperLeft.X,UpperLeft.Y,LowerRight.X,LowerRight.Y);
  }
};

template<typename T>
struct Window {
  int id;
  Box<T> box;
};

typedef Point<float> Pointf;
typedef Box<float> Boxf;
typedef Window<float> Windowf;

#else

struct Pointf {
  float X,Y;
  Pointf() {}
  Pointf(float _X, float _Y) : X(_X), Y(_Y) {}
};

struct Boxf {
  Pointf UpperLeft,LowerRight;
  Boxf() {}
  Boxf(Pointf _UpperLeft,Pointf _LowerRight) : UpperLeft(_UpperLeft), LowerRight(_LowerRight) {}
  void print(void) {
    scprintf(_T("UL.X %f UL.Y %f LR.X %f LR.Y %f\n"),UpperLeft.X,UpperLeft.Y,LowerRight.X,LowerRight.Y);
  }
};

struct Windowf {
  int id;
  Boxf box;
};

#endif

DECLARE_INSTANCE_TYPE(Pointf)
DECLARE_INSTANCE_TYPE(Boxf)
DECLARE_INSTANCE_TYPE(Windowf)

int constructPointf(float X,float Y,HSQUIRRELVM v) {
  return PostConstruct<Pointf>(v,new Pointf(X,Y),ReleaseClassPtr<Pointf>::release);
} // constructPointf

// Must pass by reference or pointer (not copy)
int constructBoxf(Pointf & UpperLeft,Pointf & LowerRight,HSQUIRRELVM v) {
  return PostConstruct<Boxf>(v,new Boxf(UpperLeft,LowerRight),ReleaseClassPtr<Boxf>::release);
} // constructBoxf

struct WindowHolder {
  static Windowf * currentWindow;
  static Windowf * getWindow(void) {
    return currentWindow;
  } // getWindow
};
Windowf * WindowHolder::currentWindow = 0;

// From forum post: compiler works OK.
void testCompiler(void) {
  SquirrelObject test = SquirrelVM::CompileBuffer(_T("\
    local SceneManager = getSceneManager() ; \n\
\n\
    SceneManager.AddScene(\"Scene1\") ; \n\
    SceneManager.AddScene(\"Scene4\") ; \n\
    SceneManager.ActivateScene(\"Scene1\") ; \n\
  "));
  SquirrelVM::RunScript(test);
}

void testPointfBoxf(void) {

//  testCompiler();

  SQClassDef<Pointf>(_T("Pointf")).
    staticFunc(constructPointf,_T("constructor")).
    var(&Pointf::X,_T("X")).
    var(&Pointf::Y,_T("Y"));

  SQClassDef<Boxf>(_T("Boxf")).
    staticFunc(constructBoxf,_T("constructor")).
    func(&Boxf::print,_T("print")).
    var(&Boxf::UpperLeft,_T("UpperLeft")).
    var(&Boxf::LowerRight,_T("LowerRight"));

  SQClassDef<Windowf>(_T("Windowf")).
    var(&Windowf::id,_T("Id")).
    var(&Windowf::box,_T("Box"));

  RegisterGlobal(WindowHolder::getWindow,_T("getWindow"));
  Windowf myWindow;
  myWindow.id = 42;
  myWindow.box = Boxf(Pointf(1.f,2.f),Pointf(3.f,4.f));
  WindowHolder::currentWindow = &myWindow;

  // The createWindow() function below creates a new instance on the root table.
  // The instance data is a pointer to the C/C++ instance, and will not be freed
  // or otherwise managed.

  SquirrelObject test = SquirrelVM::CompileBuffer(_T("\
    local MyWindow = Windowf(); \n\
    MyWindow.Box = Boxf(Pointf(11.,22.),Pointf(33.,44.)); \n\
    print(MyWindow.Box.LowerRight.Y); \n\
    MyWindow.Box.LowerRight.Y += 1.; \n\
    local MyWindow2 = Windowf(); \n\
    MyWindow2 = MyWindow; \n\
    print(MyWindow2.Box.LowerRight.Y); \n\
    local MyBox = Boxf(Pointf(10.,20.),Pointf(30.,40.)); \n\
    MyBox.UpperLeft = Pointf(1000.,1000.); \n\
    MyBox.UpperLeft.X = 5000. \n\
    print(MyBox.UpperLeft.X) \n\
    print(MyBox.UpperLeft.Y) \n\
    MyWindow2.Box = MyBox; \n\
    MyWindow2.Box.print(); \n\
    MyWindow2 = getWindow(); \n\
    print(\"MyWindow2: \"+MyWindow2.Id); \n\
    MyWindow2.Box.print(); \n\
    function createWindow(name,instance) { \n\
      ::rawset(name,instance); \n\
    } \n\
  "));
  SquirrelVM::RunScript(test);

  Windowf window = myWindow;
  window.id = 54;
  window.box.UpperLeft.X  += 1;
  window.box.UpperLeft.Y  += 1;
  window.box.LowerRight.X += 1;
  window.box.LowerRight.Y += 1;
  // Create a new Window instance "NewWindow" on the root table.
  SquirrelFunction<void>(_T("createWindow"))(_T("NewWindow"),&window);

  SquirrelObject test2 = SquirrelVM::CompileBuffer(_T("\
    print(\"NewWindow: \"+NewWindow.Id); \n\
    NewWindow.Box.print(); \n\
  "));
  SquirrelVM::RunScript(test2);

} // testPointfBoxf

// Example debug hook: called back during script execution.
SQInteger debug_hook(HSQUIRRELVM v) {
  SQUserPointer up;
  int event_type,line;
  const SQChar *src,*func;
  sq_getinteger(v,2,&event_type);
  sq_getstring(v,3,&src);
  sq_getinteger(v,4,&line);
  sq_getstring(v,5,&func);
  sq_getuserpointer(v,-1,&up);
  return 0;
} // debug_hook

// You can add functions/vars here, as well as bind globals to be accessed through this class as shown in the NameSpace example.
// If the class is instantiated in script, the instance is "locked", preventing accidental changes to elements.
// Thus using an instance as the namespace can be a better design for development.
// If variables/constants are bound to the class and/or non-static/non-global functions, the class must be instantiated before use.
struct NamespaceClass {
};

// === END Class Instance Test ===

class TestBase {
public:
  int x;
  TestBase() : x(0) {
    printf("Constructing TestBase[0x%x]\n",(size_t)this);
  }
  void print(void) {
    printf("TestBase[0x%x], x[%d]\n",(size_t)this,x);
  }
};

DECLARE_INSTANCE_TYPE(TestBase)

class TestDerivedCPP : public TestBase {
public:
  int y;
  TestDerivedCPP() {
    x = 121;
  }
};

typedef void (TestDerivedCPP::*TestDerivedCPP_print)(void);

void testInhertianceCase(void) {

  SQClassDef<TestBase>(_T("TestBase")).
    var(&TestBase::x,_T("x")).
    func(&TestBase::print,_T("print"));

  SQClassDef<TestDerivedCPP>(_T("TestDerivedCPP")).
    func((TestDerivedCPP_print)&TestDerivedCPP::print,_T("print"));

  // Note that the constructor definition and call below is not required for this example.
  // (The C/C++ constructor will be called automatically).

  SquirrelObject testInheritance2 = SquirrelVM::CompileBuffer(_T("\
    class TestDerived extends TestBase { \n\
      function print() {                 \n\
        ::TestBase.print();              \n\
        ::print(\"Derived: \"+x);        \n\
      }                                  \n\
      constructor() {                    \n\
        TestBase.constructor();          \n\
      }                                  \n\
    }                                    \n\
    local a = TestDerived();             \n\
    local b = TestDerived();             \n\
    a.x = 1;                             \n\
    b.x = 2;                             \n\
    print(\"a.x = \"+a.x);               \n\
    print(\"b.x = \"+b.x);               \n\
    a.print();                           \n\
    b.print();                           \n\
    local c = TestDerivedCPP();          \n\
    c.print();                           \n\
  "));
  SquirrelVM::RunScript(testInheritance2);
}

// === BEGIN from a forum post by jkleinecke. 8/23/06 jcs ===

namespace Scripting {
  class ScriptEntity {
  public:
    ScriptEntity() {
      Bind();
    }
    static void Bind() {
      SqPlus::SQClassDef<ScriptEntity>(_T("ScriptEntity")).
        var(&ScriptEntity::m_strName,_T("name"));
    } // Bind
    SqPlus::ScriptStringVar64 m_strName;
  };
}

DECLARE_INSTANCE_TYPE_NAME(Scripting::ScriptEntity,ScriptEntity)

void testScriptingTypeName(void) {
  try {
    Scripting::ScriptEntity entity ;
    SqPlus::BindVariable(&entity,_T("instance"));
    SquirrelObject sqObj = SquirrelVM::CompileBuffer(_T("instance.name = \"Testing an instance variable bind: member assignment.\"; print(instance.name);"));
    SquirrelVM::RunScript(sqObj);
  } // try
  catch (SquirrelError e) {
    scprintf(_T("testScriptingTypeName: %s\n"),e.desc);
  } // catch
}

// === END from a forum post by jkleinecke. 8/23/06 jcs ===


// === BEGIN Interface Test ===

class PureInterface {
public:
  virtual void pureFunc1(void)=0;
  virtual void pureFunc2(void)=0;
};

class MyImp : public PureInterface {
public:
  PureInterface * getInterface(void) { return (PureInterface *)this; }
  void pureFunc1(void) {
    scprintf(_T("PureFunc1 called [0x%p].\n"),this);
  }
  void pureFunc2(void) {
    scprintf(_T("PureFunc2 called [0x%p].\n"),this);
  }
};

class InterfaceHolder {
public:
  PureInterface * theInterface;
  void setInterface(PureInterface * pureInterface) {
    theInterface = pureInterface;
  }
  PureInterface * getInterface(void) {
    return theInterface;
  }
};

DECLARE_INSTANCE_TYPE(PureInterface)
DECLARE_INSTANCE_TYPE(MyImp)
DECLARE_INSTANCE_TYPE(InterfaceHolder)

void testPureVirtualInterface(void) {
  SQClassDefNoConstructor<PureInterface>(_T("PureInterface")).
    func(&PureInterface::pureFunc1,_T("pureFunc1")).
    func(&PureInterface::pureFunc2,_T("pureFunc2"));

  SQClassDef<InterfaceHolder>(_T("InterfaceHolder")).
    func(&InterfaceHolder::setInterface,_T("setInterface")).
    func(&InterfaceHolder::getInterface,_T("getInterface"));

  SQClassDef<MyImp>(_T("MyImp")).
    func(&MyImp::getInterface,_T("getInterface"));

  MyImp myImp;

  SquirrelObject test = SquirrelVM::CompileBuffer(_T("ih <- InterfaceHolder();"));
  SquirrelVM::RunScript(test);

  SquirrelObject root = SquirrelVM::GetRootTable();
  SquirrelObject ih = root.GetValue(_T("ih"));
  InterfaceHolder * ihp = (InterfaceHolder * )ih.GetInstanceUP(ClassType<InterfaceHolder>::type());
  ihp->setInterface(&myImp);

  test = SquirrelVM::CompileBuffer(_T("\
                                      ih.getInterface().pureFunc1(); \n\
                                      ih.getInterface().pureFunc2(); \n\
                                      ihp <- ih.getInterface(); \n\
                                      ihp.pureFunc1(); \n\
                                      ihp.pureFunc2(); \n\
                                      myIh <- MyImp(); \n\
                                      ih.setInterface(myIh.getInterface()); \n\
                                      ih.getInterface().pureFunc1(); \n\
                                      ih.getInterface().pureFunc2(); \n\
                                      "));
   SquirrelVM::RunScript(test);

} // testPureVirtualInterface

// === END Interface Test ===

void testSquirrelObjectSetGet(void) {
  // We can pass in arguments:
  //   by value ('true' arg, required for constant float, int, etc., or when a copy is desired),
  //   by reference (data will be copied to SquirrelObject and memory managed),
  //   by pointer (no data copying: pointer is used directly in SquirrelObject; the memory will not be managed).

  SquirrelObject tc(5.678f); // constant argument is passed by value (even though declaration is by ref: const & results in by-value in this case), memory will be allocated and managed for the copy.
  float valc = tc.Get<float>();

  scprintf(_T("Valc is: %f\n"),valc);

  float val = 1.234f;
  SquirrelObject t(val); // val is passed by reference, memory will be allocated, and the value copied once.

  float val2 = t.Get<float>();

  scprintf(_T("Val2 is: %f\n"),val2);

  if (1) {
    SquirrelObject v(Vector3(1.f,2.f,3.f)); // Pass in by reference: will be copied once, with memory for new copy managed by Squirrel.

    Vector3 * pv = v.Get<Vector3 *>();
    scprintf(_T("Vector3 is: %f %f %f\n"),pv->x,pv->y,pv->z);
    pv->z += 1.f;

    if (1) {
      SquirrelObject v2p(pv); // This is a pointer to v's instance (passed in by pointer: see SquirrelObject.h). 
                              // A new Squirrel Instance will be created, but the C++ instance pointer will not get freed when v2p goes out of scope (release hook will be null).
      pv = v2p.Get<Vector3 *>();
      scprintf(_T("Vector3 is: %f %f %f\n"),pv->x,pv->y,pv->z);
    } // if

  } // if

  scprintf(_T("Vector3() instance has been released.\n\n"));

} // testSquirrelObjectSetGet


#define SQDBG_DEBUG_HOOK _T("_sqdebughook_")

class TestSqPlus {
public:

  enum {SQ_ENUM_TEST=1234321};

  void init(void) {
    SquirrelVM::Init();
    HSQUIRRELVM _v = SquirrelVM::GetVMPtr();

#if 1
    sq_pushregistrytable(_v);
    sq_pushstring(_v,SQDBG_DEBUG_HOOK,-1);
    sq_pushuserpointer(_v,this);
    sq_newclosure(_v,debug_hook,1);
    sq_createslot(_v,-3);
//    sq_pop(_v,1);

//    sq_pushregistrytable(_v);
    sq_pushstring(_v,SQDBG_DEBUG_HOOK,-1);
    sq_rawget(_v,-2);
    sq_setdebughook(_v);
    sq_pop(_v,1);

#endif

    sq_enabledebuginfo(_v,SQTrue);

  } // init

  TestSqPlus() {
    init();

    testPureVirtualInterface();

    testScriptingTypeName();

    try {
      HSQUIRRELVM v = SquirrelVM::GetVMPtr();
      SquirrelObject root = SquirrelVM::GetRootTable();

      testPointfBoxf();

      // Example from forum question:
      testScripts.InitScript1();
      testScripts.InitScript2();
      SquirrelObject testScriptBinding = SquirrelVM::CompileBuffer(_T("\
        local testScripts = STestScripts(); \n\
        testScripts.Test1(); \n\
        testScripts.Test2(); \n\
        print(testScripts.Var_ToBind2); \n\
        Test1(); \n\
        Test2(); \n\
        print(Var_ToBind1); \n\
      "));
      SquirrelVM::RunScript(testScriptBinding);

      // === BEGIN Global Function binding tests ===

      // Implemented as SquirrelVM::CreateFunction(rootTable,func,name,typeMask). CreateFunctionGlobal() binds a standard SQFUNCTION (stack args).
      SquirrelVM::CreateFunctionGlobal(testFunc,_T("testFunc0"));
      SquirrelVM::CreateFunctionGlobal(testFunc,_T("testFuncN"),_T("n"));
      SquirrelVM::CreateFunctionGlobal(testFunc,_T("testFuncS"),_T("s"));
#if 0
      SquirrelObject testStandardFuncs = SquirrelVM::CompileBuffer(_T(" testFunc0(); testFuncN(1.); testFuncS(\"Hello\"); "));
      SquirrelVM::RunScript(testStandardFuncs);
#endif
      // === Register Standard Functions using template system (function will be directly called with argument auto-marshaling) ===

      RegisterGlobal(v,newtest,_T("test"));
      RegisterGlobal(v,newtestR1,_T("testR1"));

      // === Register Member Functions to existing classes (as opposed to instances of classes) ===

      NewTestObj t1,t2,t3;
      t1.val = 123;
      t2.val = 456;
      t3.val = 789;
      RegisterGlobal(v,t1,&NewTestObj::newtest,_T("testObj_newtest1"));
      RegisterGlobal(v,t2,&NewTestObj::newtest,_T("testObj_newtest2")); // Register newtest() again with different name and object pointer.
      SquirrelObject tr = SquirrelVM::GetRootTable(); // Can be any object supporting closures (functions).
      Register(v,tr.GetObjectHandle(),t3,&NewTestObj::newtestR1,_T("testObj_newtestR1")); // Return value version.

      // === END Global Function binding tests ===

      // === BEGIN Namespace examples ===

      // Create a namespace using a table.
      SquirrelObject nameSpaceTable = SquirrelVM::CreateTable();
      root.SetValue(_T("Namespace1"),nameSpaceTable);
      Register(v,nameSpaceTable.GetObjectHandle(),globalFunc,_T("namespaceFunc"));

      // Create a namespace using a class. If an instance is created from the class, using the instance will prevent accidental changes to the instance members.
      // Using the class/instance form also allows extra information to be added to the proxy class, if desired (such as vars/funcs).
      // NOTE: If any variables/static-variables/constants are registered to the class, it must be instantiated before use.
      SQClassDef<NamespaceClass>(_T("Namespace2")).
        staticFunc(globalFunc,_T("namespaceFunc"));

      SquirrelObject testNameSpace = SquirrelVM::CompileBuffer(_T("\
        Namespace1.namespaceFunc(\"Hello Namespace1 (table),\",321); \n\
        Namespace2.namespaceFunc(\"Hello Namespace2 (class),\",654); \n\
        local Namespace3 = Namespace2(); \n\
        Namespace3.namespaceFunc(\"Hello Namespace3 (instance),\",987); \n\
      "));

      SquirrelVM::RunScript(testNameSpace);

      // === END Namespace examples ===

      // === BEGIN Class Instance tests ===

      // Example showing two methods for registration.
#if 0
      SQClassDef<NewTestObj> sqClass(_T("NewTestObj"));
      sqClass.func(NewTestObj::newtestR1,_T("newtestR1"));
      sqClass.var(&NewTestObj::val,_T("val"));
      sqClass.var(&NewTestObj::s1,_T("s1"));
      sqClass.var(&NewTestObj::s2,_T("s2"));
      sqClass.var(&NewTestObj::c1,_T("c1"),VAR_ACCESS_READ_ONLY);
      sqClass.var(&NewTestObj::c2,_T("c2"),VAR_ACCESS_READ_ONLY);
      sqClass.funcVarArgs(NewTestObj::multiArgs,_T("multiArgs"));
#else
      SQClassDef<NewTestObj>(_T("NewTestObj")).                         // If a special constructor+destructor are not needed, the auto-generated versions can be used.
                                                                    // Example methods for custom constructors:
        staticFuncVarArgs(constructNewTestObj,_T("constructor"),_T("*")).   // Using a global constructor: useful in cases where a custom constructor/destructor are required and the original class is not to be modified.
//        staticFunc(constructNewTestObjFixedArgs,_T("constructor")).   // Using a global constructor: useful in cases where a custom constructor/destructor are required and the original class is not to be modified.      
//        staticFuncVarArgs(NewTestObj::construct,_T("constructor")).   // Using a static member constructor.
        staticFunc(globalFunc,_T("globalFunc")).                        // Any global function can be registered in a class namespace (no 'this' pointer will be passed to the function).
        staticFunc(globalClass,&GlobalClass::func,_T("globalClassFunc")).
        func(&NewTestObj::newtestR1,_T("newtestR1")).
        var(&NewTestObj::val,_T("val")).
        var(&NewTestObj::s1,_T("s1")).
        var(&NewTestObj::s2,_T("s2")).
        var(&NewTestObj::c1,_T("c1"),VAR_ACCESS_READ_ONLY).
        var(&NewTestObj::c2,_T("c2"),VAR_ACCESS_READ_ONLY).
        funcVarArgs(&NewTestObj::multiArgs,_T("multiArgs"));

#define SQ_10 10
#define SQ_E 2.71828182845904523536f
#define SQ_PI 3.14159265358979323846264338327950288f
#define SQ_CONST_STRING _T("A constant string")
      const int intConstant     = 7;
      const float floatConstant = 8.765f;
      const bool boolConstant   = true;
#if 1
      SQClassDef<Vector3>(_T("Vector3")).
        var(&Vector3::x,_T("x")).
        var(&Vector3::y,_T("y")).
        var(&Vector3::z,_T("z")).
        func(&Vector3::Inc,_T("Inc")).
        func(&Vector3::operator+,_T("_add")).
        staticFunc(&Add2,_T("Add2")).
        staticFuncVarArgs(&Add,_T("Add")).
#if 1
        staticVar(&Vector3::staticVar,_T("staticVar")).
#else
        staticVar(&Vector3::staticVar,_T("staticVar"),VAR_ACCESS_READ_ONLY).
#endif
        staticVar(&globalVar,_T("globalVar")).
        constant(SQ_10,_T("SQ_10")).
        constant(SQ_E,_T("SQ_E")).
        constant(SQ_PI,_T("SQ_PI")).
        constant(SQ_CONST_STRING,_T("SQ_CONST_STRING")).
        enumInt(SQ_ENUM_TEST,_T("SQ_ENUM_TEST")).
        constant(intConstant,_T("intConstant")).
        constant(floatConstant,_T("floatConstant")).
        constant(true,_T("boolTrue")).
        constant(false,_T("boolFalse")).
        constant(boolConstant,_T("boolConstant"));
#endif

#endif

      testSquirrelObjectSetGet(); // Uses Vector3().

      BindConstant(SQ_PI*2,_T("SQ_PI_2"));
      BindConstant(SQ_10*2,_T("SQ_10_2"));
      BindConstant(_T("Global String"),_T("GLOBAL_STRING"));

      SquirrelObject testStaticVars = SquirrelVM::CompileBuffer(_T(" local v = Vector3(); local v2 = Vector3(); local v3 = v+v2; v3 += v2; print(\"v3.x: \"+v3.x); print(\"Vector3::staticVar: \"+v.staticVar+\" Vector3::globalVar: \"+v.globalVar); v.staticVar = 0; "));
      SquirrelVM::RunScript(testStaticVars);

      SquirrelObject testConstants0 = SquirrelVM::CompileBuffer(_T(" print(\"SQ_PI*2: \"+SQ_PI_2+\" SQ_10_2: \"+SQ_10_2+\" GLOBAL_STRING: \"+GLOBAL_STRING); "));
      SquirrelVM::RunScript(testConstants0);

      SquirrelObject testConstants1 = SquirrelVM::CompileBuffer(_T("local v = Vector3(); print(\"SQ_10: \"+v.SQ_10+\" SQ_E: \"+v.SQ_E+\" SQ_PI: \"+v.SQ_PI+\" SQ_CONST_STRING: \"+v.SQ_CONST_STRING+\" SQ_ENUM_TEST: \"+v.SQ_ENUM_TEST);" ));
      SquirrelVM::RunScript(testConstants1);
      SquirrelObject testConstants2 = SquirrelVM::CompileBuffer(_T("local v = Vector3(); print(\"intConstant: \"+v.intConstant+\" floatConstant: \"+v.floatConstant+\" boolTrue: \"+(v.boolTrue?\"True\":\"False\")+\" boolFalse: \"+(v.boolFalse?\"True\":\"False\")+\" boolConstant: \"+(v.boolConstant?\"True\":\"False\"));" ));
      SquirrelVM::RunScript(testConstants2);

      SquirrelObject scriptedBase = SquirrelVM::CompileBuffer(_T(" class ScriptedBase { sbval = 5551212; function multiArgs(a,...) { print(\"SBase: \"+a+val); } \n } \n ")); // Note val does not exist in base.
      SquirrelVM::RunScript(scriptedBase);

      // === BEGIN Instance Test ===

      SQClassDef<PlayerManager::Player>(_T("PlayerManager::Player")).
        func(&PlayerManager::Player::printName,_T("printName")).
        var(&PlayerManager::Player::name,_T("name"));

      SQClassDef<PlayerManager>(_T("PlayerManager")).
        func(&PlayerManager::GetPlayer,_T("GetPlayer")).
        var(&PlayerManager::playerVar,_T("playerVar"));

      RegisterGlobal(getPlayerManager,_T("getPlayerManager"));
      BindVariable(&playerManager,_T("playerManagerVar"));

      SquirrelObject testGetInstance = SquirrelVM::CompileBuffer(_T("\
        local PlayerManager = getPlayerManager(); \n\
        local oPlayer = PlayerManager.GetPlayer(0); \n\
        print(typeof oPlayer); \n\
        oPlayer.printName(); \n\
        PlayerManager.playerVar.printName(); \n\
        print(PlayerManager.playerVar.name); \n\
        oPlayer = PlayerManager.playerVar; \n\
        oPlayer.name = \"New_Name1\"; \n\
        playerManagerVar.playerVar.printName(); \n\
        oPlayer.name = \"New_Name2\"; \n\
      "));
      SquirrelVM::RunScript(testGetInstance);
      scprintf(_T("playerManager.playerVar.name: %s\n"),playerManager.playerVar.name.s);

      // === END Instance Test ===

      // === BEGIN example from forum post ===

      SQClassDef<Creature>(_T("Creature")).
        func(&Creature::GetMaxHealth,_T("GetMaxHealth")).
        func(&Creature::GetHealth,_T("GetHealth")).
        func(&Creature::SetHealth,_T("SetHealth"));

      SquirrelObject testClass = SquirrelVM::CompileBuffer( _T("function HealthPotionUse(Target) { \n\
                                                               local curHealth = Target.GetHealth(); \n\
                                                               local maxHealth = Target.GetMaxHealth(); \n\
                                                               if ((maxHealth - curHealth) > 15) { \n\
                                                                 curHealth += 15; \n\
                                                               } else { \n\
                                                                 curHealth = maxHealth; \n\
                                                               } \n\
                                                               Target.SetHealth(curHealth); \n\
                                                               print(typeof Target); \n\
                                                               return Target; \n\
                                                             }"));
      Creature frodo;
      frodo.SetHealth(frodo.GetMaxHealth()/2);

      SquirrelVM::RunScript(testClass);

      Creature newFrodo = SquirrelFunction<Creature &>(_T("HealthPotionUse"))(frodo); // Pass by value and return a copy (Must return by reference due to template system design).
      SquirrelFunction<void>(_T("HealthPotionUse"))(&frodo);                          // Pass the address to directly modify frodo.
      scprintf(_T("Frodo's health: %d %d\n"),frodo.GetHealth(),newFrodo.GetHealth());

      // === END example from forum post ===

#ifdef SQ_USE_CLASS_INHERITANCE
      // Base class constructors, if registered, must use this form: static int construct(HSQUIRRELVM v).
//      SQClassDef<CustomTestObj> customClass(_T("CustomTestObj"));
      SQClassDef<CustomTestObj> customClass(_T("CustomTestObj"),_T("ScriptedBase"));
//      SQClassDef<CustomTestObj> customClass(_T("CustomTestObj"),_T("NewTestObj"));
      customClass.staticFuncVarArgs(&CustomTestObj::construct,_T("constructor"),_T("*"));                  // MUST use this form (or no args) if CustomTestObj will be used as a base class.
                                                                                                   // Using the "*" form will allow a single constructor to be used for all cases.
//      customClass.staticFuncVarArgs(CustomTestObj::construct,_T("constructor"));                     // (this form is also OK if used as a base class)
      customClass.funcVarArgs(&CustomTestObj::varArgTypesAndCount,_T("multiArgs"),_T("*"));                // "*": no type or count checking.
      customClass.funcVarArgs(&CustomTestObj::varArgTypesAndCount,_T("varArgTypesAndCount"),_T("*"));      // "*": no type or count checking.
#else
      SQClassDef<CustomTestObj> customClass(_T("CustomTestObj"));
      customClass.staticFuncVarArgs(&CustomTestObj::construct,_T("constructor"),_T("snb"));                // string, number, bool (all types must match).
      customClass.funcVarArgs(&CustomTestObj::varArgTypesAndCount,_T("varArgTypesAndCount"),_T("*"));      // "*": no type or count checking.
#endif
      customClass.funcVarArgs(&CustomTestObj::varArgTypes,_T("varArgTypes"),_T("s|ns|ns|ns|n"));           // string or number + string or number.
      customClass.funcVarArgs(&CustomTestObj::noArgsVariableReturn,_T("noArgsVariableReturn"));        // No type string means no arguments allowed.
      customClass.func(&CustomTestObj::variableArgsFixedReturnType,_T("variableArgsFixedReturnType")); // Variables args, fixed return type.
      customClass.func(&CustomTestObj::manyArgs,_T("manyArgs"));                                       // Many args, type checked.
      customClass.func(&CustomTestObj::manyArgsR1,_T("manyArgsR1"));                                   // Many args, type checked, one return value.

#ifdef SQ_USE_CLASS_INHERITANCE
//      SquirrelObject testInheritance = SquirrelVM::CompileBuffer(_T(" class Derived extends NewTestObj { s1 = 123; \n constructor() { NewTestObj.constructor(this); }; function getParentS2() return s2; \n }; \n local t = Derived(); \n print(\"DerS2: \"+t.getParentS2()); t.multiArgs(); //t.newtestR1(\"R1in\"); "));
//      SquirrelObject testInheritance = SquirrelVM::CompileBuffer(_T(" local t = CustomTestObj(\"sa\",321,true); \n t.val = 444; print(t.val); t.variableArgsFixedReturnType(4,5.5); t.multiArgs(1,2,3); t.newtestR1(\"R1in\"); "));
//      SquirrelObject testInheritance = SquirrelVM::CompileBuffer(_T(" class Derived extends CustomTestObj { val = 888; \n function func(a) print(a+dVal);\n } \n local x = Derived(); print(\"x.val \"+x.val); local t = CustomTestObj(\"sa\",321,true); \n t.val = 444; print(t.val); t.variableArgsFixedReturnType(4,5.5); t.multiArgs(1,2,3); t.newtestR1(\"R1in\"); "));
      SquirrelObject testInheritance = SquirrelVM::CompileBuffer(_T(" class Derived extends CustomTestObj { val = 888; \n function multiArgs(a,...) { print(a+val); \n print(sbval); ::CustomTestObj.multiArgs(4); ::ScriptedBase.multiArgs(5,6,7); \n }\n } \n local x = Derived(); print(\"x.val \"+x.val); x.multiArgs(1,2,3); "));
//      SquirrelObject testInheritance = SquirrelVM::CompileBuffer(_T(" class Derived extends CustomTestObj { val = 888; \n function multiArgs(a,...) print(a+val);\n } \n local x = Derived(); print(\"x.val \"+x.val); x.multiArgs(1,2,3); //local t = CustomTestObj(); \n t.val = 444; print(t.val); t.variableArgsFixedReturnType(4,5.5); t.multiArgs(1,2,3); t.newtestR1(\"R1in\"); "));
      printf("=== BEGIN INHERITANCE ===\n");
      testInhertianceCase();
      SquirrelVM::RunScript(testInheritance);
      printf("===  END INHERITANCE  ===\n");
#endif

      SquirrelObject testRegV = SquirrelVM::CompileBuffer(_T(" local vec = Vector3(); print(vec.x); vec = vec.Add(vec); print(vec.x); vec = vec.Add(vec); print(vec.x); vec = vec.Add2(vec,vec); print(vec.x); local v2 = Vector3(); vec = v2.Inc(vec); print(vec.x); print(v2.x); "));
      SquirrelVM::RunScript(testRegV);


#ifdef SQ_USE_CLASS_INHERITANCE
      SquirrelObject testReg0 = SquirrelVM::CompileBuffer(_T(" co <- CustomTestObj(\"hello\",123,true); co.varArgTypes(\"str\",123,123,\"str\"); co.varArgTypes(123,\"str\",\"str\",123); "));
      SquirrelVM::RunScript(testReg0);

      SquirrelObject testReg0a = SquirrelVM::CompileBuffer(_T(" print(co.varArgTypesAndCount(1,true)); print(co.varArgTypesAndCount(2,false,3.)); print(\"\\n\"); "));
      SquirrelVM::RunScript(testReg0a);

      SquirrelObject testReg0b = SquirrelVM::CompileBuffer(_T(" print(co.noArgsVariableReturn()); print(co.noArgsVariableReturn()); print(co.noArgsVariableReturn()); print(\"\\n\"); "));
      SquirrelVM::RunScript(testReg0b);

      SquirrelObject testReg0c = SquirrelVM::CompileBuffer(_T(" print(co.variableArgsFixedReturnType(1)); print(co.variableArgsFixedReturnType(1,2)); print(co.variableArgsFixedReturnType(1,2,3)); print(\"\\n\"); "));
      SquirrelVM::RunScript(testReg0c);

      SquirrelObject testReg0d = SquirrelVM::CompileBuffer(_T(" co.manyArgs(111,222.2,true,\"Hello\"); print(co.manyArgsR1(333,444.3,false,\"World\")); print(\"\\n\"); "));
      SquirrelVM::RunScript(testReg0d);

      SquirrelObject testReg1a = SquirrelVM::CompileBuffer(_T(" co <- CustomTestObj(\"hello\",123,true); co.noArgsVariableReturn(); local t = NewTestObj(\"S1in\",369,true); print(\"C1: \"+t.c1); print(\"C2: \"+t.c2); // t.c1 = 123; "));
      SquirrelVM::RunScript(testReg1a);

      // Constant test (read only var). Var can change on C++ side, but not on script side.
      try {
        SquirrelObject testRegConstant = SquirrelVM::CompileBuffer(_T(" local t = NewTestObj(); t.c1 = 123; "));
        SquirrelVM::RunScript(testRegConstant);
      } // try
      catch (SquirrelError & e) {
        scprintf(_T("Error: %s, %s\n"),e.desc,_T("Squirrel::TestConstant"));
      } // catch

      SquirrelObject testReg1 = SquirrelVM::CompileBuffer(_T(" local t = NewTestObj(); t.newtestR1(\"Hello\"); t.val = 789; print(t.val); print(t.s1); print(t.s2); t.s1 = \"New S1\"; print(t.s1); "));
      SquirrelVM::RunScript(testReg1);

      SquirrelObject testReg2 = SquirrelVM::CompileBuffer(_T(" local t = NewTestObj(); t.val = 789; print(t.val); t.val = 876; print(t.val); t.multiArgs(1,2,3); t.multiArgs(1,2,3,4); t.globalFunc(\"Hola\",5150,false); t.globalClassFunc(\"Bueno\",5151,true); "));
      SquirrelVM::RunScript(testReg2);
      SquirrelObject testReg3 = SquirrelVM::CompileBuffer(_T(" test(); local rv = testR1(\"Hello\"); print(rv); "));
      SquirrelVM::RunScript(testReg3);     
      SquirrelObject testReg4 = SquirrelVM::CompileBuffer(_T(" print(\"\\nMembers:\"); testObj_newtest1(); testObj_newtest2(); print(testObj_newtestR1(\"Hello Again\")); "));
      SquirrelVM::RunScript(testReg4);

      SquirrelObject defCallFunc = SquirrelVM::CompileBuffer(_T(" function callMe(var) { print(\"I was called by: \"+var); return 123; }"));
      SquirrelVM::RunScript(defCallFunc);

      SquirrelObject defCallFuncStrRet = SquirrelVM::CompileBuffer(_T(" function callMeStrRet(var) { print(\"I was called by: \"+var); return var; }"));
      SquirrelVM::RunScript(defCallFuncStrRet);

      SquirrelFunction<void>(_T("callMe"))(_T("Squirrel 1"));

      // Get a function from the root table and call it.
#if 1
      SquirrelFunction<int> callFunc(_T("callMe"));
      int ival = callFunc(_T("Squirrel"));
      scprintf(_T("IVal: %d\n"),ival);

      SquirrelFunction<const SQChar *> callFuncStrRet(_T("callMeStrRet"));
      const SQChar * sval = callFuncStrRet(_T("Squirrel StrRet"));
      scprintf(_T("SVal: %s\n"),sval);
#endif
      ival = 0;
      // Get a function from any table.
      SquirrelFunction<int> callFunc2(root.GetObjectHandle(),_T("callMe"));
      ival = callFunc(456); // Argument count is checked; type is not.

      // === END Class Instance tests ===

      SquirrelObject main = SquirrelVM::CompileBuffer(_T("table1 <- {key1=\"keyVal\",key2 = 123};\n if (\"key1\" in table1)\n print(\"Sq: Found it\");\n else\n print(\"Sq: Not found\");"));
      SquirrelVM::RunScript(main);
      SquirrelObject table1 = root.GetValue(_T("table1"));
      if (table1.Exists(_T("key1"))) {
        scprintf(_T("C++: Found it.\n"));
      } else {
        scprintf(_T("C++: Did not find it.\n"));
      } // if

      // === BEGIN Simple variable binding tests ===

      int iVar = 777;
      float fVar = 88.99f;
      bool bVar = true;
      BindVariable(root,&iVar,_T("iVar"));
      BindVariable(root,&fVar,_T("fVar"));
      BindVariable(root,&bVar,_T("bVar"));

      static ScriptStringVar128 testString;
      scsprintf(testString,_T("This is a test string"));
      BindVariable(root,&testString,_T("testString"));

      // === END Simple variable binding tests ===

      // === BEGIN Array Tests ===

      SquirrelObject array = SquirrelVM::CreateArray(10);
      int i;
      for (i = 0; i < 10; i++) array.SetValue(i,i);
      array.ArrayAppend(123);          // int
      array.ArrayAppend(true);         // bool (must use bool and not SQBool (SQBool is treated as INT by compiler).
      array.ArrayAppend(false);        // bool (must use bool and not SQBool (SQBool is treated as INT by compiler).
      array.ArrayAppend(123.456f);     // float
      array.ArrayAppend(_T("string")); // string
      array.ArrayAppend(456);          // Will be popped and thrown away (below).
      array.ArrayAppend((SQUserPointer)0);

      // Pop 3 items from array:
      array.ArrayPop(SQFalse);                 // Don't retrieve the popped value (int:123).
      SquirrelObject so1 = array.ArrayPop();   // Retrieve the popped value.
      const SQChar * val1 = so1.ToString();      // Get string.
      float val2 = array.ArrayPop().ToFloat(); // Pop and get float.
      scprintf(_T("[Popped values] Val1: %s, Val2: %f\n"),val1,val2);

      int startIndex = array.Len();
      array.ArrayExtend(10); // Implemented as: ArrayResize(Len()+amount).
      for (i = startIndex; i < array.Len(); i++) array.SetValue(i,i*10);
      root.SetValue(_T("array"),array);

      SquirrelObject arrayr = array.Clone(); // Get a copy as opposed to another reference.
      arrayr.ArrayReverse();
      root.SetValue(_T("arrayr"),arrayr);

      // === END Array Tests ===

      SquirrelObject define_printArray = SquirrelVM::CompileBuffer(_T(" function printArray(name,array) { print(name+\".len() = \"+array.len()); foreach(i, v in array) if (v != null) { if (typeof v == \"bool\") v = v ? \"true\" : \"false\"; print(\"[\"+i+\"]: \"+v); } } "));
      SquirrelVM::RunScript(define_printArray);
      SquirrelObject test = SquirrelVM::CompileBuffer(_T(" printArray(\"array\",array); printArray(\"arrayr\",arrayr); "));

      SquirrelVM::RunScript(test);
#endif
    } // try
    catch (SquirrelError & e) {
      scprintf(_T("Error: %s, in %s\n"),e.desc,_T("TestSqPlus"));
    } // catch

  }

  ~TestSqPlus() {
    SquirrelVM::Shutdown();
  }

};

void doTest(void) {
  TestSqPlus testSqPlus;
} // doTest

int main(int argc,char * argv[]) {

  // Run twice to make sure cleanup/shutdown works OK.
  SCPUTS(_T("Start Pass 1\n"));
  doTest();
#if 0
  SCPUTS(_T("Start Pass 2\n"));
  doTest();
#endif
  SCPUTS(_T("Done.\n"));

  scprintf(_T("Press RETURN to exit."));
  getchar();

	return 0;
}

