/***************************************************************************
 *   Copyright (C) 1999 by Jonas Nordin                                    *
 *   jonas.nordin@syncom.se                                                *
 *   Copyright (C) 2000-2001 by Bernd Gehrmann                             *
 *   bernd@kdevelop.org                                                    *
 *   Copyright (C) 2002-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 "javasupportpart.h"
#include "javasupport_events.h"
#include "problemreporter.h"
#include "backgroundparser.h"
#include "KDevJavaSupportIface.h"
#include "javasupportfactory.h"
#include "catalog.h"
#include "kdevdriver.h"
#include "javasupport_utils.h"

#include "JavaStoreWalker.h"
#include "JavaAST.h"

#include <tqheader.h>
#include <tqdir.h>
#include <tqdom.h>
#include <tqfileinfo.h>
#include <tqguardedptr.h>
#include <tqpopupmenu.h>
#include <tqprogressdialog.h>
#include <tqstringlist.h>
#include <tqtimer.h>
#include <tqstatusbar.h>
#include <tqprogressbar.h>
#include <tqregexp.h>
#include <tqlabel.h>
#include <tqvbox.h>
#include <tdemessagebox.h>
#include <tdeaction.h>
#include <tdeapplication.h>
#include <kdebug.h>
#include <kdialogbase.h>
#include <kgenericfactory.h>
#include <tdelocale.h>
#include <tdemainwindow.h>
#include <kstatusbar.h>
#include <tdeconfig.h>
#include <tdestandarddirs.h>
#include <kiconloader.h>

#include <tdetexteditor/document.h>
#include <tdetexteditor/editinterface.h>
#include <tdetexteditor/view.h>
#include <tdetexteditor/selectioninterface.h>
#include <tdetexteditor/viewcursorinterface.h>
#include <tdetexteditor/clipboardinterface.h>

#include <tdetexteditor/texthintinterface.h>

#include <kdevcore.h>
#include <kdevproject.h>
#include <kdevmainwindow.h>
#include <kdevpartcontroller.h>
#include <kdevmakefrontend.h>
#include <kdevcoderepository.h>

#include <domutil.h>
#include <urlutil.h>
#include <config.h>

enum { KDEV_DB_VERSION = 7 };
enum { KDEV_PCS_VERSION = 8 };

class JavaDriver: public KDevDriver
{
public:
    JavaDriver( JavaSupportPart* javaSupport )
	: KDevDriver( javaSupport )
    {
    }

    void fileParsed( const TQString& fileName )
    {
	//kdDebug(9013) << "-----> file " << fileName << " parsed!" << endl;
	RefJavaAST ast = takeTranslationUnit( fileName );

        if( javaSupport()->problemReporter() ){
	    javaSupport()->problemReporter()->removeAllProblems( fileName );

	    TQValueList<Problem> pl = problems( fileName );
	    TQValueList<Problem>::ConstIterator it = pl.begin();
	    while( it != pl.end() ){
	        const Problem& p = *it++;
	        javaSupport()->problemReporter()->reportProblem( fileName, p );
	    }
	}

	if( javaSupport()->codeModel()->hasFile(fileName) ){
	    FileDom file = javaSupport()->codeModel()->fileByName( fileName );
	    javaSupport()->removeWithReferences( fileName );
	}

	FileDom file = javaSupport()->codeModel()->create<FileModel>();
	file->setName( fileName );
	JavaStoreWalker walker;
	walker.setFile( file );
	walker.setCodeModel( javaSupport()->codeModel() );
	walker.compilationUnit( ast );
	javaSupport()->codeModel()->addFile( file );

	remove( fileName );
    }
};

JavaSupportPart::JavaSupportPart(TQObject *parent, const char *name, const TQStringList &/*args*/)
    : KDevLanguageSupport(JavaSupportFactory::info(), parent, name ? name : "KDevJavaSupport"),
      m_activeDocument( 0 ), m_activeView( 0 ), m_activeSelection( 0 ), m_activeEditor( 0 ),
      m_activeViewCursor( 0 ), m_projectClosed( true ), m_valid( false )
{
    setInstance(JavaSupportFactory::instance());

    m_driver = new JavaDriver( this );

    setXMLFile( "kdevjavasupport.rc" );

    m_catalogList.setAutoDelete( true );
    setupCatalog();

    m_backgroundParser = new BackgroundParser( this, &m_eventConsumed );
    m_backgroundParser->start();

    connect( core(), TQ_SIGNAL(projectOpened()), this, TQ_SLOT(projectOpened()) );
    connect( core(), TQ_SIGNAL(projectClosed()), this, TQ_SLOT(projectClosed()) );
    connect( partController(), TQ_SIGNAL(savedFile(const KURL&)),
             this, TQ_SLOT(savedFile(const KURL&)) );
    connect( core(), TQ_SIGNAL(contextMenu(TQPopupMenu *, const Context *)),
             this, TQ_SLOT(contextMenu(TQPopupMenu *, const Context *)) );
    connect( partController(), TQ_SIGNAL(activePartChanged(KParts::Part*)),
             this, TQ_SLOT(activePartChanged(KParts::Part*)));
    connect( partController(), TQ_SIGNAL(partRemoved(KParts::Part*)),
             this, TQ_SLOT(partRemoved(KParts::Part*)));

    m_problemReporter = new ProblemReporter( this, 0, "problemReporterWidget" );
    m_problemReporter->setIcon( SmallIcon("application-vnd.tde.info") );
    mainWindow( )->embedOutputView( m_problemReporter, i18n("Problems"), i18n("Problem reporter"));

    connect( core(), TQ_SIGNAL(configWidget(KDialogBase*)),
             m_problemReporter, TQ_SLOT(configWidget(KDialogBase*)) );
    connect( core(), TQ_SIGNAL(configWidget(KDialogBase*)),
             this, TQ_SLOT(configWidget(KDialogBase*)) );

    TDEAction *action;

    action = new TDEAction(i18n("New Class..."), "classnew", 0,
                         this, TQ_SLOT(slotNewClass()),
                         actionCollection(), "project_newclass");
    action->setToolTip( i18n("Generate a new class") );
    action->setWhatsThis( i18n("<b>New Class</b>Generates a new class.<p>") );

    // daniel
    connect( core( ), TQ_SIGNAL( projectConfigWidget( KDialogBase* ) ), this,
             TQ_SLOT( projectConfigWidget( KDialogBase* ) ) );

    new KDevJavaSupportIface( this );
    //(void) dcopClient();
}


