// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author(s): Jonathan Berry

// This software is copyrighted by the DIMACS Center at Rutgers, The State
// University of New Jersey.  IT IS PROVIDED AS IS, AND THE AUTHORS, DIMACS, AND
// RUTGERS, THE STATE UNIVERSITY OF NEW JERSEY  DISCLAIM
// ALL LIABILITY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
// DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
// IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
// NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
// MODIFICATIONS.

// The authors hereby grant permission to use, copy, modify, distribute,
// and license this software and its documentation for any purpose, provided
// that existing copyright notices are retained in all copies and that this
// notice is included verbatim in any distributions. No written agreement,
// license, or royalty fee is required for any of the authorized uses.
// Modifications to this software may be copyrighted by their authors
// and need not follow the licensing terms described here, provided that
// the new terms are clearly indicated on the first page of each file where
// they apply.

// Last File Update: 31-Jul-1996
// 

// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author: Jonathan Berry

//This software is copyrighted by the DIMACS Center at Rutgers, The State
//University of New Jersey.  IT IS PROVIDED AS IS, AND THE AUTHORS, DIMACS, AND
//RUTGERS, THE STATE UNIVERSITY OF NEW JERSEY  DISCLAIM
//ALL LIABILITY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
//DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
//DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
//POSSIBILITY OF SUCH DAMAGE.

//The authors hereby grant permission to use, copy, modify, and distribute
//this software for any purpose.  However, fees for distribution or use of this
//software or derived works may not be charged without the written
//permission of the copyright holder.
// Last File Update: 31-Jul-1996
// 

#include <stdlib.h>
#include <iostream.h>
#include <fstream.h>
#include <strstream.h>
#include <ctype.h>

#define MAX_INCLUDES	10
#define FOR_CXX	0
#define FOR_STK	1

static char *CompoundName=0;
static char *CompoundName2=0;	// e.g. SetBase<T, DEFAULT_SET_IMPL<T> >
                             	// e.g. SequenceBase<T, DEFAULT_SEQ_IMPL<T> >
static char *CompoundName3=0;	// e.g. SetBase<T, DEFAULT_SEQ_IMPL<T> >
static char *CompoundName4=0;	// e.g. MSetBase<T, DEFAULT_SEQ_IMPL<T> >
static char *StrippedName=0;
static char *StrippedSTkName=0;
static char *STkObjName=0;
static char *StrippedObjName=0;
static char *HolderClassname=0;

static ostream *out;

void genHeaderComment(int argc, char *argv[])
{
	char *s;
	ostrstream oss;
	int i;

	oss << argv[0] << " ";
	for (i=1; i<argc; i++)
		oss << "\"" << argv[i] << "\" ";
	oss << ends;
	char *buffer = oss.str();
	*out << "//" << buffer << endl;
	delete buffer;
}

char *newString(char *src)
{
	char *dest = new char[strlen(src)+1];
	strcpy(dest, src);
	return dest;
}

void genSTkHeader()
{
	//*out << "#ifdef STK_INTERFACE" << endl;
	*out << "#include <stk.h>" << endl;
	*out << "#include <LINK/stkWrapper/LINK_STk.h>" << endl;
	//*out << "#endif" << endl;
	*out << endl;
}

void genObjectIncludes(char *full_include_file_path)
{
	*out << "#include <" << full_include_file_path <<  ">" << endl;
	*out << "" << endl;
}

void genTemplateIncludes(char *temp_includes[], int temp_incl_count, 
			 int gen_wrapper_class, int gen_stk_templates)
{
	*out << "#ifdef __GNUC__" << endl;		
	*out << "#define DEFINE_TEMPLATE" << endl;
	*out << "#endif" << endl;		
	*out << endl;			
	if (!gen_stk_templates) {
		*out << "#include <LINK/basic/ElementOps.h>" << endl;
		*out << endl;
		int i;
		for (i=0; i<temp_incl_count; i++)
			genObjectIncludes(temp_includes[i]);
	} else {
		//*out << "#ifdef STK_INTERFACE" << endl;
		*out << "#include <LINK/stkWrapper/Wrapper.h>" << endl;
		*out << "#include <LINK/stkWrapper/Register.h>" << endl;
		if (HolderClassname && gen_wrapper_class)
			*out << "#include <LINK/stkWrapper/" << 
				HolderClassname << "Wrapper.h>" << endl;
		//*out << "#endif" << endl;
		*out << "" << endl;
	}
	*out << "#ifdef __GNUC__" << endl;
	*out << "#undef DEFINE_TEMPLATE" << endl;
	*out << "#endif" << endl;
	*out << "" << endl;
}

