#include "StdAfx.h"
#include "tclinterpreter.h"

TclInterpreter::TclInterpreter(void)
{
	interp = Tcl_CreateInterp();
	verbose = 0;
}

TclInterpreter::~TclInterpreter(void)
{
}

void TclInterpreter::Restart()
{
	Tcl_DeleteInterp(interp);
	interp = Tcl_CreateInterp();
}

int TclInterpreter::EvalFile(char * filename)
{
	return (Tcl_EvalFile(interp, (char *)filename)==TCL_OK);
}

int TclInterpreter::Eval(char * script)
{
	return (Tcl_Eval(interp,(char *)script)==TCL_OK);
}

// tries each namespace in order of ancestry (up to the global namespace) looking for the given variable name
// returns null if not found
Tcl_Obj * TclInterpreter::ScopedLookup(const char * name1, const char * name2)
{
	char nspace[2048];
	int i;
	std::string buffer;
	if(name1){
		i = (int)strlen(name1);
		memcpy(nspace,name1,i+1);
		i--;
	} else {
		nspace[0] = '\0';
		i = -1;
	}
	do {
		buffer = nspace;
		buffer += "::";
		buffer += name2;
		Tcl_Obj * ptr = Tcl_GetVar2Ex(interp,(char *)buffer.data(),NULL,0);
		if(ptr)
			return ptr;
		// remove the last namespace
		for(;i>-1;i--){
			if(nspace[i]==':'&& nspace[i+1]==':'){
				nspace[i] = '\0';
				break;
			}
		}
	} while(i>0);

	// try the global namespace
	Tcl_Obj * ptr = Tcl_GetVar2Ex(interp,(char *)name2,NULL,TCL_GLOBAL_ONLY);
	if(ptr)
		return ptr;
	return NULL;
}

char * TclInterpreter::GetString(const char * name1, const char * name2, char * defval)
{
	Tcl_Obj * ptr = ScopedLookup(name1,name2);
	char * x;
	if(ptr){
		x = Tcl_GetString(ptr);
	} else 
		x = defval;
	return x;
}

TCHAR * TclInterpreter::GetWideString(const char * name1, const char * name2, TCHAR * defval)
{
	char * str = GetString(name1,name2,NULL);
	TCHAR * x;
	if(str){
		static TCHAR buffer[1024];
		MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,str,-1,buffer,1024);
		x = buffer;
	} else
		x = (TCHAR*)defval;
	if(verbose)
		print(L"Tcl: %S::%S = %s\n",name1,name2,x);
	return x;
}

int TclInterpreter::GetInt(const char * name1, const char * name2, int defval)
{
	Tcl_Obj * ptr = ScopedLookup(name1,name2);
	int x;
	if(ptr){
		Tcl_GetIntFromObj(interp,ptr,&x);
	} else
		x = defval;
	if(verbose)
		print(L"Tcl: %S::%S = %d\n",name1,name2,x);
	return x;
}

double TclInterpreter::GetDouble(const char * name1, const char * name2, double defval)
{
	Tcl_Obj * ptr = ScopedLookup(name1,name2);
	double x;
	if(ptr){
		Tcl_GetDoubleFromObj(interp,ptr,&x);
	} else
		x = defval;
	if(verbose)
		print(L"Tcl: %S::%S = %f\n",name1,name2,x);
	return x;
}

unsigned int TclInterpreter::GetColor(const char * name1, const char * name2, unsigned int defval)
{
	char * str = GetString(name1,name2,NULL);
	unsigned int x;
	if(str){
		x = strtoul(str,NULL,16);
	} else
		x = defval;
	if(verbose)
		print(L"Tcl: %S::%S = %x\n",name1,name2,x);
	return x;
}

int TclInterpreter::GetList(Vector<std::string>& array, const char * name1, const char * name2)
{
	Tcl_Obj * ptr = ScopedLookup(name1,name2);
	if(ptr){
		// place the list into the array
		int n = 0;
		Tcl_ListObjLength(interp, ptr, &n);
		if(n==0)
			return 0;
		array.allocate(n);
		// get the items
		int i;
		for(i=0;i<n;i++){
			Tcl_Obj * elm = 0;
			Tcl_ListObjIndex(interp,ptr,i,&elm);	
			if(elm){
				array[i] = Tcl_GetString(elm);
			}
		}
		return 1;
	} else 
		return 0;
}