/***************************************************************************
                          javawriter.cpp  -  description
                             -------------------
    copyright            : (C) 2003 Brian Thomas brian.thomas@gsfc.nasa.gov
***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "javawriter.h"

#include <kdebug.h>

#include <klocale.h>
#include <kmessagebox.h>
#include <qfile.h>
#include <qtextstream.h>
#include <qregexp.h>

#include "../umldoc.h"
#include "../class.h"
#include "../interface.h"
#include "../operation.h"
#include "../umlnamespace.h"

JavaWriter::JavaWriter( QObject *parent, const char *name ) : CodeGenerator(parent, name) {
	indent = "\t";
	startline = "\n"+indent; // using UNIX newLine standard.. bad
}

JavaWriter::~JavaWriter() {}

void JavaWriter::writeClass(UMLClassifier *c)
{

	if (!c) {
		kdDebug()<<"Cannot write class of NULL concept!\n";
		return;
	}

	if(dynamic_cast<UMLInterface*>(c))
		isInterface = true;
	else
		isInterface = false;

	QString fileName = cleanName(c->getName().lower());

	//find an appropriate name for our file
	fileName = findFileName(c,".java");
	if (!fileName) {
		emit codeGenerated(c, false);
		return;
	}

	// check that we may open that file for writing
	QFile file;
	if ( !openFile(file,fileName+".java") ) {
		emit codeGenerated(c, false);
		return;
	}

	// Preparations
	//

	// sort attributes by Scope
        UMLAttribute *at;
        UMLAttributeList *atl;
        UMLAttributeList  atpub, atprot, atpriv;
        UMLAttributeList  final_atpub, final_atprot, final_atpriv;
        atpub.setAutoDelete(false);
        final_atpub.setAutoDelete(false);
        atprot.setAutoDelete(false);
        final_atprot.setAutoDelete(false);
        atpriv.setAutoDelete(false);
        final_atpriv.setAutoDelete(false);

	UMLClass * myClass = dynamic_cast<UMLClass *>(c);

	if(myClass) {
	        atl = myClass->getFilteredAttributeList();
	        for(at=atl->first(); at ; at=atl->next()) {
	                switch(at->getScope())
	                {
			case Uml::Public:
				if(at->getStatic())
					final_atpub.append(at);
				else
					atpub.append(at);
				break;
			case Uml::Protected:
				if(at->getStatic())
					final_atprot.append(at);
				else
					atprot.append(at);
				break;
			case Uml::Private:
				if(at->getStatic())
					final_atprot.append(at);
				else
					atpriv.append(at);
				break;
	                }
	        }
	}

	// another preparation, determine what we have
	UMLAssociationList associations = c->getSpecificAssocs(Uml::at_Association); // BAD! only way to get "general" associations.
	UMLAssociationList aggregations = c->getAggregations();
	UMLAssociationList compositions = c->getCompositions();

	bool hasAssociations = aggregations.count() > 0 || associations.count() > 0 || compositions.count() > 0;
	bool hasAttributes = atpub.count() > 0 || atprot.count() > 0 || atpriv.count() > 0
			     || final_atpub.count() > 0
			     || final_atprot.count() > 0
			     || final_atpriv.count() > 0;
	bool hasAccessorMethods = hasAttributes || hasAssociations;
	bool hasOperationMethods = c->getFilteredOperationsList()->last() ? true : false;
	// this is a bit too simplistic..some associations are for
	// SINGLE objects, and WONT be declared as Vectors, so this
	// is a bit overly inclusive
	bool hasVectorFields = hasAssociations ? true : false;

	// open text stream to file
	QTextStream java(&file);

	//try to find a heading file (license, coments, etc)
	QString str;
	str = getHeadingFile(".java");
	if(!str.isEmpty()) {
		str.replace(QRegExp("%filename%"),fileName);
		str.replace(QRegExp("%filepath%"),file.name());
		java<<str<<endl;
	}

	if(!c->getPackage().isEmpty())
		java<<"package "<<c->getPackage()<<";"<<endl;

	// IMPORT statements
	// Q: Why all utils? Isnt just List and Vector the only classes we are using?
    // A: doesn't matter at all; its more readable to just include '*' and java compilers
    //    don't slow down or anything. (TZ)
	if (hasVectorFields )
	{
		writeBlankLine(java);
		java<<"import java.util.*;"<<endl;
	}

	//only import classes in a different package as this class
	UMLClassifierList imports;
	findObjectsRelated(c,imports);
	for(UMLClassifier *con = imports.first(); con ; con = imports.next())
		if(con->getPackage() != c->getPackage())
			java<<"import "<<con->getPackage()<<"."<<cleanName(con->getName())<<";"<<endl;
	writeBlankLine(java);

	// write the opening declaration for the class incl any documentation,
	// interfaces and/or inheritence issues we have
	writeClassDecl(c, java);

	// start body of class
	java<<" {"<<endl;

	// ATTRIBUTES
	//

	// write comment for section IF needed
	if (forceDoc() || hasAccessorMethods)
	{
		writeComment("", indent, java);
		writeComment("Fields", indent, java);
		writeComment("", indent, java);
		writeBlankLine(java);
	}

	writeAttributeDecls(final_atpub, final_atprot, final_atpriv, java);
	writeAttributeDecls(atpub, atprot, atpriv, java);

	writeAssociationDecls(associations, c->getID(), java);
	writeAssociationDecls(aggregations, c->getID(), java);
	writeAssociationDecls(compositions, c->getID(), java);

	// Constructors: anything we more we need to do here ?
	//
	if(!isInterface)
		writeConstructor(c, java);

	// METHODS
	//

	// write comment for section IF needed
	if (forceDoc() || hasAccessorMethods || hasOperationMethods)
	{

		java<<startline;
		writeComment("", indent, java);
		writeComment("Methods", indent, java);
		writeComment("", indent, java);
		writeBlankLine(java);
		writeBlankLine(java);
	}

	// write comment for sub-section IF needed
	if (forceDoc() || hasAccessorMethods )
	{
		writeComment("", indent, java);
		writeComment("Accessor methods", indent, java);
		writeComment("", indent, java);
		writeBlankLine(java);
	}

	// Accessors for attributes
	writeAttributeMethods(final_atpub, Public, java);
	writeAttributeMethods(final_atprot, Protected, java);
	writeAttributeMethods(final_atpriv, Private, java);
	writeAttributeMethods(atpub, Public, java);
	writeAttributeMethods(atprot, Protected, java);
	writeAttributeMethods(atpriv, Private, java);

	// accessor methods for associations

	// first: determine the name of the other class
	writeAssociationMethods(associations, c, java);
	writeAssociationMethods(aggregations, c, java);
	writeAssociationMethods(compositions, c, java);

	// Other operation methods
	// all other operations are now written

	// write comment for sub-section IF needed
	if (forceDoc() || hasOperationMethods)
	{
		writeComment("", indent, java);
		writeComment("Other methods", indent, java);
		writeComment("", indent, java);
		writeBlankLine(java);
	}
	writeOperations(c,java);

	writeBlankLine(java);
	java<<"}"<<endl; // end class

	file.close();
	emit codeGenerated(c, true);
}

void JavaWriter::writeClassDecl(UMLClassifier *c, QTextStream &java)
{

	QString classname = cleanName(c->getName()); // our class name

	// write documentation for class, if any, first
        if(forceDoc() || !c->getDoc().isEmpty())
	{
		if(isInterface)
			writeDocumentation("Interface "+classname,c->getDoc(),"","",java);
		else
			writeDocumentation("Class "+classname,c->getDoc(),"","",java);

		writeBlankLine(java);
	}

	// Now write the actual class declaration
	QString scope = ""; // = scopeToJavaDecl(c->getScope());
	if (c->getScope() != Uml::Public) {
		// We should emit a warning in here .. java doesnt like to allow
		// private/protected classes. The best we can do (I believe)
		// is to let these declarations default to "package visibility"
		// which is a level between traditional "private" and "protected"
		// scopes. To get this visibility level we just print nothing..
	} else
		scope = "public ";

	java<<(c->getAbstract()?QString("abstract "):QString(""))<<scope;
	if(isInterface)
		java<<"interface ";
	else
		java<<"class ";

	java<<classname;


	// write inheritances out
	UMLClassifier *concept;
	UMLClassifierList superclasses = c->findSuperClassConcepts();

	if(superclasses.count()>0)
		java<<" extends ";

    // Q: Where is 'implements' ??

	int i = 0;
	for (concept= superclasses.first(); concept; concept = superclasses.next())
	{
		java<<cleanName(concept->getName())<<(i>0?", ":"");
		i++;
	}

}

void JavaWriter::writeAttributeDecls(UMLAttributeList &atpub, UMLAttributeList &atprot,
				     UMLAttributeList &atpriv, QTextStream &java )
{
	UMLAttribute *at;

	for(at=atpub.first(); at; at=atpub.next())
	{
		QString documentation = at->getDoc();
		QString staticValue = at->getStatic() ? "static " : "";
		QString typeName = fixTypeName(at->getTypeName());
		QString initialValue = fixInitialStringDeclValue(at->getInitialValue(), typeName);
		if(!documentation.isEmpty())
			writeComment(documentation, indent, java, true);
		java<<startline<<staticValue<<"public "<<typeName<<" "<<cleanName(at->getName())
		    <<(initialValue.isEmpty()?QString(""):QString(" = ") + initialValue)<<";";
	}

	for(at=atprot.first();at;at=atprot.next())
	{
		QString documentation = at->getDoc();
		QString typeName = fixTypeName(at->getTypeName());
		QString staticValue = at->getStatic() ? "static " : "";
		QString initialValue = fixInitialStringDeclValue(at->getInitialValue(), typeName);
		if(!documentation.isEmpty())
			writeComment(documentation, indent, java, true);
		java<<startline<<staticValue<<"protected "<<typeName<<" "<<cleanName(at->getName())
		    <<(initialValue.isEmpty()?QString(""):QString(" = ") + initialValue)<<";";
	}

	for(at=atpriv.first();at;at=atpriv.next())
	{
		QString documentation = at->getDoc();
		QString typeName = fixTypeName(at->getTypeName());
		QString staticValue = at->getStatic() ? "static " : "";
		QString initialValue = fixInitialStringDeclValue(at->getInitialValue(), typeName);
		if(!documentation.isEmpty())
			writeComment(documentation, indent, java, true);
		java<<startline<<staticValue<<"private "<<typeName<<" "<<cleanName(at->getName())
		    <<(initialValue.isEmpty()?QString(""):QString(" = ") + initialValue)<<";";
	}

}

void JavaWriter::writeAttributeMethods(UMLAttributeList &atpub, Scope visibility, QTextStream &java)
{

	UMLAttribute *at;
	for(at=atpub.first(); at; at=atpub.next())
	{
		QString fieldName = cleanName(at->getName());
		// force capitalizing the field name, this is silly,
		// from what I can tell, this IS the default behavior for
		// cleanName. I dunno why its not working -b.t.
		fieldName.stripWhiteSpace();
		fieldName.replace(0,1,fieldName.at(0).upper());

		writeSingleAttributeAccessorMethods(at->getTypeName(),
						    cleanName(at->getName()),
						    fieldName,
						    at->getDoc(),
						    visibility, chg_Changeable, at->getStatic(), java);
	}

}

void JavaWriter::writeComment(QString comment, QString myIndent, QTextStream &java, bool javaDocStyle)
{
	// in the case we have several line comment..
	// NOTE: this part of the method has the problem of adopting UNIX newline,
	// need to resolve for using with MAC/WinDoze eventually I assume
	if (comment.contains(QRegExp("\n"))) {

		if(javaDocStyle)
			java << myIndent << "/**" << endl;
		QStringList lines = QStringList::split( "\n", comment);
		for(uint i= 0; i < lines.count(); i++)
		{
			writeBlankLine(java);
			if(javaDocStyle)
				java<<myIndent<<" * ";
			else
				java<<myIndent<<"// ";
			java << lines[i];
		}
		if(javaDocStyle)
			java << myIndent << " */" << endl;
	} else {
		// this should be more fancy in the future, breaking it up into 80 char
		// lines so that it doesnt look too bad
		writeBlankLine(java);
		if(javaDocStyle)
			java << myIndent << "/**" << endl << myIndent << " *";
		else
		    java<<myIndent<<"//";
		if(comment.length() > 0)
			java << " " << comment;
		if(javaDocStyle)
			java << endl << myIndent << " */";
	}
}