void genNontemplateIncludes(char *nontemp_includes[], int nontemp_incl_count)
{
	int i;
	for (i=0; i<nontemp_incl_count; i++)
		genObjectIncludes(nontemp_includes[i]);
	*out << "" << endl;
}

void genElementOpsTemplates(int is_ptr)
{

	*out << endl;
	*out << endl;
	*out << "//*******************************************************"
		"**************" << endl;


	*out << "#ifdef __GNUC__" << endl;
	*out << "template class ElementOps<"
				<< StrippedName << ">;" << endl;
	*out << "#endif" << endl;

	if (is_ptr) {

	*out << "int ElementOps<"
			<< StrippedName<<">::compareItems(const "
			<< StrippedName << "& e1, const "
			<< StrippedName << "& e2) " << endl;
	*out << "{" << endl;
	*out << "\tif (e1 && e2)  {" << endl;
	*out << "\t\tif (*e1 == *e2)" << endl;
	*out << "\t\t\treturn 0;" << endl;
	*out << "\t\telse" << endl;
	*out << "\t\t\treturn (*e1<*e2)? -1 : 1;" << endl;
	*out << "\t} else {" << endl;
	*out << "\t\tif (e1 == e2)" << endl;
	*out << "\t\t\treturn 0;" << endl;
	*out << "\t\telse" << endl;
	*out << "\t\t\treturn (e1<e2)? -1 : 1;" << endl;
	*out << "\t}" << endl;
	*out << "}" << endl;
	*out << endl;
	*out << "ostream& ElementOps<"
			<< StrippedName << ">::displayItem(ostream& os, "
			"const " << StrippedName << "& e)" << endl;
	*out << "{" << endl;
	*out << "\tif (e)" << endl;
	*out << "\t\tos << *e;" << endl;
	*out << "\telse" << endl;
	*out << "\t\tos << e;" << endl;
	*out << "\treturn os;" << endl;
	*out << "}" << endl;
	}
	*out << "//*******************************************************"
		"**************" << endl;
	*out << "" << endl;
}

void genAttributeTemplates()
{

	*out << endl;
	*out << endl;

//
// This instantiation of AttributeElementOps must be manual for now.
// The specialization of a method must occur in the same compilation 
// unit in which the instantiation occurs.  This was doable automatically
// with ElementOps since the specialization could be easily automated.  Not so
// with AttributeElementOps.  Specializations of the latter's methods are
// found in src/graph/graphTemplate.cc, so that is where the instantiation
// must be for now.
//
/*
	*out << "//*******************************************************"
		"**************" << endl;
	*out << "//**Note: the displayItem() member of the following    **"
		"**************" << endl;
	*out << "//**      class may be specialized in graphTemplate.cc **"
		"**************" << endl;
	*out << "//*******************************************************"
		"**************" << endl;


	*out << "#ifdef __GNUC__" << endl;
	*out << "template class AttributeElementOps<"
				<< StrippedObjName << ">;" << endl;
	*out << "#endif" << endl;
	*out << endl;
*/
}

void genAttributeFuncs()
{
	*out << "#ifdef __GNUC__" << endl;
	*out << "template int newAttribute(Graph*, String, " << 
				StrippedObjName << "&);" << endl;
	*out << "template int getAttribute(GraphObject*, String, " << 
				StrippedObjName << "&);" << endl;
	*out << "template int setAttribute(GraphObject*, String, " << 
				StrippedObjName << "&);" << endl;

        //****REPLACE above with below in once static_flag logic is working

        //*out << "template int newAttribute(Graph*, String, " <<
        //                      StrippedObjName << "&, int);" << endl;
        //*out << "template int getAttribute(GraphObject*, String, " <<
        //                      StrippedObjName << "&);" << endl;
        //*out << "template int setAttribute(GraphObject*, String, " <<
        //                      StrippedObjName << "&, int);" << endl;

	*out << "#endif" << endl;
}