JavaSupportPart::~JavaSupportPart()
{
    delete( m_driver );
    m_driver = 0;

    if( m_backgroundParser ){
	m_backgroundParser->close();
	m_backgroundParser->wait();
	delete m_backgroundParser;
	m_backgroundParser = 0;
    }

    codeRepository()->setMainCatalog( 0 );

    TQPtrListIterator<Catalog> it( m_catalogList );
    while( Catalog* catalog = it.current() ){
        ++it;
        codeRepository()->unregisterCatalog( catalog );
    }

    mainWindow( )->removeView( m_problemReporter );

    delete m_problemReporter;
    m_problemReporter = 0;
}

void JavaSupportPart::customEvent( TQCustomEvent* ev )
{
    //kdDebug(9013) << "JavaSupportPart::customEvent()" << endl;

    if( ev->type() == int(Event_FileParsed) ){
	FileParsedEvent* event = (FileParsedEvent*) ev;
	TQString fileName = event->fileName();

        if( m_problemReporter ){
	    m_problemReporter->removeAllProblems( fileName );

	    bool hasErrors = false;
	    TQValueList<Problem> problems = event->problems();
	    TQValueList<Problem>::ConstIterator it = problems.begin();
	    while( it != problems.end() ){
	        const Problem& p = *it++;
		if( p.level() == Problem::Level_Error )
		    hasErrors = true;

	        m_problemReporter->reportProblem( fileName, p );
	    }

	    m_backgroundParser->lock();
	    if( RefJavaAST ast = m_backgroundParser->translationUnit(fileName) ){

		if( !hasErrors ){
		    if( codeModel()->hasFile(fileName) ){
			FileDom file = codeModel()->fileByName( fileName );
			removeWithReferences( fileName );
		    }

		    FileDom file = codeModel()->create<FileModel>();
		    file->setName( fileName );
		    JavaStoreWalker walker;
		    walker.setFile( file );
		    walker.setCodeModel( codeModel() );

		    walker.compilationUnit( ast );
		    codeModel()->addFile( file );

		    emit addedSourceInfo( fileName );
		}
	    }
	    m_backgroundParser->unlock();
	}
	emit fileParsed( fileName );
    }
}