void JavaWriter::writeDocumentation(QString header, QString body, QString end, QString indent, QTextStream &java)
{
	writeBlankLine(java);
	java<<indent<<"/**"<<endl;
	if (!header.isEmpty())
		java<<formatDoc(header, indent+" * ");
	if (!body.isEmpty())
		java<<formatDoc(body, indent+" * ");
	if (!end.isEmpty())
	{
		QStringList lines = QStringList::split( "\n", end);
		for(uint i= 0; i < lines.count(); i++)
			java<<formatDoc(lines[i], indent+" * ");
	}
	java<<indent<<" */";
}

void JavaWriter::writeAssociationDecls(UMLAssociationList associations, int id, QTextStream &java)
{

	if( forceSections() || !associations.isEmpty() )
	{
		bool printRoleA = false, printRoleB = false;
		for(UMLAssociation *a = associations.first(); a; a = associations.next())
		{
			// it may seem counter intuitive, but you want to insert the role of the
			// *other* class into *this* class.
			if (a->getRoleAId() == id)
				printRoleB = true;

			if (a->getRoleBId() == id)
				printRoleA = true;

			// First: we insert documentaion for association IF it has either role AND some documentation (!)
			if ((printRoleA || printRoleB) && !(a->getDoc().isEmpty()))
				writeComment(a->getDoc(), indent, java);

			// print RoleB decl
			if (printRoleB)
			{
				QString fieldClassName = cleanName(getUMLObjectName(a->getObjectB()));
				writeAssociationRoleDecl(fieldClassName, a->getRoleNameB(), a->getMultiB(), a->getRoleBDoc(), a->getVisibilityB(), java);
			}

			// print RoleA decl
			if (printRoleA)
			{
				QString fieldClassName = cleanName(getUMLObjectName(a->getObjectA()));
				writeAssociationRoleDecl(fieldClassName, a->getRoleNameA(), a->getMultiA(), a->getRoleADoc(), a->getVisibilityA(), java);
			}
		}
	}
}