void genOverloadAttributeDestructor()
{
	*out << endl;
	*out << "Attribute<" <<  StrippedObjName << " >::~Attribute()" << endl;
	*out <<	"{" << endl;
        *out << "	cout << \"special ~Attr\" << endl;" << endl;
        *out << "	cout << _name << endl;" << endl;
	*out << "	if (_graph) {" << endl;
	*out << "		if (strncmp(_name, \"x_\", 2) != 0)"<<endl;
        *out << "			resetAttribute(_graph, _name);" << endl;
        *out << "	_graph->removeAttr(this);" << endl;
    	*out << "	}" << endl;
    	*out << "	delete _name;" << endl;
    	*out << "	if (_static_flag == LINK_DYNAMIC) {" << endl;
        *out << "		cout << \"deleted\" << endl;" << endl;
        *out << "		delete _value;" << endl;
	*out <<	"	}" << endl;
	*out <<	"}" << endl;
}

char *rmSpaces(char *s)
{
	char *result = new char[strlen(s)+1], *d = result;

	while (*s) {
		if (!(*s == ' '))
			*d++ = *s++;
		else 
			s++;
	}
	*d = '\0';
	return result;
}

int calcTemplateNesting(char *s)
{
	int result = 0; 
	while (*s) 
		if ((*s++) == '<')
			result++;
	return result;
}

char *validCname(char *s, int flag, int& obj_is_ptr)
{
	char *result, *d; 
	char c = (flag==FOR_CXX) ? '_' : '-';
	char c2 = 'p';

	obj_is_ptr = (s && (s[strlen(s)-1] == '*'));

	if (flag==FOR_CXX) {
 		result = new char[strlen(s)+2];
		d = result;
		*d++ = c;
	} else {
 		result = new char[strlen(s)+1];
		d = result;
	}
	while (*s) {
		if (isalnum(*s))
			*d++ = *s;
		else if ((flag==FOR_CXX) && (*s == '*'))
			*d++ = c2;
		else if ((*s!=' ') && !((*s == '*') && (flag==FOR_STK)))
			*d++ = c;
		s++;
	}
	*d = '\0';

	if (flag == FOR_STK) {
		int j = strlen(result);	   // this to avoid List-List-int---
		while ( (--j>=0) && (result[j] == c))
			result[j] = '\0';
	}
	return result;
}

int genTypedefs(int holder_ptr, char *objName, int dont_gen_element_ops,
		int gen_attribute_funcs, int& template_nesting_depth,
		int gen_stk_templates, int& obj_is_ptr)
{
	if (HolderClassname) {
		ostrstream oss2;
		oss2 << HolderClassname << "<" << objName << " >";
		if (holder_ptr)
			oss2 << "*";
		oss2 << ends;
		CompoundName = oss2.str();
		if ((strcmp(HolderClassname, "Set") == 0) ||
		    (strcmp(HolderClassname, "MSet") == 0)) {
			ostrstream oss;
			oss << HolderClassname << "Base<" << objName << 
				", DEFAULT_SET_IMPL<" << objName << " > >";
			if (holder_ptr)
				oss << "*";
			oss << ends;
			CompoundName2 = oss.str();
		} else if (strcmp(HolderClassname, "Sequence") == 0) {
			{
			ostrstream oss;
			oss << HolderClassname << "Base<" << objName << 
				", DEFAULT_SEQ_IMPL<" << objName << " > >";
			if (holder_ptr)
				oss << "*";
			oss << ends;
			CompoundName2 = oss.str();
			}
			{
			ostrstream oss;
			oss << "SetBase<" << objName << 
				", DEFAULT_SEQ_IMPL<" << objName << " > >";
			if (holder_ptr)
				oss << "*";
			oss << ends;
			CompoundName3 = oss.str();
			}
			{
			ostrstream oss;
			oss << "MSetBase<" << objName << 
				", DEFAULT_SEQ_IMPL<" << objName << " > >";
			if (holder_ptr)
				oss << "*";
			oss << ends;
			CompoundName4 = oss.str();
			}
		} else if (strcmp(HolderClassname, "Array") == 0) {
			ostrstream oss;
			oss << "Vector<" << objName << " >";
			if (holder_ptr)
				oss << "*";
			oss << ends;
			CompoundName2 = oss.str();
		}
	} else
		CompoundName = objName;

	template_nesting_depth = calcTemplateNesting(CompoundName);
	int holder_is_ptr;
	StrippedName = validCname(CompoundName, FOR_CXX, holder_is_ptr);
	if (HolderClassname && (strcmp(HolderClassname, "Array")==0))
		StrippedSTkName = validCname(CompoundName2, FOR_STK,obj_is_ptr);
	else
		StrippedSTkName = validCname(CompoundName, FOR_STK,obj_is_ptr);
	STkObjName = validCname(objName, FOR_STK,obj_is_ptr);
	StrippedObjName = validCname(objName, FOR_CXX,obj_is_ptr);

	*out << "typedef " <<objName << " " << StrippedObjName <<  ";" << endl;
	if (HolderClassname)
		*out << "typedef " << CompoundName << " "
					<< StrippedName<< ";" << endl;

	//int is_ptr = (CompoundName[strlen(CompoundName)-1] == '*');
	if (!gen_stk_templates) {
		if (!dont_gen_element_ops)
			genElementOpsTemplates(holder_is_ptr);
		if (gen_attribute_funcs)
			genAttributeTemplates();
	}
	return holder_is_ptr;
}

