/*
 * filelistview.cc
 *
 * Copyright (c) 2002, 2003 Frerich Raabe <raabe@kde.org>
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. For licensing and distribution details, check the
 * accompanying file 'COPYING'.
 */
#include "filelistview.h"
#include "portmgr.h"

#include <kdebug.h>
#include <klocale.h>
#include <kmdcodec.h>
#include <kopenwith.h>
#include <kpropertiesdialog.h>

#include <qfile.h>
#include <qpopupmenu.h>

using namespace Barry;

FileList::FileList( QWidget *parent ): KListView( parent, "FileList" ),
	m_checkTimer( 0 ),
	m_curItem( 0 )
{
	setRootIsDecorated( true );
	setAllColumnsShowFocus( true );
	setShowSortIndicator( true );
	addColumn( i18n( "Filename" ) );

	connect( this, SIGNAL( contextMenu( KListView *, QListViewItem *, const QPoint & ) ),
	         this, SLOT( showContextMenu( KListView *, QListViewItem *, const QPoint & ) ) );
}

FileList::~FileList()
{
	delete m_checkTimer;
}

void FileList::setFileList( const Port &port )
{
	if ( m_port == port )
		return;

	m_port = port;

	delete m_checkTimer; // Maybe we were busy checking the file statuses...
	m_checkTimer = 0;
	clear();
	if ( columns() == 2 )
		removeColumn( 1 );

	QStringList files = port.installed() ? port.installedFiles() : port.files();
	QStringList::ConstIterator it = files.begin();
	QStringList::ConstIterator end = files.end();
	for ( ; it != end; ++it )
		new KListViewItem( this, *it );

	if ( !files.empty() && port.installed() )
		startFileCheck();
}

void FileList::showContextMenu( KListView *, QListViewItem *item, const QPoint &p )
{
	const bool fileExists = QFile::exists( item->text( 0 ) );
	QPopupMenu *menu = new QPopupMenu( this );
	int i = menu->insertItem( i18n( "Properties..." ), this, SLOT( showProperties() ) );
	menu->setItemEnabled( i, fileExists );
	i = menu->insertItem( i18n( "View file" ), this, SLOT( openFile() ) );
	menu->setItemEnabled( i, fileExists );

	menu->exec( p );
}

void FileList::showProperties()
{
	new KPropertiesDialog( KURL( selectedItem()->text( 0 ) ) );
}

void FileList::openFile()
{
	KMimeType::Ptr mime = KMimeType::findByURL( selectedItem()->text( 0 ), 0, true );

	KURL fileURL = KURL( selectedItem()->text( 0 ) );

	/* application shouldn't get passed to KRun since that will execute the
	 * respective file. Instead, we open a "Open with" dialog to let the user
	 * decide (most likely, an editor will be chosen). */
	if ( mime->name().startsWith( QString::fromLatin1( "application/" ) ) ) {
		KFileOpenWithHandler *openWithHandler = new KFileOpenWithHandler;
		openWithHandler->displayOpenWithDialog( fileURL );
	} else {
		new KRun( fileURL );
	}
}

void FileList::startFileCheck()
{
	addColumn( i18n( "Status" ) );

	readFileChecksums();

	m_curItem = firstChild();

	m_checkTimer = new QTimer( this );
	connect( m_checkTimer, SIGNAL( timeout() ), this, SLOT( checkFile() ) );
	m_checkTimer->start( 0 );
}

void FileList::checkFile()
{
	if ( !m_curItem ) {
		delete m_checkTimer;
		m_checkTimer = 0;
		return;
	}

	if ( QFile::exists( m_curItem->text( 0 ) ) ) {
		QFile f( m_curItem->text( 0 ) );
		if ( !f.open( IO_ReadOnly ) ) {
			kdWarning() << "Could not open " << m_curItem->text( 0 ) << " for reading." << endl;
			m_curItem->setText( 1, i18n( "Unknown" ) );
		} else {
			KMD5 md5( f.readAll() );
			if ( m_checksumMap[ m_curItem->text( 0 ) ] != md5.hexDigest() ) {
				m_curItem->setText( 1, i18n( "Checksum mismatch!" ) );
			} else {
				m_curItem->setText( 1, i18n( "OK" ) );
			}
		}
	} else {
		m_curItem->setText( 1, i18n( "Missing" ) );
	}

	m_curItem = m_curItem->nextSibling();
}

/* Maybe the code in here, at least the part which filters out the filenames
 * from the +CONTENTS file, should get moved into "Port::installedFiles()".
 * I'm not going to do that until there aren't at least two usages of that
 * code.
 */
void FileList::readFileChecksums()
{
	const QString pkgName = QString::fromLatin1( "%1-%2" )
	                        .arg( m_port.name() )
	                        .arg( m_port.installedVersion() );

	const QString contentsFileName = PortMgr::self().pkgRootDir() + QString::fromLatin1( "/" ) +
	                                 pkgName + QString::fromLatin1( "/+CONTENTS" );

	QFile contentsFile( contentsFileName );
	if ( !contentsFile.open( IO_ReadOnly ) ) {
		kdWarning() << "Could not open " << contentsFileName << endl;
		return;
	}

	QTextStream stream( &contentsFile );
	while ( !stream.atEnd() ) {
		QString line = stream.readLine();
		if ( line[ 0 ] == '@' || line[ 0 ] == '+' )
			continue;
		QString filename = m_port.prefix() + QString::fromLatin1( "/" ) + line;
		if ( stream.atEnd() ) {
			kdWarning() << "Unexpected end of " << contentsFileName << endl;
			return;
		}
		line = stream.readLine();
		if ( !line.startsWith( QString::fromLatin1( "@comment MD5:" ) ) ) {
			kdWarning() << "Expected MD5 sum, got " << line << endl;
			return;
		}
		QString md5 = line.mid( 13 );
		m_checksumMap[ filename ] = md5;
	}
}

#include "filelistview.moc"
// vim:ts=4:sw=4:noet:list
