/*******************************************************************************
 *	Gen.cc		Default output
 *			T.Barnaby,	BEAM Ltd,	12/9/03
 *******************************************************************************
 */
#define	DEBUG	1

#include <stdio.h>
#include <stdarg.h>
#include <strings.h>
#include <Gen.h>
#include <bidl.h>


FileIndent::FileIndent(){
	oindent = 0;
}

void FileIndent::indentMore(){
	oindent++;
}

void FileIndent::indentLess(){
	if(--oindent < 0)
		oindent = 0;
}

int FileIndent::writeLine(BString line){
	BString	s;
	int	i = oindent;

	while(i--)
		s = s + "\t";
	s = s + line;
	return writeString(s);
}

int FileIndent::printf(const char* fmt, ...){
	va_list		args;
	char*		s = 0;
	int		ret;

	va_start(args, fmt);
	ret = vasprintf(&s, fmt, args);
	va_end(args);
	if(ret >= 0){
		ret = writeLine(s);
		free(s);
	}

	return ret;
}

StringIndent::StringIndent(){
	oindent = 0;
}

void StringIndent::indentMore(){
	oindent++;
}

void StringIndent::indentLess(){
	if(--oindent < 0)
		oindent = 0;
}

void StringIndent::writeLine(BString line){
	int	i = oindent;

	while(i--)
		append("\t");
	append(line);
}

void StringIndent::printf(const char* fmt, ...){
	va_list		args;
	char*		s = 0;
	int		ret;

	va_start(args, fmt);
	ret = vasprintf(&s, fmt, args);
	va_end(args);
	if(ret >= 0){
		writeLine(s);
		free(s);
	}
}



Gen::Gen(){
	ouseBObjects = 0;
}

Gen::~Gen(){
}

void Gen::setOptions(BDictString& options){
	ooptions = options;
}

int Gen::setUseBObjects(int on){
	int	ret = ouseBObjects;

	ouseBObjects = on;

	return ret;	
}

int Gen::getUseBObjects(){
	return ouseBObjects;
}

BString Gen::getTypeName(Node* n, int data){
	BString	typeName;

	if(ouseBObjects){
		if(n->nodeType() == Node::TTYPELIST){
			return BString("BObjListVar<") + getTypeName(n->node(0), data) + " >";
		}
		else {
			typeName = n->name();
			if(typeName == "Int32"){
				if(data)
					return "BObjInt";
				else
					return "BInt32";
			}
			else if(typeName == "UInt32"){
				if(data)
					return "BObjInt";
				else
					return "BUInt32";
			}
			else if(typeName == "Bool"){
				if(data)
					return "BObjInt";
				else
					return "BInt32";
			}
			else if(typeName == "String"){
				if(data)
					return "BObjString";
				else
					return "BString";
			}
			else if(typeName == "Error")	return "BError";
			else if(typeName == "Date")	return "BObjDate";
			else if(typeName == "Time")	return "BObjTime";
			else if(typeName == "DateTime")	return "BObjDateTime";
			else if(typeName == "Id")	return "BObjId";
			else if(typeName == "ObjData")	return "BObjData";
			else if(typeName == "TimeStamp")	return "BTimeStamp";
			else if(typeName == "Complex")	return "BComplex";
			else return typeName;
		}
	}
	else {
		if(n->nodeType() == Node::TTYPELIST){
			return BString("BList<") + getTypeName(n->node(0), data) + " >";
		}
		else if(n->nodeType() == Node::TTYPEARRAY){
			return BString("BArray<") + getTypeName(n->node(0), data) + " >";
		}
		else if(n->nodeType() == Node::TTYPEDICT){
			return BString("BDict<") + getTypeName(n->node(0), data) + " >";
		}
		else {
			typeName = n->name();
			if(typeName == "Int8"){
				return "BInt8";
			}
			else if(typeName == "Int16"){
				return "BInt16";
			}
			else if(typeName == "Int32"){
				return "BInt32";
			}
			else if(typeName == "Int64"){
				return "BInt64";
			}
			else if(typeName == "UInt8"){
				return "BUInt8";
			}
			else if(typeName == "UInt16"){
				return "BUInt16";
			}
			else if(typeName == "UInt32"){
				return "BUInt32";
			}
			else if(typeName == "UInt64"){
				return "BUInt64";
			}
			else if(typeName == "Float32"){
				return "BFloat32";
			}
			else if(typeName == "Float64"){
				return "BFloat64";
			}
			else if(typeName == "Bool"){
				return "BInt32";
			}
			else if(typeName == "Char"){
				return "BChar";
			}
			else if(typeName == "String"){
				return "BString";
			}
			else if(typeName == "Error")	return "BError";
			else if(typeName == "Date")	return "BDate";
			else if(typeName == "Time")	return "BTime";
			else if(typeName == "DateTime")	return "BDateTime";
			else if(typeName == "Id")	return "BObjId";
			else if(typeName == "ObjData")	return "BObjData";
			else if(typeName == "TimeStamp")	return "BTimeStamp";
			else if(typeName == "Complex")	return "BComplex";
			else return typeName;
		}
	}
}