void genWrapperTemplate(char *hname, int is_ptr, int gen_node_type,
			int gen_wrapper_class, int gen_attribute_funcs)
{
	
	*out << "#ifdef __GNUC__" << endl;
	*out << "template class Wrapper<" 
				<< StrippedName << ">;" << endl;
	*out << "template class Register<"
				<< StrippedName << ">;" << endl;
	*out << "#endif" << endl;
	*out << "" << endl;
	
	if (is_ptr)
		return;

	if (gen_wrapper_class) {
		*out << "#ifdef __GNUC__" << endl;
		*out << "template class " << HolderClassname << "Wrapper" 
				<< "<" << StrippedObjName << ">;" << endl;
		*out << "#endif" << endl;
	}
}

void genTemplate(char *hname, int is_ptr, int gen_node_type,
			int gen_wrapper_class, int gen_attribute_funcs,
			int obj_is_ptr)
{
	if (is_ptr) return;

	*out << "#ifdef __GNUC__" << endl;  // matching endif in genAttributeF.
	if (HolderClassname)
		*out << "template class " << CompoundName << ";" << endl;
	if (CompoundName2 && (strcmp(HolderClassname,"Array")!=0))
		*out << "template class " << CompoundName2 << ";" << endl;
	if (CompoundName3 && (strcmp(HolderClassname,"Array")!=0))
		*out << "template class " << CompoundName3 << ";" << endl;
	if (CompoundName4 && (strcmp(HolderClassname,"Array")!=0))
		*out << "template class " << CompoundName4 << ";" << endl;
	if (gen_node_type)
		*out << "template class " << HolderClassname << "Node" 
				<< "<" << StrippedObjName << ">;" << endl;
	*out << endl;

	if (hname && strcmp(hname,"List")==0) {
		*out << "template class SimpleContainer<"
					<< StrippedObjName << ">;" << endl;
		*out << "template class ListContainerNode<"
					<< StrippedObjName << ">;" << endl;
		*out << "template class Iterator<"
					<< StrippedObjName << ">;" << endl;
		*out << endl;

	} 
	if (gen_attribute_funcs) 
		genAttributeFuncs();
	*out << "#endif" << endl; 
	if (gen_attribute_funcs && obj_is_ptr) 
		;//genOverloadAttributeDestructor();
}

void genStaticInits(char *compound_name)
{
	//*out << "#ifdef STK_INTERFACE" << endl;
	*out << "Tcl_HashTable Register<"
			<< StrippedName << ">::objTable;" << endl;
	char *stk_name = rmSpaces(compound_name);
	*out << "char *Wrapper<"
			<< StrippedName << ">::name = \""
					<< "<" << stk_name << ">" 
						<< "\";" << endl; 
	delete stk_name;
	*out << "int   Wrapper<"
			<< StrippedName << ">::type = 0;" << endl;
	//*out << "#endif" << endl;
	*out << "" << endl;
}

