
/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

/*  This code generated by:
 *      Author : thomas
 *      Date   : Sep Mon 1 2003
 */

// own header
#include "simplecodegenerator.h"
// system includes
#include <cstdlib> //to get the user name
// qt includes
#include <qdatetime.h>
#include <qregexp.h>
#include <qdir.h>
// kde includes
#include <klocale.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <kdialogbase.h>
#include <kapplication.h>
// app includes
#include "../dialogs/overwritedialogue.h"
#include "../attribute.h"
#include "../umloperationlist.h"
#include "../umlattributelist.h"
#include "../class.h"
#include "../classifier.h"
#include "../codedocument.h"
#include "../operation.h"
#include "../umldoc.h"

// Constructors/Destructors
//

SimpleCodeGenerator::SimpleCodeGenerator (UMLDoc * parentDoc , const char * name,
					  bool createDirHierarchyForPackages /* =true */)
    : CodeGenerator( parentDoc, name )
{
	m_indentLevel = 0;
	parentDoc->disconnect(this); // disconnect from UMLDoc.. we arent planning to be synced at all
	m_createDirHierarchyForPackages = createDirHierarchyForPackages;
	initFields(parentDoc);
}

SimpleCodeGenerator::~SimpleCodeGenerator ( ) { }

//
// Methods
//

// Accessor methods
//


// Other methods
//

QString SimpleCodeGenerator::getIndent ()
{
	QString myIndent;
	for (int i = 0 ; i < m_indentLevel ; i++)
		myIndent.append(m_indentation);
	return myIndent;
}

QString SimpleCodeGenerator::findFileName(UMLClassifier* concept, QString ext) {

        //if we already know to which file this class was written/should be written, just return it.
        if(m_fileMap->contains(concept))
                return ((*m_fileMap)[concept]);

        //else, determine the "natural" file name
        QString name;
        // Get the package name
        QString package = concept->getPackage(".");

        // Replace all white spaces with blanks
        package.simplifyWhiteSpace();

        // Replace all blanks with underscore
        package.replace(QRegExp(" "), "_");

	// Convert all "::" to "/" : Platform-specific path separator
	// package.replace(QRegExp("::"), "/");

        // if package is given add this as a directory to the file name
        if (!package.isEmpty() && m_createDirHierarchyForPackages) {
                name = package + "." + concept->getName();
        	name.replace(QRegExp("\\."),"/");
                package.replace(QRegExp("\\."), "/");
                package = "/" + package;
        } else {
                name = concept->getFullyQualifiedName("-");
        }

        if (ext != ".idl" && ext != ".java" && ext != ".pm" && ext != ".py") {
                package = package.lower();
                name = name.lower();
        }

        // if a package name exists check the existence of the package directory
        if (!package.isEmpty() && m_createDirHierarchyForPackages) {
                QDir pathDir(m_outputDirectory.absPath() + package);
		// does our complete output directory exist yet? if not, try to create it
		if (!pathDir.exists())
		{
			QStringList dirs = QStringList::split("/",pathDir.absPath());
			QString currentDir = "";

			QStringList::iterator end(dirs.end());
			for (QStringList::iterator dir(dirs.begin()); dir != end; ++dir)
			{
				currentDir += "/" + *dir;
				if (! (pathDir.exists(currentDir) 
					|| pathDir.mkdir(currentDir) ) ) 
				{
					KMessageBox::error(0, i18n("Cannot create the folder:\n") + 
					pathDir.absPath() + i18n("\nPlease check the access rights"),
					   i18n("Cannot Create Folder"));
					return NULL;
				}
			}
		}
	}


        name.simplifyWhiteSpace();
        name.replace(QRegExp(" "),"_");

        ext.simplifyWhiteSpace();
        ext.replace(QRegExp(" "),"_");

        return overwritableName(concept, name, ext);
}