void JavaSupportPart::projectConfigWidget( KDialogBase* /*dlg*/ )
{
}

void JavaSupportPart::configWidget(KDialogBase */*dlg*/)
{
}

void JavaSupportPart::activePartChanged(KParts::Part *part)
{
    kdDebug(9032) << "JavaSupportPart::activePartChanged()" << endl;

    bool enabled = false;

    m_activeDocument = dynamic_cast<KTextEditor::Document*>( part );
    m_activeView = part ? dynamic_cast<KTextEditor::View*>( part->widget() ) : 0;
    m_activeEditor = dynamic_cast<KTextEditor::EditInterface*>( part );
    m_activeSelection = dynamic_cast<KTextEditor::SelectionInterface*>( part );
    m_activeViewCursor = part ? dynamic_cast<KTextEditor::ViewCursorInterface*>( m_activeView ) : 0;

    m_activeFileName = TQString();

    if (m_activeDocument) {
	m_activeFileName = URLUtil::canonicalPath( m_activeDocument->url().path() );
        TQFileInfo fi( m_activeFileName );
        TQString ext = fi.extension();
        if (fileExtensions().contains(ext))
            enabled = true;
    }

    if( !part )
	return;

    if( !m_activeView )
	return;

#if 0
    KTextEditor::TextHintInterface* textHintIface = dynamic_cast<KTextEditor::TextHintInterface*>( m_activeView );
    if( !textHintIface )
	return;

    connect( view, TQ_SIGNAL(needTextHint(int,int,TQString&)),
	     this, TQ_SLOT(slotNeedTextHint(int,int,TQString&)) );

    textHintIface->enableTextHints( 1000 );
#endif
}


void JavaSupportPart::projectOpened( )
{
    kdDebug( 9013 ) << "projectOpened( )" << endl;

    m_projectDirectory = URLUtil::canonicalPath( project()->projectDirectory() );

    connect( project( ), TQ_SIGNAL( addedFilesToProject( const TQStringList & ) ),
             this, TQ_SLOT( addedFilesToProject( const TQStringList & ) ) );
    connect( project( ), TQ_SIGNAL( removedFilesFromProject( const TQStringList &) ),
             this, TQ_SLOT( removedFilesFromProject( const TQStringList & ) ) );
    connect( project( ), TQ_SIGNAL( changedFilesInProject( const TQStringList & ) ),
             this, TQ_SLOT( changedFilesInProject( const TQStringList & ) ) );
    connect( project(), TQ_SIGNAL(projectCompiled()),
	     this, TQ_SLOT(slotProjectCompiled()) );

    m_timestamp.clear();

    m_projectClosed = false;

    TQTimer::singleShot( 500, this, TQ_SLOT( initialParse( ) ) );
}


void JavaSupportPart::projectClosed( )
{
    kdDebug( 9013 ) << "projectClosed( )" << endl;

    saveProjectSourceInfo();

    if( m_backgroundParser )
	m_backgroundParser->removeAllFiles();

    m_projectClosed = true;
}

void JavaSupportPart::contextMenu(TQPopupMenu */*popup*/, const Context *context)
{
    m_activeClass = 0;
    m_activeFunction = 0;
    m_activeVariable = 0;

    if( context->hasType(Context::EditorContext) ){
        // nothing!
    } else if( context->hasType(Context::CodeModelItemContext) ){
	const CodeModelItemContext* mcontext = static_cast<const CodeModelItemContext*>( context );

	if( mcontext->item()->isClass() ){
	    m_activeClass = (ClassModel*) mcontext->item();
	} else if( mcontext->item()->isFunction() ){
	    m_activeFunction = (FunctionModel*) mcontext->item();
	}
    }
}

