/***************************************************************************
*   Copyright (C) 2003 by Roberto Raggi                                   *
*   roberto@kdevelop.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 "createpcsdialog.h"
#include "createpcsdialog.moc"
#include "driver.h"
#include "tag_creator.h"
#include "cppsupportpart.h"
#include "setuphelper.h"

#include <catalog.h>
#include <kdevpcsimporter.h>
#include <kdevcoderepository.h>

#include <tdeparts/componentfactory.h>

#include <ktrader.h>
#include <kdebug.h>
#include <klibloader.h>
#include <tdelistbox.h>
#include <kiconloader.h>
#include <tdelistview.h>
#include <tdeapplication.h>
#include <tdeinstance.h>
#include <kstandarddirs.h>
#include <tdelocale.h>
#include <kstringhandler.h>
#include <klineedit.h>

#include <tqprogressbar.h>
#include <tqheader.h>
#include <tqlabel.h>
#include <tqregexp.h>
#include <tqlayout.h>
#include <tqtimer.h>
#include <tqpushbutton.h>

#include <stdlib.h>
#include <unistd.h>

class CreatePCSDialog::RppDriver: public Driver
{
public:
	RppDriver( Catalog* c )
			: catalog( c )
	{
		setup();
	}

	virtual ~RppDriver()
	{
#if 0 /// \FIXME robe
		TagCreator::destroyDocumentation();
#endif

	}

#if 0 /// \FIXME robe
	void addDocDirectory( const TQString& dir )
	{
		m_docDirectoryList.append( dir );
		TagCreator::setDocumentationDirectories( m_docDirectoryList );
	}
#endif

	void fileParsed( ParsedFile& ast )
	{
		/// @todo increment progress

#if 0 /// @todo show problems
		TQValueList<Problem> l = problems( fileName );
		TQValueList<Problem>::Iterator it = l.begin();
		while ( it != l.end() )
		{
			const Problem & p = *it;
			++it;
		}
#endif

		takeTranslationUnit( ast );

		TagCreator w( ast.fileName(), catalog );
		w.parseTranslationUnit( ast );

		//if( !isResolveDependencesEnabled() )
		//    removeAllMacrosInFile( fileName );
	}

	// setup the preprocessor
	// code provided by Reginald Stadlbauer <reggie@trolltech.com>
	void setup()
	{
        bool ok;   
        TQString gccLibPath = SetupHelper::getGccIncludePath(&ok);
        if (!ok) 
            return;      
		gccLibPath = gccLibPath.replace( TQRegExp( "[\r\n]" ), "" );
		addIncludePath( gccLibPath );
		//addIncludePath( "/usr/include/g++-3" );
		//addIncludePath( "/usr/include/g++" );
        TQStringList lines = SetupHelper::getGccMacros(&ok);
        if (!ok) 
            return;  
        for (TQStringList::ConstIterator it = lines.constBegin(); it != lines.constEnd(); ++it) {
            TQStringList lst = TQStringList::split( ' ', *it );
            if ( lst.count() != 3 )
                continue;
            addMacro( Macro( lst[1], lst[2] ) );
        }
		addMacro( Macro( "__cplusplus", "1" ) );
		addMacro( Macro( "signals", "signals" ) );
		addMacro( Macro( "slots", "slots" ) );
	}

private:
	Catalog* catalog;
#if 0 /// \FIXME

	TQStringList m_docDirectoryList;
#endif
};


class PCSListViewItem: public TDEListViewItem
{
public:
	PCSListViewItem( KService::Ptr ptr, KDevPCSImporter* importer, TQListViewItem* parent )
			: TDEListViewItem( parent ), m_importer( importer )
	{
		init( ptr );
	}
	PCSListViewItem( KService::Ptr ptr, KDevPCSImporter* importer, TQListView* parent )
			: TDEListViewItem( parent ), m_importer( importer )
	{
		init( ptr );
	}

	~PCSListViewItem()
	{
		delete( m_importer );
		m_importer = 0;
	}

	void init( KService::Ptr ptr )
	{
		setText( 0, ptr->comment() );
		setPixmap( 0, SmallIcon( ptr->icon() ) );
	}

	KDevPCSImporter* importer()
	{
		return m_importer;
	}

private:
	KDevPCSImporter* m_importer;
};

class CreatePCSDialog::PCSJobData
{
public:
	TQString dbName;
	Catalog * catalog;
	RppDriver * driver;
	TQStringList list;
	TQStringList::iterator it;
	int progress;

	PCSJobData( const TQString & dbName, TQStringList const & fileList ) 
		: dbName( dbName), list( fileList ), it( list.begin() ), progress( 0 )
	{
		catalog = new Catalog;
		catalog->open( dbName );
		catalog->addIndex( "kind" );
		catalog->addIndex( "name" );
		catalog->addIndex( "scope" );
		catalog->addIndex( "fileName" );
		
		driver = new RppDriver( catalog );
	}
	
	~PCSJobData()
	{
		delete driver;
		delete catalog;
	}
};



CreatePCSDialog::CreatePCSDialog( CppSupportPart* part, TQWidget* parent, const char* name, bool modal, WFlags fl )
	: CreatePCSDialogBase( parent, name, modal, fl ), m_part( part ), m_jobData( 0 )
{
	helpButton()->hide();
	
	m_settings = 0;
	importerListView->header() ->hide();

	TDETrader::OfferList lst = TDETrader::self() ->query( "TDevelop/PCSImporter" );
	kdDebug( 9007 ) << "====================> found " << lst.size() << " importers" << endl;

	for ( TDETrader::OfferList::Iterator it = lst.begin(); it != lst.end(); ++it )
	{
		KService::Ptr ptr = *it;

		int error = 0;
		KDevPCSImporter* importer = KParts::ComponentFactory::createInstanceFromService<KDevPCSImporter>( ptr, this, ptr->name().latin1(), TQStringList(), &error );
		if ( importer )
		{
			new PCSListViewItem( ptr, importer, importerListView );
		}
	}

	setNextEnabled( importerPage, false );

	TQHBoxLayout* hbox = new TQHBoxLayout( settingsPage );
	hbox->setAutoAdd( true );

	if ( importerListView->firstChild() )
	{
		importerListView->setSelected( importerListView->firstChild(), true );
		setNextEnabled( importerPage, true );
	}
}

CreatePCSDialog::~CreatePCSDialog()
{}

/*$SPECIALIZATION$*/
void CreatePCSDialog::back()
{
	TQWizard::back();
}