void JavaWriter::writeAssociationRoleDecl(QString fieldClassName,
					QString roleName, QString multi,
					QString doc, Scope visib, QTextStream &java)
{
	// ONLY write out IF there is a rolename given
	// otherwise its not meant to be declared in the code
	if (roleName.isEmpty())
		return;

	QString scope = scopeToJavaDecl(visib);

	// always put space between this and prior decl, if any
	writeBlankLine(java);

	if (!doc.isEmpty())
		writeComment(doc, indent, java);

	// declare the association based on whether it is this a single variable
	// or a List (Vector). One day this will be done correctly with special
	// multiplicity object that we dont have to figure out what it means via regex.
	if(multi.isEmpty() || multi.contains(QRegExp("^[01]$")))
	{
		QString fieldVarName = roleName.replace(0, 1, roleName.left(1).lower());
		java<<startline<<scope<<" "<<fieldClassName<<" "<<fieldVarName<<";";
	}
	else
	{
		QString fieldVarName = roleName.lower() + "Vector";
		java<<startline<<scope<<" Vector "<<fieldVarName<<" = new Vector();";
		// from here we could initialize default values, or put in an init() section
		// of the constructors
	}

}

void JavaWriter::writeAssociationMethods (UMLAssociationList associations, UMLClassifier *thisClass, QTextStream &java)
{
	if( forceSections() || !associations.isEmpty() )
	{
		for(UMLAssociation *a = associations.first(); a; a = associations.next())
		{

			// insert the methods to access the role of the other
			// class in the code of this one
			if (a->getRoleAId() == thisClass->getID())
			{
				// only write out IF there is a rolename given
				if(!a->getRoleNameB().isEmpty()) {
					QString fieldClassName = getUMLObjectName(a->getObjectB());
					writeAssociationRoleMethod(fieldClassName,
								   a->getRoleNameB(),
								   a->getMultiB(), a->getRoleBDoc(),
								   a->getVisibilityB(),
								   a->getChangeabilityB(), java);
				}
			}

			if (a->getRoleBId() == thisClass->getID())
			{
				// only write out IF there is a rolename given
				if(!a->getRoleNameA().isEmpty()) {
					QString fieldClassName = getUMLObjectName(a->getObjectA());
					writeAssociationRoleMethod(fieldClassName, a->getRoleNameA(),
								   a->getMultiA(),
								   a->getRoleADoc(),
								   a->getVisibilityA(),
								   a->getChangeabilityA(),
								   java);
				}
			}

		}
	}
}