void JavaSupportPart::addedFilesToProject(const TQStringList &fileList)
{
    TQStringList files = fileList;

    for ( TQStringList::ConstIterator it = files.begin(); it != files.end(); ++it )
    {
	TQString path = URLUtil::canonicalPath( m_projectDirectory + "/" + (*it) );

	maybeParse( path );
	emit addedSourceInfo( path );
    }
}

void JavaSupportPart::removedFilesFromProject(const TQStringList &fileList)
{
    for ( TQStringList::ConstIterator it = fileList.begin(); it != fileList.end(); ++it )
    {
	TQString path = URLUtil::canonicalPath( m_projectDirectory + "/" + *it );

	removeWithReferences( path );
	m_backgroundParser->removeFile( path );
    }
}

void JavaSupportPart::changedFilesInProject( const TQStringList & fileList )
{
    TQStringList files = fileList;

    for ( TQStringList::ConstIterator it = files.begin(); it != files.end(); ++it )
    {
	TQString path = URLUtil::canonicalPath( m_projectDirectory + "/" + *it );

	maybeParse( path );
	emit addedSourceInfo( path );
    }
}

void JavaSupportPart::savedFile(const KURL &fileName)
{
    Q_UNUSED( fileName.path() );

#if 0  // not needed anymore
    kdDebug(9013) << "savedFile(): " << fileName.mid ( m_projectDirectory.length() + 1 ) << endl;

    TQStringList projectFileList = project()->allFiles();
    if (projectFileList.contains(fileName.mid ( m_projectDirectory.length() + 1 ))) {
	maybeParse( fileName );
	emit addedSourceInfo( fileName );
    }
#endif
}

TQString JavaSupportPart::findSourceFile()
{
    TQFileInfo fi( m_activeFileName );
    TQString path = fi.filePath();
    TQString ext = fi.extension();
    TQString base = path.left( path.length() - ext.length() );
    TQStringList candidates;

    if (ext == "h" || ext == "H" || ext == "hh" || ext == "hxx" || ext == "hpp" || ext == "tlh") {
        candidates << (base + "c");
        candidates << (base + "cc");
        candidates << (base + "java");
        candidates << (base + "java");
        candidates << (base + "cxx");
        candidates << (base + "C");
        candidates << (base + "m");
        candidates << (base + "mm");
        candidates << (base + "M");
	candidates << (base + "inl");
    }

    TQStringList::ConstIterator it;
    for (it = candidates.begin(); it != candidates.end(); ++it) {
        kdDebug(9013) << "Trying " << (*it) << endl;
        if (TQFileInfo(*it).exists()) {
            return *it;
        }
    }

    return m_activeFileName;
}

KDevLanguageSupport::Features JavaSupportPart::features()
{
    return Features( Classes | Functions | Variables );
}

TQString JavaSupportPart::formatClassName(const TQString &name)
{
    return name;
}

TQString JavaSupportPart::unformatClassName(const TQString &name)
{
    return name;
}

TQStringList JavaSupportPart::fileExtensions() const
{
    return TQStringList::split(",", "java");
}

void JavaSupportPart::slotNewClass()
{
}

void JavaSupportPart::addMethod( ClassDom /*klass*/ )
{
}

void JavaSupportPart::addAttribute( ClassDom /*klass*/ )
{
}

void JavaSupportPart::initialParse( )
{
    // For debugging
    if( !project( ) ){
        // messagebox ?
        kdDebug( 9013 ) << "No project" << endl;
        return;
    }

    parseProject( );
    emit updatedSourceInfo();
    m_valid = true;
    return;
}