void genOutputOperator(char *full_name)
{
	*out << "#ifdef __GNUC__" << endl;
	*out << "template ostream& operator<<(ostream&, const ";
	*out << full_name << "&);" << endl;
	*out << "#endif" << endl;
}

ostream *openFile(int gen_stk_templates, char *file_root, char *dir_name=0)
{
	char *link_path;
	char *file_path;
	ostream *out;

	if (dir_name) {
		if ((link_path=getenv("NEWLINKBASE")) == 0) {
			cerr << "error: NEWLINKBASE environment variable "
				"must be set" << endl;
			exit(2);
		}
		ostrstream oss;

		if (gen_stk_templates)
		   oss << link_path<<"/src/"<<dir_name<<"/STkTemplates/";
		else 
		   oss << link_path<<"/src/"<<dir_name << "/linkTemplates/";
		oss << file_root << "Template.cc" << ends;
	
		file_path = oss.str();
		out = new ofstream(file_path, ios::out);
		delete file_path;
	} else
		out = new ofstream(file_root, ios::out);

	if (!(*out)) {
		cerr << "error: cannot open "<< file_path <<" for output"<<endl;
		exit(1);
	}
	return out;
}

void genWrapperFile(int holder_ptr, int gen_node_type, char *obj_name, 
		    char *temp_includes[], char *nontemp_includes[],
		    int temp_incl_count, int nontemp_incl_count,
		    int gen_output_op, int gen_wrapper_class,
		    int dont_gen_element_ops, int gen_attribute_funcs,
		    int &template_nesting_depth, int gen_stk_templates)
{

	if (!holder_ptr) {
		genTemplateIncludes(temp_includes, temp_incl_count,
				gen_wrapper_class, gen_stk_templates);
		genNontemplateIncludes(nontemp_includes, nontemp_incl_count);
	} else {
		genTemplateIncludes(temp_includes, temp_incl_count,
				gen_wrapper_class, gen_stk_templates);
		genNontemplateIncludes(nontemp_includes, nontemp_incl_count);
	}
	int obj_is_ptr;
	int is_ptr = genTypedefs(holder_ptr, obj_name, dont_gen_element_ops,
				 gen_attribute_funcs, template_nesting_depth,
				 gen_stk_templates, obj_is_ptr);
	if (!gen_stk_templates) {
		genTemplate(HolderClassname, is_ptr, gen_node_type, 
				 gen_wrapper_class, gen_attribute_funcs,
				 obj_is_ptr);
		if (gen_output_op)
			genOutputOperator(CompoundName);
	} else {
		genWrapperTemplate(HolderClassname, is_ptr, gen_node_type, 
				 gen_wrapper_class, gen_attribute_funcs);
		genStaticInits(CompoundName);
	}
}


typedef char *charptr;
typedef ostream *ostreamptr;
typedef char *charptrarray[MAX_INCLUDES];

void processArgs(int argc, 
		 char *argv[], 
		 charptr& HolderClassname,
		 int &gen_wrapper_class,
		 int &holder_ptr,
		 int &gen_node_type,
		 charptr& obj_name,
		 charptr& dir_name,
		 charptr& file_name,
		 int &gen_output_op,
		 int &temp_incl_count,
		 int &nontemp_incl_count,
		 charptrarray& template_includes,
		 charptrarray& nontemp_includes,
		 int &dont_gen_element_ops,
		 int &gen_attribute_funcs,
		 int &gen_stk_templates)
{
	char *s;
	while(--argc > 0 && (*++argv)[0] == '-') {
	   for(s=argv[0]+1; *s != '\0'; s++)
		switch(*s) {
			case 'h' :  
				--argc;
				HolderClassname = newString((++argv)[0]);
				break;
			case 'a' :  
				gen_attribute_funcs = 1;
				break;
			case 'r' :  
				gen_wrapper_class = 1;
				break;
			case 's' :  
				gen_stk_templates = 1;
				break;
			case 'p' :  
				holder_ptr = 1;
				break;
			case 'n' :  
				gen_node_type = 1;
				break;
			case 'd' :  
				--argc;
				dir_name = newString((++argv)[0]);
				break;
			case 't' :  
				--argc;
				obj_name = newString((++argv)[0]);
				break;
                        case 'o' :
                                --argc;
                                file_name = newString((++argv)[0]);
                                out = new ofstream(file_name, ios::out);
                                break;
			case 'e' :  
				--argc;
				dont_gen_element_ops = 1;
				break;
			case 'u' :  
				--argc;
				gen_output_op = 1;
				break;
			case 'I' :  
				--argc;
                                if (*(s+1) == 'I') {
					template_includes[temp_incl_count++] =
						newString((++argv)[0]);
					s++;
				} else
					nontemp_includes[nontemp_incl_count++] =
						newString((++argv)[0]);
				break;
			default:
				*out << "Illegal option: -" << *s << endl;
				exit(1);
		}
	}
}

