/*********************************************************************************
* C++ Implementation: kbearremotedirlister.cpp
* Description:
*                              
 Begin : ons feb 26 2003
** Author : Björn Sahlström <kbjorn@users.sourceforge.net> (C) 2003
* Copyright : See COPYING file that comes with this distribution
**********************************************************************************/

//////////////////////////////////////////////////////////////////////
// Qt specific include files
#include <qdir.h>
//////////////////////////////////////////////////////////////////////
// KDE specific include files
#include <kdirlister.h>
#include <kio/job.h>
#include <kio/global.h>
#include <kglobal.h>
#include <kfileitem.h>
#include <klargefile.h>
#include <kdebug.h>
//////////////////////////////////////////////////////////////////////
// System specific include files
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
//////////////////////////////////////////////////////////////////////
// Application specific include files
#include "kbearremotedirlister.h"
#include "kbeardeletejob.h"
#include "kbearlistjob.h"
#include "connectionmanager.h"
#include "kbearmainwiniface.h"

#include "kbearremotedirlister.moc"

using namespace KBear;
//-----------------------------------------------
KBearRemoteDirLister::KBearRemoteDirLister( QWidget* parent )
	:	KBearDirListerIface( parent ), m_showingDotFiles( false ),
	m_useFilter( false ), m_state( DISCONNECTED )
{
/* we take this from the jobs instead
	connect( ConnectionManager::getInstance(), SIGNAL( infoMessage( int, const QString& ) ),
						this, SLOT( slotInfoMessage( int, const QString& ) ) );
*/
	connect( ConnectionManager::getInstance(), SIGNAL( error( int, int, const QString& ) ),
						this, SLOT( slotError( int, int, const QString& ) ) );
	connect( ConnectionManager::getInstance(), SIGNAL( connected( int ) ), this, SLOT( slotConnected( int) ) );
	connect( ConnectionManager::getInstance(), SIGNAL( notConnected( int ) ), this, SLOT( slotNotConnected( int) ) );

}
//-----------------------------------------------
KBearRemoteDirLister::~KBearRemoteDirLister() {
	closeConnection();
}
//-----------------------------------------------
void KBearRemoteDirLister::closeConnection() {
	ConnectionManager::getInstance()->closeConnection( m_siteInfo.ID() );
}
//-----------------------------------------------
void KBearRemoteDirLister::openConnection() {
	m_state = ( m_state & ~DISCONNECTED ) & CONNECTING;
	if( ! ConnectionManager::getInstance()->openConnection( m_siteInfo.ID() ) ) {
		kdDebug()<<"KBearRemoteDirLister::openConnection() could not open connection"<<endl;
		return;
	}
}
//-----------------------------------------------
void KBearRemoteDirLister::slotConnected(int ID ) {
	if( ID != m_siteInfo.ID() )
		return;
	m_state = ( m_state & ~CONNECTING ) & CONNECTED;
	emit connected(); // tell the outside world that we're connected
}
//-----------------------------------------------
void KBearRemoteDirLister::slotNotConnected(int ID ) {
	if( ID != m_siteInfo.ID() )
		return;
	m_state = DISCONNECTED;
}
//-----------------------------------------------
void KBearRemoteDirLister::openURL( const KURL& url, bool /*reload*/ ) {
	m_url = url;
	m_state |= LISTING;
	KBearListJob* job = KBearListJob::listDir( m_siteInfo.ID(), url, false, m_showingDotFiles );
	job->setAutoErrorHandlingEnabled( true, (QWidget*)parent() );
	ConnectionManager::getInstance()->attachJob( m_siteInfo.ID(), job );
	m_currentJob = job;
	connect( job, SIGNAL( infoMessage( const QString& ) ), this, SLOT( slotInfoMessage( const QString& ) ) );
	connect( job, SIGNAL( entries( KIO::Job*, const KIO::UDSEntryList & ) ), this, SLOT( slotEntries( KIO::Job*, const KIO::UDSEntryList & ) ) );
	connect( job, SIGNAL( percent( KIO::Job*, unsigned long ) ), this, SLOT( slotPercent( KIO::Job*, unsigned long ) ) );
	connect( job, SIGNAL( speed( KIO::Job*, unsigned long ) ), this, SLOT( slotSpeed( KIO::Job*, unsigned long ) ) );
	connect( job, SIGNAL( result( KIO::Job* ) ), this, SIGNAL( finishedLoading() ) );
	connect( job, SIGNAL( result( KIO::Job* ) ), this, SLOT( slotResult( KIO::Job* ) ) );
	emit clear();
	emit started();
}
//-----------------------------------------------
void KBearRemoteDirLister::getMimetype( const KURL& url ) {
	if( ! url.isValid() )
		return;
	m_state |= GETTING_MIME;
	m_statURL = url;
	m_lastMimeType = QString::null;
	KIO::TransferJob* job = KIO::get( url, false, false );
	job->setAutoErrorHandlingEnabled( true, (QWidget*)parent() );
	ConnectionManager::getInstance()->attachJob( m_siteInfo.ID(), job );
	if( job ) {
		m_currentJob = job;
		connect( job, SIGNAL( infoMessage( const QString& ) ), this, SLOT( slotInfoMessage( const QString& ) ) );
		connect( job, SIGNAL( result( KIO::Job* ) ), this, SLOT( slotResult( KIO::Job* ) ) );
		connect( job, SIGNAL( mimetype( KIO::Job*, const QString& ) ), this, SLOT( slotMimetype( KIO::Job*, const QString& ) ) );
		connect( job, SIGNAL( permanentRedirection( KIO::Job*, const KURL& , const KURL& ) ), this, SLOT( slotStatRedirection( KIO::Job*, const KURL&, const KURL&  ) ) );
		emit started();
	}
}
//-----------------------------------------------
void KBearRemoteDirLister::statURL( const KURL& url, bool /*statingLink*/ ) {
	m_state |= STATING;
	m_statURL = url;
	m_lastMimeType = QString::null;
	KIO::StatJob* job = KIO::stat( url, false );
	job->setAutoErrorHandlingEnabled( true, (QWidget*)parent() );
	ConnectionManager::getInstance()->attachJob( m_siteInfo.ID(), job );
	if( job ) {
		m_currentJob = job;
		connect( job, SIGNAL( infoMessage( const QString& ) ), this, SLOT( slotInfoMessage( const QString& ) ) );
		connect( job, SIGNAL( result( KIO::Job* ) ), this, SIGNAL( finishedLoading() ) );
		connect( job, SIGNAL( result( KIO::Job* ) ), this, SLOT( slotResult( KIO::Job* ) ) );
		connect( job, SIGNAL( permanentRedirection( KIO::Job*, const KURL& , const KURL& ) ), this, SLOT( slotStatRedirection( KIO::Job*, const KURL&, const KURL&  ) ) );
		emit started();
	}
}
//-----------------------------------------------
void KBearRemoteDirLister::slotMimetype( KIO::Job* job, const QString& mime ) {
	m_state = m_state & ~GETTING_MIME;
	KFileItem fileItem( m_statURL, mime, KFileItem::Unknown );
	if( job && fileItem.isFile() ) {
		static_cast<KIO::SimpleJob*>( job )->putOnHold();
		m_lastMimeType = mime;
		emit openFile( fileItem.url() );
	}
}
//-----------------------------------------------
void KBearRemoteDirLister::stop() {
	if( m_currentJob ) {
		m_currentJob->kill();
	}
	emit finishedLoading();
}
//-----------------------------------------------
void KBearRemoteDirLister::mkdir( const KURL& url ) {
	m_state |= MAKING_DIR;
	KIO::SimpleJob* job = KIO::mkdir( url );
	job->setAutoErrorHandlingEnabled( true, (QWidget*)parent() );
	connect( job, SIGNAL( infoMessage( const QString& ) ), this, SLOT( slotInfoMessage( const QString& ) ) );
	connect( job, SIGNAL( result( KIO::Job* ) ), this, SLOT( slotResult( KIO::Job* ) ) );
	ConnectionManager::getInstance()->attachJob( m_siteInfo.ID(), job );
	emit started();
}
//-----------------------------------------------
void KBearRemoteDirLister::deleteFiles( const KURL::List urls,  bool,  bool showProgress ) {
	m_state |= DELETING;
	KBearDeleteJob* job =  KBearDeleteJob::del( urls, false, showProgress );
	job->setAutoErrorHandlingEnabled( true, (QWidget*)parent() );
	connect( job, SIGNAL( infoMessage( const QString& ) ), this, SLOT( slotInfoMessage( const QString& ) ) );
	connect( job, SIGNAL( result( KIO::Job* ) ), this, SLOT( slotResult( KIO::Job* ) ) );
	job->start( m_siteInfo.ID() );
}
//-----------------------------------------------
void KBearRemoteDirLister::setNameFilter(const QString& nameFilter) {
	m_useFilter = ( nameFilter != "*" && nameFilter != "");

	if( ! m_useFilter )
		return;
	m_filterList.clear();
	// Split on white space
	QStringList list = QStringList::split( ' ', nameFilter );
	for( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
		m_filterList.append( new QRegExp(*it, true, true ) );
}
//-----------------------------------------------
void KBearRemoteDirLister::setShowingDotFiles( bool show ) {
	m_showingDotFiles = show;
}
//-----------------------------------------------
bool KBearRemoteDirLister::showingDotFiles() const {
	return m_showingDotFiles;
}
//-----------------------------------------------
bool KBearRemoteDirLister::matchesNameFilter( const QString& name ) const {
	for( QPtrListIterator<QRegExp> it( m_filterList ); it.current(); ++it )	{
		if ( it.current()->exactMatch( name )/* != -1*/ )
			return true;
	}

	return false;
}
//-----------------------------------------------
void KBearRemoteDirLister::slotResult( KIO::Job*job ) {
	if( ! job )
		return;
	int err = job->error();
	if( err ) {
		emit error( err, job->errorString() );
	}

//	unsigned int oldState = m_state;
	if( m_state & LISTING ) {
		m_state = m_state & ~LISTING;
	}
	else if( m_state & STATING ) {
		m_state = m_state & ~STATING;
		const KIO::UDSEntry entry = static_cast<KIO::StatJob*>( job )->statResult();
		if( ! err ) {
			if( entry.isEmpty() ) {
				return;
			}
			KFileItem* fileItem = new KFileItem( entry, m_statURL );
			m_lastMimeType = fileItem->mimetype();
			if( fileItem->isDir() ) {
				emit openDir( fileItem->url() );
			}
			else if( fileItem->isFile() ) {
				emit openFile( fileItem->url() );
			}
			delete fileItem;
			m_statURL = KURL();
		}
	}
	else if( m_state & DELETING ) {
		m_state = m_state & ~DELETING;
		if( ! err ) {
			openURL( m_url );
		}
	}
	else if( m_state & GETTING_MIME ) {
		m_state = m_state & ~GETTING_MIME;
	}
	else if( m_state & RENAMING ) {
		m_state = m_state & ~RENAMING;
		emit finishedLoading();
	}
	else if( m_state & MAKING_DIR ) {
		m_state = m_state & ~MAKING_DIR;
		emit finishedLoading();
		openURL( m_url );
	}
}
//-----------------------------------------------
void KBearRemoteDirLister::slotEntries( KIO::Job* job, const KIO::UDSEntryList& entryList ) {
/*
	if( job != m_listJob )
		return;
*/
	static const QString& dot = KGlobal::staticQString(".");
	static const QString& dotdot = KGlobal::staticQString("..");

	KURL url = static_cast<KIO::ListJob*>(job)->url();
	url.adjustPath(-1);

	KIO::UDSEntryListConstIterator it = entryList.begin();
	KIO::UDSEntryListConstIterator end = entryList.end();
	KFileItemList fileItems;

	for( ; it != end; ++it ) {
		QString name;

		// find out about the name
		KIO::UDSEntry::ConstIterator entit = (*it).begin();
		for( ; entit != (*it).end(); ++entit ) {
			 if( (*entit).m_uds == KIO::UDS_NAME ) {
				name = (*entit).m_str;
				break;
			}
		}
		Q_ASSERT( !name.isEmpty() );
		if( name.isEmpty() )
			continue;
		if( name != dot && name != dotdot ) {
			KFileItem* item = new KFileItem( *it, url, true, true );
			Q_ASSERT( item );
			if( name.left(1) == "." && ! m_showingDotFiles )
				emit deleteItem( item );
			else if( ! m_useFilter || matchesNameFilter( name ) )
				fileItems.append( item );
		}
	}
	emit newItems( fileItems );
}
//-----------------------------------------------
void KBearRemoteDirLister::slotPercent( KIO::Job*, unsigned long pcnt ) {
	emit progress( static_cast<int>(pcnt) );
}
//-----------------------------------------------
void KBearRemoteDirLister::slotSpeed( KIO::Job*, unsigned long s ) {
	emit speed( static_cast<int>(s) );
}
//-----------------------------------------------
void KBearRemoteDirLister::slotInfoMessage( const QString& message ) {
	static const QString& respString = KGlobal::staticQString( "resp" );
	static const QString& commandString = KGlobal::staticQString( "command" );
	static const QString& multiString = KGlobal::staticQString( "multi-line" );
	static const QString& internalString = KGlobal::staticQString( "internal" );
	// Only emit for non log messages
	if(  message.left( respString.length() ) != respString
		&&message.left( commandString.length() ) !=commandString
		&& message.left( multiString.length() ) != multiString
		&& message.left( internalString.length() ) != internalString )
	{
		emit infoMessage( message );
	}
}
//-----------------------------------------------
void KBearRemoteDirLister::slotError( int ID, int err, const QString& errMsg ) {
	if( ID != m_siteInfo.ID() )
		return;

	if( m_state & DISCONNECTED ) {
		emit error( err, errMsg );
	}
}
//-----------------------------------------------
void KBearRemoteDirLister::slotRename( const KURL& oldURL, const KURL& newURL ) {
	m_state |= RENAMING;
	KIO::SimpleJob* job = KIO::rename( oldURL, newURL, false );
	job->setAutoErrorHandlingEnabled( true, (QWidget*)parent() );
	connect( job, SIGNAL( infoMessage( const QString& ) ), this, SLOT( slotInfoMessage( const QString& ) ) );
	connect( job, SIGNAL( result( KIO::Job* ) ), this, SLOT( slotResult( KIO::Job* ) ) );
	ConnectionManager::getInstance()->attachJob( m_siteInfo.ID(), job );
	emit started();
}
//-----------------------------------------------