void CreatePCSDialog::next()
{
	TQWizard::next();
}

void CreatePCSDialog::reject()
{
	if ( m_jobData ) {
		m_part->removeCatalog( m_jobData->dbName );
		
		delete m_jobData;
		m_jobData = 0;
	}
	
	TQWizard::reject();
}

void CreatePCSDialog::accept()
{
	delete m_jobData;
	m_jobData = 0;
	
	TQWizard::accept();
}

void CreatePCSDialog::slotSelected( const TQString & )
{
	if ( currentPage() == settingsPage )
	{
		if ( m_settings )
			delete( m_settings );

		KDevPCSImporter* importer = static_cast<PCSListViewItem*>( importerListView->selectedItem() ) ->importer();
		m_settings = importer->createSettingsPage( settingsPage );
		setNextEnabled( currentPage(), false );
		setHelpEnabled( currentPage(), false );
		connect( m_settings, TQ_SIGNAL( enabled( int ) ), this, TQ_SLOT( setNextPageEnabled( int ) ) );

		if ( m_settings )
		{
			setHelpEnabled( m_settings, false );
			m_settings->show();
		}
	}
	else if ( currentPage() == descriptionPage )
	{
		KDevPCSImporter* importer = static_cast<PCSListViewItem*>( importerListView->selectedItem() )->importer();
		filename_edit->setText( importer->dbName() );
	}
	else if ( currentPage() == finalPage )
	{
		setBackEnabled( currentPage(), false );
		setNextEnabled( currentPage(), false );

		KDevPCSImporter* importer = static_cast<PCSListViewItem*>( importerListView->selectedItem() )->importer();
		TQStringList fileList = importer->fileList();
		progressBar->setTotalSteps( fileList.size() );
		progressBar->setPercentageVisible( true );

		TDEStandardDirs *dirs = m_part->instance() ->dirs();

		TQString dbName = dirs->saveLocation( "data", "kdevcppsupport/pcs" ) + KURL::encode_string_no_slash(filename_edit->text()) + ".db";
		kdDebug( 9007 ) << "================================> dbName = " << dbName << endl;

		m_part->removeCatalog( dbName );
		
		m_jobData = new PCSJobData( dbName, fileList );
		TQTimer::singleShot( 0, this, TQ_SLOT(parseNext()) );
	}
}

void CreatePCSDialog::parseNext( )
{
	if ( ! m_jobData ) return;
	
	if ( m_jobData->it == m_jobData->list.end() ) 
	{
		if ( m_jobData->progress > 0 )
		{
			m_part->addCatalog( m_jobData->catalog );
			m_jobData->catalog = 0;
		}
		currentFile->setText("");
		cancelButton()->setEnabled( false );
		
		setFinishEnabled( currentPage(), true );
		
		delete m_jobData;
		m_jobData = 0;
		
		return;
	}
	
	progressBar->setProgress( ++(m_jobData->progress) );
	currentFile->setText( KStringHandler::lsqueeze( *(m_jobData->it), 80 ) );
	
	m_jobData->driver->parseFile( *(m_jobData->it) );
	
	++(m_jobData->it);
	
	TQTimer::singleShot( 0, this, TQ_SLOT(parseNext()) );	
}


void CreatePCSDialog::setNextPageEnabled( int enabled )
{
	setNextEnabled( currentPage(), enabled );
}

void CreatePCSDialog::slotSelectionChanged( TQListViewItem * item )
{
	setNextPageEnabled( item != 0 );
}