void JavaWriter::writeAssociationRoleMethod (QString fieldClassName, QString roleName, QString multi,
					     QString description, Scope visib, Changeability_Type change,
					     QTextStream &java)
{
	if(multi.isEmpty() || multi.contains(QRegExp("^[01]$")))
	{
		QString fieldVarName = "m_" + roleName.lower();
		writeSingleAttributeAccessorMethods(fieldClassName, fieldVarName, roleName,
						    description, visib, change, false, java);
	}
	else
	{
		QString fieldVarName = roleName.lower() + "Vector";
		writeVectorAttributeAccessorMethods(fieldClassName, fieldVarName, roleName,
						    description, visib, change, java);
	}
}

void JavaWriter::writeVectorAttributeAccessorMethods (QString fieldClassName, QString fieldVarName,
						      QString fieldName, QString description,
						      Scope visibility, Changeability_Type changeType,
						      QTextStream &java)
{

	fieldClassName = fixTypeName(fieldClassName);
	fieldName = capitaliseFirstLetter(fieldName);
	QString strVis = scopeToJavaDecl(visibility);

	// ONLY IF changeability is NOT Frozen
	if (changeType != chg_Frozen)
	{
		writeDocumentation("Add a "+fieldName+" object to the "+fieldVarName+" List",description,"",indent,java);
		java<<startline<<strVis<<" void add"<<fieldName<<" ( "<<fieldClassName<<" new_object ) {";
		java<<startline<<indent<<fieldVarName<<".add(new_object);";
		java<<startline<<"}"<<endl;
	}

	// ONLY IF changeability is Changeable
	if (changeType == chg_Changeable)
	{
		writeDocumentation("Remove a "+fieldName+" object from "+fieldVarName+" List",description,"",indent,java);
		java<<startline<<strVis<<" void remove"<<fieldName<<" ( "<<fieldClassName<<" new_object )";
		java<<startline<<"{";
		java<<startline<<indent<<fieldVarName<<".remove(new_object);";
		java<<startline<<"}"<<endl;
	}

	// always allow getting the list of stuff
	writeDocumentation("Get the List of "+fieldName+" objects held by "+fieldVarName,description,"@return List of "+fieldName+" objects held by "+fieldVarName,indent,java);
	java<<startline<<strVis<<" List get"<<fieldName<<"List ( ) {";
	java<<startline<<indent<<"return (List) "<<fieldVarName<<";";
	java<<startline<<"}"<<endl;
	writeBlankLine(java);
}


