/***************************************************************************
 *   Copyright (C) 2003-2005 by David Saxton                               *
 *   david@bluehaze.org                                                    *
 *                                                                         *
 *   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 "core/ktlconfig.h"
#include "docmanager.h"
#include "document.h"
#include "language.h"
#include "languagemanager.h"
#include "ktechlab.h"
#include "microselectwidget.h"
#include "programmerdlg.h"
#include "projectdlgs.h"
#include "projectmanager.h"
#include "recentfilesaction.h"

#include <kdebug.h>
#include <kfiledialog.h>
#include <kiconloader.h>
#include <kio/netaccess.h>
#include <klocale.h>
#include <kmessagebox.h> 
#include <kmimetype.h>
#include <kstandarddirs.h>
#include <qdom.h>
#include <qpopupmenu.h>
#include <qwhatsthis.h>

#include <assert.h>

//BEGIN class LinkerOptions
LinkerOptions::LinkerOptions()
{
	m_hexFormat = HexFormat::inhx32;
	m_bOutputMapFile = false;
}


QDomElement LinkerOptions::toDomElement( QDomDocument & doc, const KURL & baseURL ) const
{
	QDomElement node = doc.createElement("linker");
	
	node.setAttribute( "hex-format", hexFormatToString(hexFormat()) );
	node.setAttribute( "output-map-file", outputMapFile() );
	node.setAttribute( "library-dir", libraryDir() );
	node.setAttribute( "linker-script", linkerScript() );
	node.setAttribute( "other", linkerOther() );
	
	QStringList::const_iterator end = m_linkedInternal.end();
	for ( QStringList::const_iterator it = m_linkedInternal.begin(); it != end; ++it )
	{
		QDomElement child = doc.createElement("linked-internal");
		node.appendChild(child);
		child.setAttribute( "url", KURL::relativeURL( baseURL, *it ) );
	}
	
	end = m_linkedExternal.end();
	for ( QStringList::const_iterator it = m_linkedExternal.begin(); it != end; ++it )
	{
		QDomElement child = doc.createElement("linked-external");
		node.appendChild(child);
		child.setAttribute( "url", *it );
	}
	
	return node;
}


void LinkerOptions::domElementToLinkerOptions( const QDomElement & element, const KURL & baseURL )
{
	setHexFormat( stringToHexFormat( element.attribute( "hex-format", QString::null ) ) );
	setOutputMapFile( element.attribute( "output-map-file", "0" ).toInt() );
	setLibraryDir( element.attribute( "library-dir", QString::null ) );
	setLinkerScript( element.attribute( "linker-script", QString::null ) );
	setLinkerOther( element.attribute( "other", QString::null ) );
	
	m_linkedInternal.clear();
	m_linkedExternal.clear();
	
	QDomNode node = element.firstChild();
	while ( !node.isNull() )
	{
		QDomElement childElement = node.toElement();
		if ( !childElement.isNull() )
		{
			const QString tagName = childElement.tagName();
			
			if ( tagName == "linked-internal" )
				m_linkedInternal << KURL( baseURL, childElement.attribute( "url", QString::null ) ).url();
			
			else if ( tagName == "linked-external" )
				m_linkedExternal << childElement.attribute( "url", QString::null );
			
			else
				kdError() << k_funcinfo << "Unrecognised element tag name: "<<tagName<<endl;
		}
		
		node = node.nextSibling();
	}
}


QString LinkerOptions::hexFormatToString( HexFormat::type hexFormat )
{
	switch ( hexFormat )
	{
		case HexFormat::inhx32:
			return "inhx32";
			
		case HexFormat::inhx8m:
			return "inhx8m";
			
		case HexFormat::inhx8s:
			return "inhx8s";
			
		case HexFormat::inhx16:
			return "inhx16";
	}
	
	// Default hex format is inhx32
	return "inhx32";
}


LinkerOptions::HexFormat::type LinkerOptions::stringToHexFormat( const QString & hexFormat )
{
	if ( hexFormat == "inhx8m" )
		return HexFormat::inhx8m;
	
	if ( hexFormat == "inhx8s" )
		return HexFormat::inhx8s;
	
	if ( hexFormat == "inhx16" )
		return HexFormat::inhx16;
	
	return HexFormat::inhx32;
}
//END class LinkerOptions



//BEGIN class ProcessingOptions
ProcessingOptions::ProcessingOptions()
{
	m_bUseParentMicroID = false;
	m_microID = "P16F84";
}


ProcessingOptions::~ProcessingOptions()
{
}


QDomElement ProcessingOptions::toDomElement( QDomDocument & doc, const KURL & baseURL ) const
{
	QDomElement node = doc.createElement("processing");
	
	node.setAttribute( "output", KURL::relativeURL( baseURL, outputURL().url() ) );
	node.setAttribute( "micro", m_microID );
	
	return node;
}


void ProcessingOptions::domElementToProcessingOptions( const QDomElement & element, const KURL & baseURL )
{
	setOutputURL( KURL( baseURL, element.attribute( "output", QString::null ) ) );
	setMicroID( element.attribute("micro", QString::null ) );
}
//END class ProcessingOptions



//BEGIN class ProjectItem
ProjectItem::ProjectItem( ProjectItem * parent, Type type, ProjectManager * projectManager, KTechlab * ktechlab )
	: QObject()
{
	m_pParent = parent;
	m_pILVItem = 0l;
	m_pProjectManager = projectManager;
	p_ktechlab = ktechlab;
	m_type = type;
}


ProjectItem::~ProjectItem()
{
	m_children.remove( (ProjectItem*)0l );
	ProjectItemList::iterator end = m_children.end();
	for ( ProjectItemList::iterator it = m_children.begin(); it != end; ++it )
		(*it)->deleteLater();
	m_children.clear();
	
	delete m_pILVItem;
	m_pILVItem = 0l;
}


void ProjectItem::setILVItem( ILVItem * ilvItem )
{
	m_pILVItem = ilvItem;
	ilvItem->setOpen(true);
	ilvItem->setText( 0, name() );
	ilvItem->setProjectItem(this);
	updateILVItemPixmap();
}


void ProjectItem::updateILVItemPixmap()
{
	if ( !m_pILVItem )
		return;
	
	switch ( type() )
	{
		case ProjectType:
		{
			// ?! - We shouldn't have an ilvitem for this.
			break;
		}
		
		case ProgramType:
		{
			QPixmap pm;
			pm.load( locate( "appdata", "icons/project_program.png" ) );
			m_pILVItem->setPixmap( 0, pm );
			break;
		}
		
		case LibraryType:
		{
			QPixmap pm;
			pm.load( locate( "appdata", "icons/project_library.png" ) );
			m_pILVItem->setPixmap( 0, pm );
			break;
		}
		
		case FileType:
		{
			KMimeType::Ptr m = KMimeType::findByPath( url().path() );
			m_pILVItem->setPixmap( 0, m->pixmap( KIcon::Small ) );
			break;
		}
	}
}


void ProjectItem::addChild( ProjectItem * child )
{
	if ( !child || m_children.contains(child) )
		return;
	
	m_children << child;
	
	child->setILVItem( m_pILVItem ?
			new ILVItem( m_pILVItem, child->name() ) :
			new ILVItem( m_pProjectManager, name() ) );
	
	updateControlChildMicroIDs();
}


void ProjectItem::updateControlChildMicroIDs()
{
	bool control = false;
	switch ( type() )
	{
		case ProjectItem::ProjectType:
		case ProjectItem::LibraryType:
		case ProjectItem::ProgramType:
			control = !microID().isEmpty();
			break;
			
		case ProjectItem::FileType:
			control = true;
			break;
	}
	
	m_children.remove( (ProjectItem*)0l );
	ProjectItemList::iterator end = m_children.end();
	for ( ProjectItemList::iterator it = m_children.begin(); it != end; ++it )
		(*it)->setUseParentMicroID( control );
}


void ProjectItem::setName( const QString & name )
{
	m_name = name;
	if (m_pILVItem)
		m_pILVItem->setText( 0, name );
}


void ProjectItem::setURL( const KURL & url )
{
	m_url = url;
	
	if ( m_name.isEmpty() )
		setName( url.fileName() );
	
	if ( type() != FileType )
	{
		// The output url *is* our url
		setOutputURL(url);
	}
	else if ( outputURL().isEmpty() )
	{
		// Try and guess what the output url should be...
		QString newExtension;
		
		switch ( outputType() )
		{
			case ProgramOutput:
				newExtension = ".hex";
				break;
				
			case ObjectOutput:
				newExtension = ".o";
				break;
				
			case LibraryOutput:
				newExtension = ".o";
				break;
				
			case UnknownOutput:
				break;
		}
		
		if ( !newExtension.isEmpty() )
		{
			const QString fileName = url.url();
			QString extension = fileName.right( fileName.length() - fileName.findRev('.') );
			setOutputURL( QString(fileName).replace( extension, newExtension ) );
		}
	}
	
	updateILVItemPixmap();
}


QString ProjectItem::microID() const
{
	if ( !m_bUseParentMicroID )
		return m_microID;
	
	return m_pParent ? m_pParent->microID() : QString::null;
}


void ProjectItem::setMicroID( const QString & id )
{
	ProcessingOptions::setMicroID(id);
	updateControlChildMicroIDs();
}


ProjectItem::OutputType ProjectItem::outputType() const
{
	if ( !m_pParent )
		return UnknownOutput;
	
	switch ( m_pParent->type() )
	{
		case ProjectItem::ProjectType:
		{
			// We're a top level build target, so look at our own type
			switch ( type() )
			{
				case ProjectItem::ProjectType:
					kdWarning() << k_funcinfo << "Parent item and this item are both project items" << endl;
					return UnknownOutput;
						
				case ProjectItem::FileType:
				case ProjectItem::ProgramType:
					return ProgramOutput;
						
				case ProjectItem::LibraryType:
					return LibraryOutput;
			}
			return UnknownOutput;
		}
				
		case ProjectItem::FileType:
		{
			kdWarning() << k_funcinfo << "Don't know how to handle parent item being a file" << endl;
			return UnknownOutput;
		}
				
		case ProjectItem::ProgramType:
		case ProjectItem::LibraryType:
			return ObjectOutput;
	}
	
	return UnknownOutput;
}


bool ProjectItem::build( ProcessOptionsList * pol )
{
	if ( !pol )
		return false;
	
	// Check to see that we aren't already in the ProcessOptionstList;
	ProcessOptionsList::iterator polEnd = pol->end();
	for ( ProcessOptionsList::iterator it = pol->begin(); it != polEnd; ++it )
	{
		if ( (*it).targetFile() == outputURL().path() )
			return true;
	}
	
	ProjectInfo * projectInfo = ProjectManager::self()->currentProject();
	assert(projectInfo);
	
	if ( outputURL().isEmpty() )
	{
		KMessageBox::sorry( 0l, i18n("Don't know how to build \"%1\" (output url is empty).").arg(name()) );
		return false;
	}
	
	// Build all internal libraries that we depend on
	QStringList::iterator send = m_linkedInternal.end();
	for ( QStringList::iterator it = m_linkedInternal.begin(); it != send; ++it )
	{
		ProjectItem * lib = projectInfo->findItem( projectInfo->directory() + *it );
		if ( !lib )
		{
			KMessageBox::sorry( 0l, i18n("Don't know how to build \"%1\" (library does not exist in project).").arg(*it) );
			return false;
		}
		
		if ( !lib->build(pol) )
			return false;
	}
	
	
	// Build all children
	m_children.remove( (ProjectItem*)0l );
	ProjectItemList::iterator cend = m_children.end();
	for ( ProjectItemList::iterator it = m_children.begin(); it != cend; ++it )
	{
		if ( ! (*it)->build(pol) )
			return false;
	}
	
	
	// Now build ourself
	ProcessOptions po;
	po.b_addToProject = false;
	po.setTargetFile( outputURL().path() );
	po.m_picID = microID();
	
	ProcessOptions::ProcessPath::MediaType typeTo;
	
	switch ( outputType() )
	{
		case UnknownOutput:
			KMessageBox::sorry( 0l, i18n("Don't know how to build \"%1\" (unknown output type).").arg(name()) );
			return false;
			
		case ProgramOutput:
			typeTo = ProcessOptions::ProcessPath::Program;
			break;
			
		case ObjectOutput:
			typeTo = ProcessOptions::ProcessPath::Object;
			break;
			
		case LibraryOutput:
			typeTo = ProcessOptions::ProcessPath::Library;
			break;
	}
	
	switch ( type() )
	{
		case ProjectType:
			// Nothing to do
			return true;
			
		case FileType:
			po.setInputFiles( url().path() );
			po.setProcessPath( ProcessOptions::ProcessPath::path( ProcessOptions::guessMediaType( url().url() ), typeTo ) );
			break;
			
		case ProgramType:
		case LibraryType:
			// Build up a list of input urls
			QStringList inputFiles;
			
			// Link child objects
			m_children.remove( (ProjectItem*)0l );
			ProjectItemList::iterator cend = m_children.end();
			for ( ProjectItemList::iterator it = m_children.begin(); it != cend; ++it )
				inputFiles << (*it)->outputURL().path();
			
			po.setInputFiles(inputFiles);
			po.setProcessPath( ProcessOptions::ProcessPath::path( ProcessOptions::ProcessPath::Object, typeTo ) );
			break;
	}
	
	po.m_hexFormat = hexFormatToString( hexFormat() );
	po.m_bOutputMapFile = outputMapFile();
	po.m_libraryDir = libraryDir();
	po.m_linkerScript = linkerScript();
	po.m_linkOther = linkerOther();
	
	// Link against libraries	
	QStringList::iterator lend = m_linkedInternal.end();
	for ( QStringList::iterator it = m_linkedInternal.begin(); it != lend; ++it )
		po.m_linkLibraries += projectInfo->directory() + *it;
	lend = m_linkedExternal.end();
	for ( QStringList::iterator it = m_linkedExternal.begin(); it != lend; ++it )
		po.m_linkLibraries += *it;
	
	// Save our working file (if open) and append to the build list
	Document * currentDoc = DocManager::self()->findDocument( url() );
	if (currentDoc)
		currentDoc->fileSave();
	pol->append(po);
	
	return true;
}


void ProjectItem::upload( ProcessOptionsList * pol )
{
	build( pol );
	
	ProgrammerDlg * dlg = new ProgrammerDlg( microID(), (QWidget*)p_ktechlab, "Programmer Dlg" );
	
	dlg->exec();
	if ( !dlg->isAccepted() )
	{
		dlg->deleteLater();
		return;
	}
	
	ProcessOptions po;
	dlg->initOptions( & po );
	po.b_addToProject = false;
	po.setInputFiles( outputURL().path() );
	po.setProcessPath( ProcessOptions::ProcessPath::Program_PIC );
	
	pol->append( po );
	
	dlg->deleteLater();
}


QDomElement ProjectItem::toDomElement( QDomDocument & doc, const KURL & baseURL ) const
{
	QDomElement node = doc.createElement("item");
	
	node.setAttribute( "type", typeToString() );
	node.setAttribute( "name", m_name );
	node.setAttribute( "url", KURL::relativeURL( baseURL, m_url.url() ) );
	
	node.appendChild( LinkerOptions::toDomElement( doc, baseURL ) );
	node.appendChild( ProcessingOptions::toDomElement( doc, baseURL ) );
	
	
	ProjectItemList::const_iterator end = m_children.end();
	for ( ProjectItemList::const_iterator it = m_children.begin(); it != end; ++it )
	{
		if (*it)
			node.appendChild( (*it)->toDomElement( doc, baseURL ) );
	}
	
	return node;
}


KURL::List ProjectItem::childOutputURLs( unsigned types, unsigned outputTypes ) const
{
	KURL::List urls;
	
	ProjectItemList::const_iterator end = m_children.end();
	for ( ProjectItemList::const_iterator it = m_children.begin(); it != end; ++it )
	{
		if (!*it)
			continue;
		
		if ( ((*it)->type() & types) && ((*it)->outputType() & outputTypes) )
			urls += (*it)->outputURL().prettyURL();
		
		urls += (*it)->childOutputURLs(types);
	}
	
	return urls;
}


ProjectItem * ProjectItem::findItem( const KURL & url )
{
	if ( this->url() == url )
		return this;
	
	ProjectItemList::const_iterator end = m_children.end();
	for ( ProjectItemList::const_iterator it = m_children.begin(); it != end; ++it )
	{
		if (!*it)
			continue;
		
		ProjectItem * found = (*it)->findItem(url);
		if (found)
			return found;
	}
	
	return 0l;
}


bool ProjectItem::closeOpenFiles()
{
	Document * doc = DocManager::self()->findDocument(m_url);
	if ( doc && !doc->fileClose() )
		return false;
	
	m_children.remove( (ProjectItem*)0l );
	ProjectItemList::iterator end = m_children.end();
	for ( ProjectItemList::iterator it = m_children.begin(); it != end; ++it )
	{
		if ( !(*it)->closeOpenFiles() )
			return false;
	}
	
	return true;
}


void ProjectItem::addFiles()
{
	KURL::List urls = p_ktechlab->getFileURLs();
	const KURL::List::iterator end = urls.end();
	for ( KURL::List::iterator it = urls.begin(); it != end; ++ it)
		addFile(*it);
}


void ProjectItem::addCurrentFile()
{
	Document *document = DocManager::self()->getFocusedDocument();
	if (!document)
		return;
	
	// If the file isn't saved yet, we must do that
	// before it is added to the project.
	if( document->url().isEmpty() )
	{
		document->fileSaveAs();
		// If the user pressed cancel then just give up,
		// otherwise the file can now be added.
	}
	
	if( !document->url().isEmpty() )
		addFile( document->url() );
}


void ProjectItem::addFile( const KURL & url )
{
	if ( url.isEmpty() )
		return;
	
	m_children.remove( (ProjectItem*)0l );
	ProjectItemList::iterator end = m_children.end();
	for ( ProjectItemList::iterator it = m_children.begin(); it != end; ++it )
	{
		if ( (*it)->type() == FileType && (*it)->url() == url )
			return;
	}
	
	ProjectItem * item = new ProjectItem( this, FileType, m_pProjectManager, p_ktechlab );
	item->setURL(url);
	addChild(item);
}


QString ProjectItem::typeToString() const
{
	switch (m_type)
	{
		case ProjectType:
			return "Project";
			
		case FileType:
			return "File";
			
		case ProgramType:
			return "Program";
			
		case LibraryType:
			return "Library";
	}
	return QString::null;
}


ProjectItem::Type ProjectItem::stringToType( const QString & type )
{
	if ( type == "Project" )
		return ProjectType;
	
	if ( type == "File" )
		return FileType;
	
	if ( type == "Program" )
		return ProgramType;
	
	if ( type == "Library" )
		return LibraryType;
	
	return FileType;
}


void ProjectItem::domElementToItem( const QDomElement & element, const KURL & baseURL )
{
	Type type = stringToType( element.attribute( "type", QString::null ) );
	QString name = element.attribute( "name", QString::null );
	KURL url( baseURL, element.attribute( "url", QString::null ) );
	
	ProjectItem * createdItem = new ProjectItem( this, type, m_pProjectManager, p_ktechlab );
	createdItem->setName( name );
	createdItem->setURL( url );
	
	addChild( createdItem );
	
	QDomNode node = element.firstChild();
	while ( !node.isNull() )
	{
		QDomElement childElement = node.toElement();
		if ( !childElement.isNull() )
		{
			const QString tagName = childElement.tagName();
			
			if ( tagName == "linker" )
				createdItem->domElementToLinkerOptions( childElement, baseURL );
			
			else if ( tagName == "processing" )
				createdItem->domElementToProcessingOptions( childElement, baseURL );
			
			else if ( tagName == "item" )
				createdItem->domElementToItem( childElement, baseURL );
			
			else
				kdError() << k_funcinfo << "Unrecognised element tag name: "<<tagName<<endl;
		}
		
		node = node.nextSibling();
	}
}
//END class ProjectItem



//BEGIN class ProjectInfo
ProjectInfo::ProjectInfo( ProjectManager * projectManager, KTechlab * ktechlab )
	: ProjectItem( 0l, ProjectItem::ProjectType, projectManager, ktechlab )
{
	m_microID = QString::null;
}


ProjectInfo::~ ProjectInfo()
{
}


bool ProjectInfo::open( const KURL & url )
{
	QString target;
	if ( !KIO::NetAccess::download( url, target, 0l ) )
	{
		// If the file could not be downloaded, for example does not
		// exist on disk, NetAccess will tell us what error to use
		KMessageBox::error( 0l, KIO::NetAccess::lastErrorString() );
		
		return false;
	}
	
	QFile file(target);
	if ( !file.open( IO_ReadOnly ) )
	{
		KMessageBox::sorry( 0l, i18n("Could not open %1 for reading").arg(target) );
		return false;
	}
	
	m_url = url;
	
	QString xml;
	QTextStream textStream( &file );
	while ( !textStream.eof() )
		xml += textStream.readLine() + '\n';
	
	file.close();
	
	QDomDocument doc( "KTechlab" );
	QString errorMessage;
	if ( !doc.setContent( xml, &errorMessage ) )
	{
		KMessageBox::sorry( 0l, i18n("Couldn't parse xml:\n%1").arg(errorMessage) );
		return false;
	}
	
	QDomElement root = doc.documentElement();
	
	QDomNode node = root.firstChild();
	while ( !node.isNull() )
	{
		QDomElement element = node.toElement();
		if ( !element.isNull() )
		{
			const QString tagName = element.tagName();
			
			if ( tagName == "linker" )
				domElementToLinkerOptions( element, m_url );
			
			else if ( tagName == "processing" )
				domElementToProcessingOptions( element, m_url );
			
			else if ( tagName == "file" || tagName == "item" )
				domElementToItem( element, m_url );
			
			else
				kdWarning() << k_funcinfo << "Unrecognised element tag name: "<<tagName<<endl;
		}
		
		node = node.nextSibling();
	}
	
	updateControlChildMicroIDs();
	return true;
}


bool ProjectInfo::save()
{
	QFile file( m_url.path() );
	if ( file.open(IO_WriteOnly) == false )
	{
		KMessageBox::sorry( NULL, i18n("Project could not be saved to \"%1\"").arg(m_url.path()), i18n("Saving Project") );
		return false;
	}
	
	QDomDocument doc("KTechlab");
	
	QDomElement root = doc.createElement("project");
	doc.appendChild(root);
	
// 	root.appendChild( LinkerOptions::toDomElement(doc) );
// 	root.appendChild( ProcessingOptions::toDomElement(doc) );
	
	m_children.remove( (ProjectItem*)0l );
	ProjectItemList::const_iterator end = m_children.end();
	for ( ProjectItemList::const_iterator it = m_children.begin(); it != end; ++it )
		root.appendChild( (*it)->toDomElement( doc, m_url ) );
	
	QTextStream stream(&file);
	stream << doc.toString();
	file.close();
	
	(static_cast<RecentFilesAction*>(p_ktechlab->action("project_open_recent")))->addURL(m_url);
	
	return true;
}


bool ProjectInfo::saveAndClose()
{
	if (!save())
		return false;
	
	if (!closeOpenFiles())
		return false;
	
	return true;
}
//END class ProjectInfo



//BEGIN class ProjectManager
ProjectManager * ProjectManager::m_pSelf = 0l;

ProjectManager * ProjectManager::self( KTechlab * ktl, KateMDI::ToolView * parent )
{
	if ( !m_pSelf )
	{
		assert(ktl);
		assert(parent);
		m_pSelf = new ProjectManager( ktl, parent );
	}
	return m_pSelf;
}


ProjectManager::ProjectManager( KTechlab * ktl, KateMDI::ToolView * parent )
	: ItemSelector( parent, "Project Manager" ),
	m_pCurrentProject(0l),
	p_ktechlab(ktl)
{
	QWhatsThis::add( this, i18n("Displays the list of files in the project.\nTo open or close a project, use the \"Project\" menu. Right click on a file to remove it from the project") );
	
	setListCaption( i18n("File") );
	setCaption( i18n("Project Manager") );
	
	connect( this, SIGNAL(clicked(QListViewItem*)), this, SLOT(slotItemClicked(QListViewItem*)) );
}


ProjectManager::~ProjectManager()
{
}


void ProjectManager::slotNewProject()
{
	if ( !slotCloseProject() )
		return;
	
	NewProjectDlg *newProjectDlg = new NewProjectDlg(this);
	newProjectDlg->exec();

	if ( newProjectDlg->accepted() )
	{
		m_pCurrentProject = new ProjectInfo( this, p_ktechlab );
		m_pCurrentProject->setName( newProjectDlg->projectName() );
		m_pCurrentProject->setURL( newProjectDlg->location() + m_pCurrentProject->name().lower() + ".ktechlab" );
		
        QDir dir;
        if ( !dir.mkdir( m_pCurrentProject->directory() ) )
			kdDebug() << "Error in creating directory " << m_pCurrentProject->directory() << endl;
		
		m_pCurrentProject->save();
		updateActions();
		
		emit projectCreated();
	}
	
	delete newProjectDlg;
}


void ProjectManager::slotProjectOptions()
{
}


void ProjectManager::slotOpenProject()
{
    KURL url = KFileDialog::getOpenURL(QString::null,
	        "*.ktechlab|KTechlab Project(*.ktechlab)\n*|All Files", this, i18n("Open Location"));
	
    if ( url.isEmpty() )
		return;
	
	slotOpenProject(url);
}


void ProjectManager::slotOpenProject( const KURL & url )
{
	if ( m_pCurrentProject && m_pCurrentProject->url() == url )
		return;
	
	if ( !slotCloseProject() )
		return;
	
	m_pCurrentProject = new ProjectInfo( this, p_ktechlab );
	
	if ( !m_pCurrentProject->open(url) )
	{
		m_pCurrentProject->deleteLater();
		m_pCurrentProject = 0l;
		return;
	}
	
	RecentFilesAction * rfa = static_cast<RecentFilesAction*>(p_ktechlab->action("project_open_recent"));
	rfa->addURL( m_pCurrentProject->url() );
	
	if ( KTLConfig::raiseItemSelectors() )
		p_ktechlab->showToolView( p_ktechlab->toolView( toolViewIdentifier() ) );
	
	updateActions();
	emit projectOpened();
}


bool ProjectManager::slotCloseProject()
{
	if ( !m_pCurrentProject )
		return true;
	
	if ( !m_pCurrentProject->saveAndClose() )
		return false;
	
	m_pCurrentProject->deleteLater();
	m_pCurrentProject = 0l;
	updateActions();
	emit projectClosed();
	return true;
}


void ProjectManager::slotCreateSubproject()
{
	if ( !currentProject() )
		return;
	
	CreateSubprojectDlg * dlg = new CreateSubprojectDlg(this);
	dlg->exec();
	
	if ( dlg->accepted() )
	{
		ProjectItem::Type type = ProjectItem::ProgramType;
		switch ( dlg->type() )
		{
			case CreateSubprojectDlg::ProgramType:
				type = ProjectItem::ProgramType;
				break;
				
			case CreateSubprojectDlg::LibraryType:
				type = ProjectItem::LibraryType;
				break;
		}
		
		ProjectItem * subproject = new ProjectItem( currentProject(), type, this, p_ktechlab );
		subproject->setURL( dlg->targetFile() );
		
		currentProject()->addChild(subproject);
		currentProject()->save();
		
		emit subprojectCreated();
	}
	
	delete dlg;
}


void ProjectManager::updateActions()
{
	bool projectIsOpen = m_pCurrentProject;
	
	p_ktechlab->action("project_create_subproject")->setEnabled( projectIsOpen );
	p_ktechlab->action("project_export_makefile")->setEnabled( projectIsOpen );
	p_ktechlab->action("subproject_add_existing_file")->setEnabled( projectIsOpen );
	p_ktechlab->action("subproject_add_current_file")->setEnabled( projectIsOpen );
// 	p_ktechlab->action("project_options")->setEnabled( projectIsOpen );
	p_ktechlab->action("project_close")->setEnabled( projectIsOpen );
	p_ktechlab->action("project_add_existing_file")->setEnabled( projectIsOpen );
	p_ktechlab->action("project_add_current_file")->setEnabled( projectIsOpen );
}


void ProjectManager::slotAddFile()
{
	if ( !currentProject() )
		return;
	
	currentProject()->addFiles();
	emit filesAdded();
}


void ProjectManager::slotAddCurrentFile()
{
	if ( !currentProject() )
		return;
	currentProject()->addCurrentFile();
	emit filesAdded();
}


void ProjectManager::slotSubprojectAddExistingFile()
{
	ILVItem * currentItem = dynamic_cast<ILVItem*>(selectedItem());
	if ( !currentItem || !currentItem->projectItem() )
		return;
	
	currentItem->projectItem()->addFiles();
	emit filesAdded();
}


void ProjectManager::slotSubprojectAddCurrentFile()
{
	ILVItem * currentItem = dynamic_cast<ILVItem*>(selectedItem());
	if ( !currentItem || !currentItem->projectItem() )
		return;
	
	currentItem->projectItem()->addCurrentFile();
	emit filesAdded();
}


void ProjectManager::slotItemBuild()
{
	ILVItem * currentItem = dynamic_cast<ILVItem*>(selectedItem());
	if ( !currentItem || !currentItem->projectItem() )
		return;
	
	ProcessOptionsList pol;
	currentItem->projectItem()->build(&pol);
	LanguageManager::self()->compile(pol);
}


void ProjectManager::slotItemUpload()
{
	ILVItem * currentItem = dynamic_cast<ILVItem*>(selectedItem());
	if ( !currentItem || !currentItem->projectItem() )
		return;
	
	ProcessOptionsList pol;
	currentItem->projectItem()->upload(&pol);
	LanguageManager::self()->compile(pol);
}


void ProjectManager::slotRemoveSelected()
{
	ILVItem *currentItem = dynamic_cast<ILVItem*>(selectedItem());
	if ( !currentItem )
		return;
	
	int choice = KMessageBox::questionYesNo( this, i18n("Do you really want to remove \"%1\"?").arg( currentItem->text(0) ), i18n("Remove Project File?"), KGuiItem(i18n("Remove")), KGuiItem(i18n("Cancel")) );
	
	if ( choice == KMessageBox::No )
		return;
	
	currentItem->projectItem()->deleteLater();
	emit filesRemoved();
}


void ProjectManager::slotExportToMakefile()
{
}


void ProjectManager::slotSubprojectLinkerOptions()
{
	ILVItem * currentItem = dynamic_cast<ILVItem*>(selectedItem());
	if ( !currentItem || !currentItem->projectItem() )
		return;
	
	LinkerOptionsDlg * dlg = new LinkerOptionsDlg( currentItem->projectItem(), this );
	dlg->exec();
	currentProject()->save();
	
	// The dialog sets the options for us if it was accepted, so we don't need to do anything
	delete dlg;
}


void ProjectManager::slotItemProcessingOptions()
{
	ILVItem * currentItem = dynamic_cast<ILVItem*>(selectedItem());
	if ( !currentItem || !currentItem->projectItem() )
		return;
	
	ProcessingOptionsDlg * dlg = new ProcessingOptionsDlg( currentItem->projectItem(), this );
	dlg->exec();
	currentProject()->save();
	
	// The dialog sets the options for us if it was accepted, so we don't need to do anything
	delete dlg;
}


void ProjectManager::slotItemClicked( QListViewItem * item )
{
	ILVItem * ilvItem = dynamic_cast<ILVItem*>(item);
	if ( !ilvItem )
		return;
	
	ProjectItem * projectItem = ilvItem->projectItem();
	if ( !projectItem || projectItem->type() != ProjectItem::FileType )
		return;
	
	DocManager::self()->openURL( projectItem->url() );
}


void ProjectManager::slotContextMenuRequested( QListViewItem * item, const QPoint& pos, int /*col*/ )
{
	QString popupName;
	ILVItem * ilvItem = dynamic_cast<ILVItem*>(item);
	KAction * linkerOptionsAct = p_ktechlab->action("project_item_linker_options");
	linkerOptionsAct->setEnabled(false);
	
	if ( !m_pCurrentProject )
		popupName = "project_none_popup";
	
	else if ( !ilvItem )
		popupName = "project_blank_popup";
	
	else
	{
		ProcessOptions::ProcessPath::MediaType mediaType = ProcessOptions::guessMediaType( ilvItem->projectItem()->url().url() );
		
		switch ( ilvItem->projectItem()->type() )
		{
			case ProjectItem::FileType:
				if ( mediaType == ProcessOptions::ProcessPath::Unknown )
					popupName = "project_file_other_popup";
				else
					popupName = "project_file_popup";
				break;
			
			case ProjectItem::ProgramType:
				popupName = "project_program_popup";
				break;
			
			case ProjectItem::LibraryType:
				popupName = "project_library_popup";
				break;
			
			case ProjectItem::ProjectType:
				return;
		}
		switch ( ilvItem->projectItem()->outputType() )
		{
			case ProjectItem::ProgramOutput:
				linkerOptionsAct->setEnabled(true);
				break;
				
			case ProjectItem::ObjectOutput:
			case ProjectItem::LibraryOutput:
			case ProjectItem::UnknownOutput:
				linkerOptionsAct->setEnabled(false);
				break;
		}
		
		// Only have linking options for SDCC files
		linkerOptionsAct->setEnabled( mediaType == ProcessOptions::ProcessPath::C );
	}
	
	bool haveFocusedDocument = DocManager::self()->getFocusedDocument();
	p_ktechlab->action("subproject_add_current_file")->setEnabled( haveFocusedDocument );
	p_ktechlab->action("project_add_current_file")->setEnabled( haveFocusedDocument );
	
	QPopupMenu *pop = static_cast<QPopupMenu*>(p_ktechlab->factory()->container( popupName, p_ktechlab ));
	if (pop)
		pop->popup(pos);
}
//END class ProjectManager

#include "projectmanager.moc"
