@

function isNodeType(theType : node) {
	if theType.name == "base" || theType.name == "enum" return theType.pointers;
	if theType.name == "callback" return false;
	return true;
}

function getCppType(theType : node) {
	local sType = theType.is_const;
	switch(theType) {
		case "base":
		case "enum":
		case "struct":
		case "union":
		case "callback":
			sType += theType.name;
	}
	return sType + theType.pointers;
}

@// C++ CodeWorker interface for building dynamic library bindings
#include "CW4dl.h"
#include "ExternalValueNode.h"

#include "SDL.h"


//-------------------------------------------------------------------------
// Exported function 'SDL_Init'.
//
// Initialization of the module in CodeWorker.
// Registers all commands in CodeWorker, for recognizing them in the
// scripting language.
//-------------------------------------------------------------------------
CW4DL_EXPORT_SYMBOL void SDL_Init(CW4dl::Interpreter* interpreter) {
@
foreach i in this.functions {
	local sFunction = subString(i.key(), 4);
	if $i.parameters > 4$ {
		@	CW4dl::PARAMETER_TYPE @sFunction@[] = {@
		foreach j in i.parameters {
			if j.name == "..." break;
			if !j.first() {
				@, @
			}
			if isNodeType(j.type) {
				@CW4dl::NODE_PARAMETER@
			} else {
				@CW4dl::VALUE_PARAMETER@
			}
		}
		@};
@
	}
	@	interpreter->createCommand("@sFunction@"@
	if $i.parameters > 4$ {
		@, @sFunction@@
	} else {
		foreach j in i.parameters {
			if j.name == "..." break;
			@, CW4dl::@
			if isNodeType(j.type) {
				@NODE_PARAMETER@
			} else {
				@VALUE_PARAMETER@
			}
		}
	}
	@);
@
}

foreach i in this.constants {
	local sConstant = i.name.subString(4);
	@	CW4dl::Tree* p_@sConstant@ = interpreter->createVariable("@sConstant@");
	interpreter->setIntValue(p_@sConstant@, @i.name@);
@
}

@}


//-------------------------------------------------------
// Wrappers for all public structures
//-------------------------------------------------------

@
foreach i in this.structs if i.name.startString("SDL_") {
	local sStruct = i.name.subString(4);
	@class @sStruct@StructWrapper : public CodeWorker::ExternalValueNode {
	public:
		@i.name@* internal_;

	public:
		inline @sStruct@StructWrapper(@i.name@* internal = NULL) : internal_(internal) {}
};


@
}
@

//-------------------------------------------------------
// Wrappers for all unions
//-------------------------------------------------------

@
foreach i in this.unions if i.name.startString("SDL_") {
	local sUnion = i.name.subString(4);
	@class @sUnion@UnionWrapper : public CodeWorker::ExternalValueNode {
	public:
		@i.name@* internal_;

	public:
		inline @sUnion@UnionWrapper(@i.name@* internal = NULL) : internal_(internal) {}
};


@
}

@


//-------------------------------------------------------
// Wrappers for all callbacks
//-------------------------------------------------------

class CBKParamWrapper {
	public:
		std::string functionName_;
		CW4dl::Tree* data_;
};

@
foreach i in this.callbacks {
	@@getCppType(i.return_type)@ @i.name@CBKWrapper(@
	local bParams = (i.parameters#back.type.name == "void");
	foreach j in i.parameters {
		if !j.first() {@, @}
		@@getCppType(j.type)@ @j.name@@
	}
	@) {
@
	if bParams {
		@	CBKParamWrapper* pParams = (CBKParamWrapper*) @i.parameters#back.name@;
	if (pParams == NULL) globalInterpreter_->error("no @i.parameters#back.name@ instance for the callback '@i.name@'");
@
	}
@	CW4dl::Function* pCWCBK = globalInterpreter_->findFunction(@(bParams?"pParams->functionName_.c_str()":"\"" + i.name + "\"")@);
	if (pCWCBK == NULL) globalInterpreter_->error("No CodeWorker callback existing with the specified name, while triggering the callback '@i.name@'");
	const char* tcResult = globalInterpreter_->callFunction(pCWCBK@
	foreach j in i.parameters {
		@, @
		if j.last() && bParams {
			@pParams->data_@
		} else {
			@l_@j.name@@
		}
	}
	@);
	globalInterpreter_->releaseFunction(pCWCBK);
@
	switch(i.return_type.name) {
		case "int":
		case "Uint32":
			if i.return_type.pointers error("unhandled callback return type");
			@	return atoi(tcResult);
@
	}
@}

@
}
@


//-------------------------------------------------------
// Binding to the C functions of SDL
//-------------------------------------------------------

@
function convert2Cpp(param : node) {
	@	@getCppType(param.type)@ @param.name@;
@
	switch(param.type) {
		case "base":
			if param.type.pointers {
				if param.type.pointers == '*' && param.type.name == "void" {
					@	@param.name@ = a considerer!;
@
					break;
				} else if param.type.pointers == '*' && param.type.name == "FILE" {
					@	@param.name@ = a considerer;
@
					break;
				} else error("base* not handled yet (" + getCppType(param.type) + ")!");
			}
			switch(param.type.name) {
				case "double":
				case "float":
					@	@param.name@ = ((p_@param.name@ == NULL) ? 0.0 : atof((const char*) p_@param.name@));
@
					break;
				case "Sint8":
				case "Uint8":
				case "Sint16":
				case "Uint16":
				case "Sint32":
				case "Uint32":
				case "short":
				case "long":
				case "int":
					@	@param.name@ = ((p_@param.name@ == NULL) ? 0 : atoi((const char*) p_@param.name@));
@
					break;
				case "string":
					@	@param.name@ = (const char*) p_@param.name@;
@
					break;
			}
			break;
		case "enum":
			if param.type.pointers error("enum* not handled yet (" + getCppType(param.type) + ")!");
			@	@param.name@ = ((p_@param.name@ == NULL) ? 0 : atoi((const char*) p_@param.name@));
@
			break;
		case "struct":
			local sStruct = param.name.subString(4);
			@	if (p_@param.name@ != NULL) {
		@sStruct@StructWrapper* w_@param.name@ = dynamic_cast<@sStruct@StructWrapper*>((CW4dl::Tree*) p_@param.name@);
		if (w_@param.name@ != NULL) @param.name@ = w_@param.name@->instance_;
		else @param.name@ = NULL;
	} else @param.name@ = NULL;
@
			break;
		case "callback":
			@	@param.name@ = @param.type.name@CBKWrapper;
@
			break;
	}
}

foreach i in this.functions {
	local sFunction = subString(i.key(), 4);
	@CW4DL_EXPORT_SYMBOL const char* @sFunction@(CW4dl::Interpreter* interpreter@
	if $i.parameters > 4$ {
		@, CW4dl::Parameter* tParams@
	} else {
		foreach j in i.parameters {
			if j.name == "..." break;
			@, CW4dl::Parameter p_@j.name@@
		}
	}
	@) {
@
	if $i.parameters > 4$ {
		local iIndex = 0;
		foreach j in i.parameters {
			if j.name == "..." break;
			@	CW4dl::Parameter p_@j.name@ = tParams[@iIndex@];
@
			increment(iIndex);
		}
	}
	// translate parameters to C++
traceLine("++ " + sFunction + "()");
	foreach j in i.parameters {
		if j.name == "..." break;
local sError;
try {
		convert2Cpp(j);
} catch(sError) {
traceLine(sError);
traceObject(i);
}
	}
	@}

@
}
