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

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

BString GenBDataPy::getTypeName(Node* n, int data){
	BString	typeName;
	
	if(n->nodeType() == Node::TTYPELIST){
		return BString("BList");
	}
	else if(n->nodeType() == Node::TTYPEARRAY){
		return BString("BList");
	}
	else if(n->nodeType() == Node::TTYPEDICT){
		return BString("BList");
	}
	else {
		typeName = n->name();
		if(typeName == "Int32")		return "BInt32";
		else if(typeName == "UInt32")	return "BUInt32";
		else if(typeName == "Int16")	return "BInt16";
		else if(typeName == "UInt16")	return "BUInt16";
		else if(typeName == "Int8")	return "BInt8";
		else if(typeName == "UInt8")	return "BUInt8";
		else if(typeName == "Int64")	return "BInt64";
		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 == "String")	return "BString";
		else if(typeName == "Error")	return "BError";
		else if(typeName == "TimeStamp")return "BTimeStamp";
		else return typeName;
	}
}

void GenBDataPy::produceImp(Node* n){
	BString		s;
	BString		t;
	BIter		i;
	BList<Node*>*	nl;
	BString		typeName;
	BString		line;
	
	switch(n->nodeType()){
	case Node::TMODULE:
		omodule = n->name();

		for(n->nodes().start(i); !n->nodes().isEnd(i); n->nodes().next(i)){
			produceImp(n->nodes()[i]);
		}
		break;
	case Node::TLIST:
		for(n->nodes().start(i); !n->nodes().isEnd(i); n->nodes().next(i)){
			produceImp(n->nodes()[i]);
		}
		break;
	case Node::TSTRUCT:
		if(n->name() == "BObj")
			return;

		typeName = BString("") + n->name();
		ofileImp.writeLine(BString("# ") + typeName + " Object Implementation\n");
		
		if((n->nodes().number() == 2) && n->node(1)){
			ofileImp.writeLine(BString("class ") + typeName + "(" + getTypeName(n->node(1), 1) + "):\n");
		}
		else {
			ofileImp.writeLine(BString("class ") + typeName + ":\n");
		}

		ofileImp.indentMore();
		line = "def __init__(s";
		nl = &n->node(0)->nodes();
		if(nl->number()){
			for(nl->start(i); !nl->isEnd(i); nl->next(i)){
				t = getTypeName(nl->get(i)->node(0), 1);
				s = nl->get(i)->node(1)->name();
				line += BString(", ") + s + " = " + t + "()";
			}
		}
		ofileImp.writeLine(line + "):\n");

		ofileImp.indentMore();
		if((n->nodes().number() == 2) && n->node(1)){
			ofileImp.writeLine(getTypeName(n->node(1), 1) + ".__init__(s);\n");
		}

		nl = &n->node(0)->nodes();
		if(nl->number()){
			for(nl->start(i); !nl->isEnd(i); nl->next(i)){
				t = getTypeName(nl->get(i)->node(0), 1);
				s = nl->get(i)->node(1)->name();
				ofileImp.writeLine(BString("s.") + s + " = " + s + ";\n");
			}
		}
		else {
			ofileImp.writeLine("pass;\n");
		}
		ofileImp.indentLess();
		ofileImp.indentLess();
		ofileImp.writeLine("\n");
		break;
	default:
		break;
	}
}

BError GenBDataPy::produceHeaderImp(){
	BError	err;

	ofileImp.printf("#############################################################################\n");
	ofileImp.printf("#\t%s\tProduced by Bidl\n", (ofileName + ".cc").retStr());
	ofileImp.printf("#############################################################################\n");
	ofileImp.printf("#\n");
	ofileImp.printf("from Beam import *\n");
	ofileImp.printf("\n\n");
	return err;
}
BError GenBDataPy::produceTrailerImp(){
	BError	err;
	
	return err;
}

GenBDataPy::GenBDataPy(){
}

GenBDataPy::~GenBDataPy(){
}

BError GenBDataPy::produce(Node* n, BString fileName){
	BError	err;
	
//	dprintf("GenBDataPy::produce: %p\n", n);

	ofileName = fileName;
	ofileImp.open(ofileName + ".py", "w");
	
	// File Headers
	produceHeaderImp();
	
	// Generate code
	produceImp(n);

	// Generate trailers
	produceTrailerImp();
	ofileImp.close();

	return err;
}