bool
JavaSupportPart::parseProject( )
{
    //TQLabel* label = new TQLabel( "", mainWindow( )->statusBar( ) );
    //label->setMinimumWidth( 600 );
    //mainWindow( )->statusBar( )->addWidget( label );
    //label->show( );

    mainWindow()->statusBar()->message( i18n("Updating...") );

    tdeApp->processEvents( );
    tdeApp->setOverrideCursor( waitCursor );

    TQStringList files = modifiedFileList();

    TQProgressBar* bar = new TQProgressBar( files.count( ), mainWindow( )->statusBar( ) );
    bar->setMinimumWidth( 120 );
    bar->setCenterIndicator( true );
    mainWindow( )->statusBar( )->addWidget( bar );
    bar->show( );

    TQDir d( m_projectDirectory );

    TQDataStream stream;
    TQMap< TQString, TQPair<uint, uint> > pcs;

    if( TQFileInfo( project()->projectDirectory() + "/" +
			    project()->projectName().lower() + ".kdevelop.pcs" ).exists() )
    {
        d.rename(project()->projectName().lower() + ".kdevelop.pcs",
			project()->projectName() + ".kdevelop.pcs");
    }
    TQFile f(project()->projectDirectory() + "/" + project()->projectName() + ".kdevelop.pcs");
    if( f.open(IO_ReadOnly) ){
	stream.setDevice( &f );

	TQString sig;
	int pcs_version = 0;
	stream >> sig >> pcs_version;
	if( sig == "PCS" && pcs_version == KDEV_PCS_VERSION ){

	    int numFiles = 0;
	    stream >> numFiles;

	    for( int i=0; i<numFiles; ++i ){
		TQString fn;
		uint ts;
		uint offset;

		stream >> fn >> ts >> offset;
		pcs[ fn ] = qMakePair( ts, offset );
	    }
	}
    }

    int n = 0;
    for( TQStringList::Iterator it = files.begin( ); it != files.end( ); ++it ) {
        bar->setProgress( n++ );
	TQFileInfo fileInfo( d, *it );

        if( fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable() ){
            TQString absFilePath = URLUtil::canonicalPath( fileInfo.absFilePath() );
	    kdDebug(9013) << "parse file: " << absFilePath << endl;

	    if( (n%5) == 0 ){
	        tdeApp->processEvents();

		if( m_projectClosed ){
		    delete( bar );
		    return false;
		}
	    }

	    if( isValidSource(absFilePath) ){
		TQDateTime t = fileInfo.lastModified();
		if( m_timestamp.contains(absFilePath) && m_timestamp[absFilePath] == t )
		    continue;

		if( pcs.contains(absFilePath) && t.toTime_t() == pcs[absFilePath].first ){
		    stream.device()->at( pcs[absFilePath].second );
		    FileDom file = codeModel()->create<FileModel>();
		    file->read( stream );
		    codeModel()->addFile( file );
		} else {
		    m_driver->parseFile( absFilePath );
		}

		m_timestamp[ absFilePath ] = t;
	    }
        }

	if( m_projectClosed ){
	    kdDebug(9013) << "ABORT" << endl;
            tdeApp->restoreOverrideCursor( );
	    return false;
	}
    }

    kdDebug( 9013 ) << "updating sourceinfo" << endl;
    emit updatedSourceInfo();

    mainWindow( )->statusBar( )->removeWidget( bar );
    delete bar;
    //mainWindow( )->statusBar( )->removeWidget( label );
    //delete label;

    tdeApp->restoreOverrideCursor( );
    mainWindow( )->statusBar( )->message( i18n( "Done" ), 2000 );

    return true;
}

void JavaSupportPart::maybeParse( const TQString& fileName )
{
    if( !isValidSource(fileName) )
        return;

    TQFileInfo fileInfo( fileName );
    TQString path = URLUtil::canonicalPath( fileName );
    TQDateTime t = fileInfo.lastModified();

    if( !fileInfo.exists() ){
	removeWithReferences( path );
	return;
    }

    TQMap<TQString, TQDateTime>::Iterator it = m_timestamp.find( path );
    if( it != m_timestamp.end() && *it == t ){
	return;
    }

    m_timestamp[ path ] = t;
    m_driver->parseFile( path );
}

void JavaSupportPart::slotNeedTextHint( int /*line*/, int /*column*/, TQString& /*textHint*/ )
{
}

TQStringList JavaSupportPart::subclassWidget(const TQString& /*formName*/)
{
    TQStringList newFileNames;
    return newFileNames;
}