void JavaWriter::writeSingleAttributeAccessorMethods(QString fieldClassName, QString fieldVarName,
						     QString fieldName, QString description,
						     Scope visibility, Changeability_Type change,
						     bool isFinal, QTextStream &java)
{

	QString strVis = scopeToJavaDecl(visibility);
	fieldClassName = fixTypeName(fieldClassName);
	fieldName = capitaliseFirstLetter(fieldName);

	// set method
	if (change == chg_Changeable && !isFinal) {
		writeDocumentation("Set the value of "+fieldVarName,description,"@param newVar the new value of "+fieldVarName,indent,java);
		java<<startline<<strVis<<" void set"<<fieldName<<" ( "<<fieldClassName<<" newVar ) {";
		java<<startline<<indent<<fieldVarName<<" = newVar;";
		java<<startline<<"}"<<endl;
	}

	// get method
	writeDocumentation("Get the value of "+fieldVarName,description,"@return the value of "+fieldVarName,indent,java);
	java<<startline<<strVis<<" "<<fieldClassName<<" get"<<fieldName<<" ( ) {";
	java<<startline<<indent<<"return "<<fieldVarName<<";";
	java<<startline<<"}";
	writeBlankLine(java);
}

void JavaWriter::writeConstructor(UMLClassifier *c, QTextStream &java)
{

	if (forceDoc())
	{
		java<<startline;
		writeComment("", indent, java);
		writeComment("Constructors", indent, java);
		writeComment("", indent, java);
		writeBlankLine(java);
	}

	// write the first constructor
	QString className = cleanName(c->getName());
	java<<indent<<"public "<<className<<" () { };";

}

// IF the type is "string" we need to declare it as
// the Java Object "String" (there is no string primative in Java).
// Same thing again for "bool" to "boolean"
QString JavaWriter::fixTypeName(QString string)
{
	string.replace(QRegExp("^string$"),"String");
	string.replace(QRegExp("^bool$"),"boolean");
	return string;
}