QString SimpleCodeGenerator::overwritableName(UMLClassifier* concept, QString name, const QString &ext) {
        //check if a file named "name" with extension "ext" already exists
        if(!m_outputDirectory.exists(name+ext)) {
                m_fileMap->insert(concept,name);
                return name; //if not, "name" is OK and we have not much to to
        }

        int suffix;
        OverwriteDialogue overwriteDialogue( name+ext, m_outputDirectory.absPath(),
                                             m_applyToAllRemaining, kapp -> mainWidget() );
        switch(m_overwrite) {  //if it exists, check the OverwritePolicy we should use
                case CodeGenerationPolicy::Ok:                //ok to overwrite file
                        break;
                case CodeGenerationPolicy::Ask:               //ask if we can overwrite
                        switch(overwriteDialogue.exec()) {
                                case KDialogBase::Yes:  //overwrite file
                                        if ( overwriteDialogue.applyToAllRemaining() ) {
                                                m_overwrite = CodeGenerationPolicy::Ok;
                                        } else {
                                                m_applyToAllRemaining = false;
                                        }
                                        break;
                                case KDialogBase::No: //generate similar name
                                        suffix = 1;
                                        while( m_outputDirectory.exists(name + "__" + QString::number(suffix) + ext) ) {
                                                suffix++;
                                        }
                                        name = name + "__" + QString::number(suffix);
                                        if ( overwriteDialogue.applyToAllRemaining() ) {
                                                m_overwrite = CodeGenerationPolicy::Never;
                                        } else {
                                                m_applyToAllRemaining = false;
                                        }
                                        break;
                              case KDialogBase::Cancel: //don't output anything
                                        if ( overwriteDialogue.applyToAllRemaining() ) {
                                                m_overwrite = CodeGenerationPolicy::Cancel;
                                        } else {
                                                m_applyToAllRemaining = false;
                                        }
                                        return NULL;
                                        break;
                        }

                        break;
                case CodeGenerationPolicy::Never: //generate similar name
                        suffix = 1;
                        while( m_outputDirectory.exists(name + "__" + QString::number(suffix) + ext) ) {
                                suffix++;
                        }
			name = name + "__" + QString::number(suffix);
                        break;
                case CodeGenerationPolicy::Cancel: //don't output anything
                        return NULL;
                        break;
        }

        m_fileMap->insert(concept,name);
        return name;
}


bool SimpleCodeGenerator::hasDefaultValueAttr(UMLClass *c) {
        UMLAttributeList atl = c->getAttributeList();
        for(UMLAttribute *at = atl.first(); at; at = atl.next())
                if(!at->getInitialValue().isEmpty())
                        return true;
        return false;
}

bool SimpleCodeGenerator::hasAbstractOps(UMLClassifier *c) {
        UMLOperationList opl(c->getOpList());
        for(UMLOperation *op = opl.first(); op ; op = opl.next())
                if(op->getAbstract())
                        return true;
        return false;
}

/**
 * @return	ClassifierCodeDocument
 * @param	classifier
 * @param	this This package generator object.
 */
CodeDocument * SimpleCodeGenerator::newClassifierCodeDocument(UMLClassifier* /*classifier*/)
{
	return (CodeDocument*)NULL;
}

// write all concepts in project to file
void SimpleCodeGenerator::writeCodeToFile ( ) {
        m_fileMap->clear(); // yeah, need to do this, if not, just keep getting same damn directory to write to.
        UMLClassifierList concepts = m_doc->getClassesAndInterfaces();
        for (UMLClassifier *c = concepts.first(); c; c = concepts.next())
		this->writeClass(c); // call the writer for each class.
}

// write only selected concepts to file
void SimpleCodeGenerator::writeCodeToFile ( UMLClassifierList & concepts) {
        m_fileMap->clear(); // ??
        for (UMLClassifier *c = concepts.first(); c; c = concepts.next())
		this->writeClass(c); // call the writer for each class.
}

void SimpleCodeGenerator::initFields ( UMLDoc * parentDoc ) {

        // load Classifier documents from parent document
        // initFromParentDocument();

        m_fileMap = new QMap<UMLClassifier*,QString>;
        m_applyToAllRemaining = true;
	m_doc = parentDoc;

	// this really is just being used to sync the internal params
	// to the codegenpolicy as there are no code documents to really sync.
	syncCodeToDocument();
}

// a little method to provide some compatability between
// the newer codegenpolicy object and the older class fields.
void SimpleCodeGenerator::syncCodeToDocument() {

	CodeGenerationPolicy *policy = getPolicy();

        m_overwrite = policy->getOverwritePolicy();
        m_modname = policy->getModifyPolicy();
        m_forceDoc = policy->getCodeVerboseDocumentComments();
        m_forceSections = policy->getCodeVerboseSectionComments();
        m_outputDirectory = QDir(policy->getOutputDirectory().absPath());
        m_headingFiles = QDir(policy->getHeadingFileDir());
        m_indentation = policy->getIndentation();
        m_endl = policy->getNewLineEndingChars();

}


// override parent method
void SimpleCodeGenerator::initFromParentDocument( )
{
	// Do nothing
}


#include "simplecodegenerator.moc"
