/***************************************************************************
 *   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 <catalog.h>
#include <kdevpcsimporter.h>
#include <kdevcoderepository.h>

#include <kparts/componentfactory.h>

#include <ktrader.h>
#include <kdebug.h>
#include <klibloader.h>
#include <klistbox.h>
#include <kiconloader.h>
#include <klistview.h>
#include <kapplication.h>
#include <kinstance.h>
#include <kstandarddirs.h>

#include <qprogressbar.h>
#include <qheader.h>
#include <qlabel.h>
#include <qprocess.h>
#include <qregexp.h>
#include <qlayout.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 QString& dir )
    {
        m_docDirectoryList.append( dir );
        TagCreator::setDocumentationDirectories( m_docDirectoryList );
    }
#endif

    void fileParsed( const QString& fileName )
    {
	/// @todo increment progress

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

        TranslationUnitAST::Node ast = takeTranslationUnit( fileName );

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

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

    // setup the preprocessor
    // code provided by Reginald Stadlbauer <reggie@trolltech.com>
    void setup()
    {
	QProcess proc;
	proc.addArgument( "gcc" );
	proc.addArgument( "-print-file-name=include" );
	if ( !proc.start() ) {
	    /// @todo message box
	    return;
	}

	while ( proc.isRunning() )
	    usleep( 1 );

	QString gccLibPath = proc.readStdout();
	gccLibPath = gccLibPath.replace( QRegExp("[\r\n]"), "" );
	addIncludePath( gccLibPath );
	//addIncludePath( "/usr/include/g++-3" );
	//addIncludePath( "/usr/include/g++" );
	proc.clearArguments();
	proc.addArgument( "gcc" );
	proc.addArgument( "-E" );
	proc.addArgument( "-dM" );
	proc.addArgument( "-ansi" );
	proc.addArgument( "-" );

	if ( !proc.start() ) {
	    /// @todo message box
	    return;
	}

	while ( !proc.isRunning() )
	    usleep( 1 );
	proc.closeStdin();
	while ( proc.isRunning() )
	    usleep( 1 );

	while ( proc.canReadLineStdout() ) {
	    QString l = proc.readLineStdout();
	    QStringList lst = QStringList::split( ' ', l );
	    if ( lst.count() != 3 )
		continue;

	    addMacro( Macro( lst[1], lst[2] ) );
	}
	addMacro( Macro( "__cplusplus", "1" ) );
    }

private:
    Catalog* catalog;
#if 0 /// \FIXME
    QStringList m_docDirectoryList;
#endif
};


class PCSListViewItem: public KListViewItem
{
public:
    PCSListViewItem( KService::Ptr ptr, KDevPCSImporter* importer, QListViewItem* parent )
	: KListViewItem( parent ), m_importer( importer ) { init( ptr ); }
    PCSListViewItem( KService::Ptr ptr, KDevPCSImporter* importer, QListView* parent )
	: KListViewItem( 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;
};

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

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

    for( KTrader::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(), QStringList(), &error );
	if( importer ){
	    new PCSListViewItem( ptr, importer, importerListView );
	}
    }

    setNextEnabled( page, false );

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

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

CreatePCSDialog::~CreatePCSDialog()
{
}

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

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

void CreatePCSDialog::reject()
{
    QWizard::reject();
}

void CreatePCSDialog::accept()
{
    QWizard::accept();
}

void CreatePCSDialog::slotSelected( const QString & )
{
    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, SIGNAL(enabled(int)), this, SLOT(setNextPageEnabled(int)) );

	if( m_settings )
        setHelpEnabled( m_settings, false );
	    m_settings->show();
    } else if( currentPage() == finalPage ) {
	setBackEnabled( currentPage(), false );
	setNextEnabled( currentPage(), false );

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

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

	QString dbName = dirs->saveLocation( "data", "kdevcppsupport/pcs" ) + "/" + importer->dbName() + ".db";
	kdDebug(9007) << "================================> dbName = " << dbName << endl;

	m_part->removeCatalog( dbName );

	Catalog* c = new Catalog();
	c->open( dbName );
	c->addIndex( "kind" );
	c->addIndex( "name" );
	c->addIndex( "scope" );
	c->addIndex( "fileName" );

	RppDriver driver( c );
	for( QStringList::Iterator it=fileList.begin(); it!=fileList.end(); ++it )
	{
	    //kdDebug(9007) << "==========> parsing: " << *it << endl;
	    progressBar->setProgress( ++n );
	    currentFile->setText( *it );
	    driver.parseFile( *it );
	    kapp->processEvents();
	}

	currentFile->setText( "" );
	m_part->addCatalog( c );

	setFinishEnabled( currentPage(), true );
    }
}

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

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