void usageMsg(int argc, char *obj_name, char *dir_name, char *file_name)
{
	if ((argc <3) || !obj_name) {
	    cerr << "usage: instantiate [-npru] -t <element type name> " 
								<< endl;
	    cerr << "	    [-d <LINK directory> | -o <output file>]" << endl;
	    cerr << "	    [-r]" << endl;
	    cerr << "	    [-a]" << endl;
	    cerr << "	    [-h <holder class name (e.g. List)>]  " << endl;
	    cerr << "	    [-p ]  " << endl;
	    cerr << "	    [-n ]  " << endl;
	    cerr << "	    [-I <full include path of .h>]" << endl;
	    cerr << "	    [-II <full include path of .h for template"
			    " which needs instantiation >]" << endl;
	    cerr << "	    [-u ]" << endl;
	    cerr << "ex: instantiate -p -t \"Vertex*\" -h List "
		   "-I \"LINK/graph/Vertex.h\" -II \"LINK/basic/List.h\""<<endl;
	    exit(1);
	}
	if (dir_name && file_name) {
	    cerr << "error: -d and -o options may not be used together"<<endl;
	    exit(3);
	}
}

main(int argc, char *argv[])
{
	char *s;
	int holder_ptr=0, gen_node_type=0, gen_output_op=0, gen_wrapper_class=0;
	int template_nesting_depth=0;
	int gen_attribute_funcs=0;
	int gen_stk_templates=0;
	int dont_gen_element_ops=0;
	char *dir_name=0, *obj_name=0, *file_name=0;
	char *template_includes[MAX_INCLUDES];
	char *nontemp_includes[MAX_INCLUDES];
	int temp_incl_count=0;
	int nontemp_incl_count=0;
	char **save_argv = argv;
	int save_argc = argc;
	
	dir_name=0;
	ostrstream the_whole_file;

	out = &the_whole_file;

	processArgs(argc, argv, HolderClassname, gen_wrapper_class, holder_ptr,
		    gen_node_type, obj_name, dir_name,file_name, gen_output_op, 
		    temp_incl_count, nontemp_incl_count, template_includes, 
		    nontemp_includes, dont_gen_element_ops,gen_attribute_funcs,
		    gen_stk_templates);
	usageMsg(argc, obj_name, dir_name, file_name);
	genHeaderComment(save_argc, save_argv);
	if (gen_stk_templates)
		genSTkHeader();
	genWrapperFile( holder_ptr, gen_node_type, obj_name,  
			template_includes, nontemp_includes, temp_incl_count,
			nontemp_incl_count,
			gen_output_op, gen_wrapper_class, dont_gen_element_ops,
			gen_attribute_funcs, template_nesting_depth,
			gen_stk_templates);
	the_whole_file << ends;
	char *file_string = the_whole_file.str();
	if (dir_name) {
		ostrstream oss;
		if (template_nesting_depth > 0) oss << "_";
		int i;
		for (i=0; i<template_nesting_depth; i++) 
			oss << "z";
		oss << StrippedName << ends;
		char *fname = oss.str();
		out = openFile(gen_stk_templates, fname, dir_name);
		delete fname;
	} else if (file_name)
		out = openFile(gen_stk_templates, file_name);
	else
		out = &cout;

	*out << file_string << endl;

	if (dir_name || file_name) {
		//(*(ofstream*)out).close();
		//delete out;
	}
	if (CompoundName)    delete CompoundName;
	if (CompoundName2)   delete CompoundName2;	
	if (StrippedName)    delete StrippedName;
	if (StrippedSTkName) delete StrippedSTkName;
	if (STkObjName)      delete STkObjName;
	if (HolderClassname) delete HolderClassname;
}