void JavaWriter::writeOperations(UMLClassifier *c, QTextStream &java) {
	UMLOperationList *opl;
	UMLOperationList oppub,opprot,oppriv;
	oppub.setAutoDelete(false);
	opprot.setAutoDelete(false);
	oppriv.setAutoDelete(false);

	UMLOperation *op;
	//sort operations by scope first and see if there are abstrat methods
	opl = c->getFilteredOperationsList();
	for(op = opl->first(); op ; op=opl->next()) {
		switch(op->getScope()) {
		case Uml::Public:
			oppub.append(op);
			break;
		case Uml::Protected:
			opprot.append(op);
			break;
		case Uml::Private:
			oppriv.append(op);
			break;
		}
	}

	// do people REALLY want these comments? Hmm.
	/*
	  if(forceSections() || oppub.count())
	  {
	  writeComment("public operations",indent,java);
		writeBlankLine(java);
	  }
	*/
	writeOperations(oppub,java);

	/*
	  if(forceSections() || opprot.count())
	  {
	  writeComment("protected operations",indent,java);
		writeBlankLine(java);
	  }
	*/
	writeOperations(opprot,java);

	/*
	  if(forceSections() || oppriv.count())
	  {
	  writeComment("private operations",indent,java);
		writeBlankLine(java);
	  }
	*/
	writeOperations(oppriv,java);

}

void JavaWriter::writeOperations(UMLOperationList &oplist, QTextStream &java) {
	UMLOperation *op;
	UMLAttributeList *atl;
	UMLAttribute *at;
	int i,j;
	QString str;

	// generate method decl for each operation given
	for( op=oplist.first(); op ;op=oplist.next())
	{

		QString returnStr = "";
		// write documentation

		QString methodReturnType = fixTypeName(op->getReturnType());
		if(methodReturnType != "void")
			returnStr += "@return	"+methodReturnType+"\n";

		str = ""; // reset for next method
		str += ((op->getAbstract() || isInterface) ? "abstract ":"");
		str += (op->getStatic() ? "static":"");
		str += scopeToJavaDecl(op->getScope()) + " ";
		str += methodReturnType + " " +cleanName(op->getName()) + "( ";

		atl = op->getParmList();
		i= atl->count();
		j=0;
		for( at = atl->first(); at ;at = atl->next(),j++) {
			QString typeName = fixTypeName(at->getTypeName());
			QString atName = cleanName(at->getName());
			str += typeName + " " + atName +
			       (!(at->getInitialValue().isEmpty()) ?
			        (QString(" = ")+at->getInitialValue()) :
			        QString(""))
			       + ((j < i-1)?", ":"");
			returnStr += "@param	"+atName+" "+at->getDoc()+"\n";
		}
		str+= " )";

		// method only gets a body IF its not abstract
		if (op->getAbstract() || isInterface)
			str+=";\n\n"; // terminate now
		else
			str+=startline+"{\n\n"+indent+"}\n\n"; // empty method body

		// write it out
		writeDocumentation("", op->getDoc(), returnStr, indent, java);
		java<<startline<<str;
	}
}

QString JavaWriter::fixInitialStringDeclValue(QString value, QString type)
{
	// check for strings only
	if (!value.isEmpty() && type == "String") {
		if (!value.startsWith("\""))
			value.prepend("\"");
		if (!value.endsWith("\""))
			value.append("\"");
	}
	return value;
}

QString JavaWriter::scopeToJavaDecl(Uml::Scope scope)
{
	QString scopeString;
	switch(scope)
	{
		case Uml::Public:
			scopeString = "public";
			break;
		case Uml::Protected:
			scopeString = "protected";
			break;
		case Uml::Private:
		default:
			scopeString = "private";
			break;
	}
	return scopeString;
}

// methods like this _shouldnt_ be needed IF we properly did things thruought the code.
QString JavaWriter::getUMLObjectName(UMLObject *obj)
{
	return(obj!=0)?obj->getName():QString("NULL");
}

QString JavaWriter::capitaliseFirstLetter(QString string)
{
	// we could lowercase everything tostart and then capitalize? Nah, it would
	// screw up formatting like getMyRadicalVariable() to getMyradicalvariable(). Bah.
	QChar firstChar = string.at(0);
	string.replace( 0, 1, firstChar.upper());
	return string;
}

void JavaWriter::writeBlankLine(QTextStream &java)
{
	java<<endl;
}