BError Gen::getTypeInfo(Node* n, BType& type, BTypeComp& typeMod, BUInt& size, BString& typeName){
	BError	err;

	if(n->nodeType() == Node::TTYPELIST){
		typeMod = BTypeCompList;
		size = atoi(n->node(2)->name());
	}
	else if(n->nodeType() == Node::TTYPEARRAY){
		typeMod = BTypeCompArray;
		size = atoi(n->node(2)->name());
	}
	else if(n->nodeType() == Node::TTYPEDICT){
		typeMod = BTypeCompDict;
		size = atoi(n->node(2)->name());
	}
	else if(n->nodeType() == Node::TSTRUCTITEM_ARRAYFIXED){
		typeMod = BTypeCompArrayFixed;
		size = atoi(n->node(2)->name());
	}
	else{
		typeMod = BTypeCompSingle;
		size = 1;
	}
	
	typeName = n->node(0)->name();
	if(typeName == "Bool"){
		type = BTypeBool;
	}
	else if(typeName == "Int8"){
		type = BTypeInt8;
	}
	else if(typeName == "UInt8"){
		type = BTypeUInt8;
	}
	else if(typeName == "Int16"){
		type = BTypeInt16;
	}
	else if(typeName == "UInt16"){
		type = BTypeUInt16;
	}
	else if(typeName == "Int32"){
		type = BTypeInt32;
	}
	else if(typeName == "UInt32"){
		type = BTypeUInt32;
	}
	else if(typeName == "Int64"){
		type = BTypeInt64;
	}
	else if(typeName == "UInt64"){
		type = BTypeUInt64;
	}
	else if(typeName == "Float32"){
		type = BTypeFloat32;
	}
	else if(typeName == "Float64"){
		type = BTypeFloat64;
	}
	else if(typeName == "Char"){
		type = BTypeChar;
	}
	else if(typeName == "String"){
		type = BTypeString;
	}
	else if(typeName == "Time"){
		type = BTypeTime;
	}
#ifdef ZAP
	else if(typeName == "Error")	type = "BError";
	else if(typeName == "Date")	type = "BDate";
	else if(typeName == "DateTime")	type = "BDateTime";
	else if(typeName == "Id")	type = "BObjId";
	else if(typeName == "ObjData")	type = "BObjData";
	else if(typeName == "TimeStamp")	type = "BTimeStamp";
	else if(typeName == "Complex")	type = "BComplex";
#endif
	else {
		if(getBaseClass(n) == "BObj")
			type = BTypeObj;
		else
			type = BTypeNone;
	}
	
	return err;
}

BString Gen::getBaseClass(Node* node){
	BString	baseClass;
	
	if(node->nodeType() == Node::TSTRUCT){
		if((node->nodes().number() >= 2) && node->node(1) && (node->node(1)->nodeType() == Node::TDERIVED)){
			if(node->nodes()[1]){
				return node->node(1)->node(0)->name();
			}
		}
	}
	return baseClass;
}

int Gen::isBaseType(Node* n){
	BString	typeName;
	Type*	t;
	BIter	i;

	typeName = n->name();
//	printf("isRawType: %d %s\n", n->nodeType(), typeName.retStr());

	if(n->nodeType() == Node::TTYPE){
		if(typeName == "Int8")		return 1;
		else if(typeName == "UInt8")	return 1;
		else if(typeName == "Int16")	return 1;
		else if(typeName == "UInt16")	return 1;
		else if(typeName == "Int32")	return 1;
		else if(typeName == "UInt32")	return 1;
		else if(typeName == "Int64")	return 1;
		else if(typeName == "UInt64")	return 1;
		else if(typeName == "Float32")	return 1;
		else if(typeName == "Float64")	return 1;
		else if(typeName == "Double")	return 1;
		else if(typeName == "Bool")	return 1;
		else if(typeName == "Char")	return 1;
	}
	
	return 0;
}


int Gen::isRawType(Node* n){
	BString	typeName;
	Type*	t;
	BIter	i;

	typeName = n->name();
//	printf("isRawType: %d %s\n", n->nodeType(), typeName.retStr());

	if(n->nodeType() == Node::TTYPEARRAY){
		return 0;
	}
	else if(n->nodeType() == Node::TTYPE){
		if(typeName == "Int8")		return 1;
		else if(typeName == "UInt8")	return 1;
		else if(typeName == "Int16")	return 1;
		else if(typeName == "UInt16")	return 1;
		else if(typeName == "Int32")	return 1;
		else if(typeName == "UInt32")	return 1;
		else if(typeName == "Int64")	return 1;
		else if(typeName == "UInt64")	return 1;
		else if(typeName == "Float32")	return 1;
		else if(typeName == "Float64")	return 1;
		else if(typeName == "Double")	return 1;
		else if(typeName == "Bool")	return 1;
		else if(typeName == "String")	return 0;
		else if(typeName == "Error")	return 0;
		else if(typeName == "Date")	return 0;
		else if(typeName == "DateTime")	return 0;
		else if(typeName == "Id")	return 0;
		else if(typeName == "ObjData")	return 0;
		else if(typeName == "TimeStamp")	return 0;
		else if(typeName == "Complex")	return 0;
		else {
			if((t = gtypelist.search(typeName)) && (t->node())){
//				printf("gtypelist: %s\n", t->node()->name().retStr());
				return isRawType(t->node());
			}
			else{
				return 0;
			}
		}
	}
	else if(n->nodes().number()){
		for(n->nodes().start(i); !n->nodes().isEnd(i); n->nodes().next(i)){
			if(!isRawType(n->nodes()[i]))
				return 0;
		}

		return 1;
	}
	else {
		return 1;
	}
}

int Gen::useCopyType(Node* n){
	BString	typeName;

	if(n->nodeType() == Node::TTYPE){
		typeName = n->name();
		
		if((typeName == "String") || (typeName == "Error"))
			return 1;
	}
	
	return isRawType(n);
}