TQStringList JavaSupportPart::updateWidget(const TQString& /*formName*/, const TQString& /*fileName*/)
{
    TQStringList dummy;
    return dummy;
}

void JavaSupportPart::partRemoved( KParts::Part* part )
{
    kdDebug(9032) << "JavaSupportPart::partRemoved()" << endl;

    if( KTextEditor::Document* doc = dynamic_cast<KTextEditor::Document*>( part ) ){

	TQString fileName = doc->url().path();
	if( fileName.isEmpty() )
	    return;

	TQString canonicalFileName = URLUtil::canonicalPath( fileName );
	m_backgroundParser->removeFile( canonicalFileName );
	m_backgroundParser->addFile( canonicalFileName, true );
    }
}

void JavaSupportPart::slotProjectCompiled()
{
    kdDebug(9013) << "JavaSupportPart::slotProjectCompiled()" << endl;
    parseProject();
}

TQStringList JavaSupportPart::modifiedFileList()
{
    TQStringList lst;

    TQStringList fileList = project()->allFiles();
    TQStringList::Iterator it = fileList.begin();
    while( it != fileList.end() ){
	TQString fileName = *it;
	++it;

	TQFileInfo fileInfo( m_projectDirectory, fileName );

	if( !fileExtensions().contains(fileInfo.extension()) )
	    continue;

	TQDateTime t = fileInfo.lastModified();
	TQString path = URLUtil::canonicalPath( fileInfo.absFilePath() );
	TQMap<TQString, TQDateTime>::Iterator dictIt = m_timestamp.find( path );
	if( fileInfo.exists() && dictIt != m_timestamp.end() && *dictIt == t )
	    continue;

	lst << fileName;
    }

    return lst;
}

KTextEditor::Document * JavaSupportPart::findDocument( const KURL & url )
{
    if( !partController()->parts() )
        return 0;

    TQPtrList<KParts::Part> parts( *partController()->parts() );
    TQPtrListIterator<KParts::Part> it( parts );
    while( KParts::Part* part = it.current() ){
        KTextEditor::Document* doc = dynamic_cast<KTextEditor::Document*>( part );
	if( doc && doc->url() == url )
	    return doc;
        ++it;
    }

    return 0;
}

void JavaSupportPart::setupCatalog( )
{
    kdDebug(9013) << "JavaSupportPart::setupCatalog()" << endl;

    TQStringList indexList = TQStringList() << "kind" << "name" << "scope" << "fileName";

    TDEStandardDirs *dirs = JavaSupportFactory::instance()->dirs();
    TQStringList pcsList = dirs->findAllResources( "pcs", "*.db", false, true );
    TQStringList pcsIdxList = dirs->findAllResources( "pcs", "*.idx", false, true );

    if( pcsList.size() && pcsVersion() < KDEV_DB_VERSION ){
        TQStringList l = pcsList + pcsIdxList;
        int rtn = KMessageBox::questionYesNoList( 0, i18n("Persistent class store will be disabled: you have a wrong version of pcs installed.\nRemove old pcs files?"), l, i18n("Java Support"), KStdGuiItem::remove(), i18n("Keep Them") );
        if( rtn == KMessageBox::Yes ){
            TQStringList::Iterator it = l.begin();
            while( it != l.end() ){
                TQFile::remove( *it );
                ++it;
            }
            // @todo regenerate the pcs list
            pcsList.clear();
        } else {
            return;
        }
    }

    TQStringList::Iterator it = pcsList.begin();
    while( it != pcsList.end() ){
        Catalog* catalog = new Catalog();
        catalog->open( *it );
        ++it;

        for( TQStringList::Iterator idxIt=indexList.begin(); idxIt!=indexList.end(); ++idxIt )
            catalog->addIndex( (*idxIt).utf8() );

        m_catalogList.append( catalog );
        codeRepository()->registerCatalog( catalog );
    }

    setPcsVersion( KDEV_DB_VERSION );
}

KMimeType::List JavaSupportPart::mimeTypes( )
{
    KMimeType::List list;
    KMimeType::Ptr mime;

    mime = KMimeType::mimeType( "text/x-java" );
    if( mime )
	list << mime;

    return list;
}

int JavaSupportPart::pcsVersion()
{
    TDEConfig* config = JavaSupportFactory::instance()->config();
    TDEConfigGroupSaver cgs( config, "PCS" );
    return config->readNumEntry( "Version", 0 );
}

void JavaSupportPart::setPcsVersion( int version )
{
    TDEConfig* config = JavaSupportFactory::instance()->config();
    TDEConfigGroupSaver cgs( config, "PCS" );
    config->writeEntry( "Version", version );
    config->sync();
}

TQString JavaSupportPart::formatTag( const Tag & /*inputTag*/ )
{
    return TQString();
}

void JavaSupportPart::removeWithReferences( const TQString & fileName )
{
    kdDebug(9013) << "remove with references: " << fileName << endl;
    m_timestamp.remove( fileName );
    if( !codeModel()->hasFile(fileName) )
        return;

    emit aboutToRemoveSourceInfo( fileName );

    codeModel()->removeFile( codeModel()->fileByName(fileName) );
}

bool JavaSupportPart::isValidSource( const TQString& fileName ) const
{
    TQFileInfo fileInfo( fileName );
    return fileExtensions().contains( fileInfo.extension() ) && !TQFile::exists(fileInfo.dirPath(true) + "/.tdev_ignore");
}

TQString JavaSupportPart::formatModelItem( const CodeModelItem *item, bool shortDescription )
{
    if (item->isFunction())
    {
        const FunctionModel *model = static_cast<const FunctionModel*>(item);
        TQString function;
        TQString args;
        ArgumentList argumentList = model->argumentList();
        for (ArgumentList::const_iterator it = argumentList.begin(); it != argumentList.end(); ++it)
        {
            args.isEmpty() ? args += "" : args += ", " ;
            args += formatModelItem((*it).data());
        }
	if( !shortDescription )
            function += model->resultType() + " ";

	function += model->name() + "(" + args + ")" +
            (model->isAbstract() ? TQString(" = 0") : TQString("") );

        return function;
    }
    else if (item->isVariable())
    {
        const VariableModel *model = static_cast<const VariableModel*>(item);
	if( shortDescription )
	    return model->name();
        return model->type() + " " + model->name();
    }
    else if (item->isArgument())
    {
        const ArgumentModel *model = static_cast<const ArgumentModel*>(item);
	TQString arg;
	if( !shortDescription )
	    arg += model->type() + " ";
	arg += model->name();
	if( !shortDescription )
	    arg += model->defaultValue().isEmpty() ? TQString("") : TQString(" = ") + model->defaultValue();
	return arg.stripWhiteSpace();
    }
    else
        return KDevLanguageSupport::formatModelItem( item, shortDescription );
}

void JavaSupportPart::addClass( )
{
    slotNewClass();
}

void JavaSupportPart::saveProjectSourceInfo( )
{
    const FileList fileList = codeModel()->fileList();

    if( !project() || fileList.isEmpty() )
	return;

    TQFile f( project()->projectDirectory() + "/" +
		    project()->projectName() + ".kdevelop.pcs" );
    if( !f.open( IO_WriteOnly ) )
	return;

    TQDataStream stream( &f );
    TQMap<TQString, uint> offsets;

    TQString pcs( "PCS" );
    stream << pcs << KDEV_PCS_VERSION;

    stream << int( fileList.size() );
    for( FileList::ConstIterator it=fileList.begin(); it!=fileList.end(); ++it ){
	const FileDom dom = (*it);
  stream << dom->name() << m_timestamp[ dom->name() ].toTime_t();
	offsets.insert( dom->name(), stream.device()->at() );
	stream << (uint)0; // dummy offset
    }

    for( FileList::ConstIterator it=fileList.begin(); it!=fileList.end(); ++it ){
	const FileDom dom = (*it);
	int offset = stream.device()->at();

	dom->write( stream );

	int end = stream.device()->at();

	stream.device()->at( offsets[dom->name()] );
	stream << offset;
	stream.device()->at( end );
    }
}

#include "javasupportpart.moc"
