/*********************************************************************************
* C++ Implementation: kbeartransferqueueplugin.cpp
* Description:
*
* Begin : sön feb 02 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 <qtimer.h>
#include <qfile.h>
//////////////////////////////////////////////////////////////////////
// KDE specific include files
#include <klineedit.h>
#include <klocale.h>
#include <kglobal.h>
#include <kconfig.h>
#include <kconfigbase.h>
#include <kmessagebox.h>
#include <kshortcut.h>
#include <kpopupmenu.h>
#include <kapplication.h>
#include <kmainwindow.h>
#include <kinstance.h>
#include <kgenericfactory.h>
#include <kdebug.h>
//////////////////////////////////////////////////////////////////////
// System specific include files
#include <stdlib.h>
//////////////////////////////////////////////////////////////////////
// Application specific include files
#include "kbeartransferqueueplugin.h"
#include "kbearmainwiniface.h"
#include "kbearapi.h"
#include "kbearcore.h"
#include "transfermanager.h"
#include "transferqueuewidget.h"
#include "transferqueuesession.h"


#include "kbeartransferqueueplugin.moc"

using namespace KBear;

//-----------------------------------------------
typedef KGenericFactory<KBearTransferQueuePlugin> KBearTransferQueuePluginFactory;
K_EXPORT_COMPONENT_FACTORY( kbeartransferqueue, KBearTransferQueuePluginFactory( "kbeartransferqueue" ) );
//-----------------------------------------------
// KBearTransferQueuePlugin
//-----------------------------------------------
KBearTransferQueuePlugin::KBearTransferQueuePlugin( QObject* parent, const char* , const QStringList& )
	:	KBearPlugin( parent, "KBearTransferQueuePlugin" ),
		m_queueWidget( new TransferQueueWidget( this ) ),
		m_sysShutdownWhenDone( false ),
		m_session( new TransferQueueSession( this, m_queueWidget ) ),
		m_initialized( false )
{
	KGlobal::locale()->insertCatalogue("kbear");
	setInstance( KBearTransferQueuePluginFactory::instance() );
	setXMLFile( "kbeartransferqueueplugin.rc" );

	m_startAction = new KAction( i18n("&Start transfer"),"launch", 0, this, SLOT( slotStart() ), actionCollection(), "transfer_start" );
	m_startAction->setToolTip( i18n("Start selected transfer.") );
	m_startAction->setEnabled( false );

	m_stopAction = new KAction( i18n("S&top transfer"),"stop", 0, this, SLOT( slotStop() ), actionCollection(), "transfer_stop" );
	m_stopAction->setToolTip( i18n("Stop selected transfer.") );
	m_stopAction->setEnabled( false );

	m_queueAction = new KAction( i18n("&Queue transfer"),"queue", 0, this, SLOT( slotQueue() ), actionCollection(), "transfer_queue" );
	m_queueAction->setToolTip( i18n("Queue selected transfer.") );
	m_queueAction->setEnabled( false );

	m_pauseAction = new KAction( i18n("&Pause transfer"),"player_pause", 0, this, SLOT( slotPause() ), actionCollection(), "transfer_pause" );
	m_pauseAction->setToolTip( i18n("Pause selected transfer.") );
	m_pauseAction->setEnabled( false );

	m_continueAction = new KAction( i18n("&Continue transfer"),"finish", 0, this, SLOT( slotContinue() ), actionCollection(), "transfer_continue" );
	m_continueAction->setToolTip( i18n("Continue selected transfer.") );
	m_continueAction->setEnabled( false );

	m_removeAction = new KAction( i18n("&Remove"),"remove", 0, this, SLOT( slotRemove() ), actionCollection(), "transfer_remove" );
	m_removeAction->setToolTip( i18n("Remove selected transfer.") );
	m_removeAction->setEnabled( false );

	m_removeAllAction = new KAction( i18n("Remove &All"), 0, this, SLOT( slotRemoveAll() ), actionCollection(), "transfer_remove_all" );
	m_removeAllAction->setToolTip( i18n("Remove selected transfer.") );
	m_removeAllAction->setEnabled( false );

	m_queueAllAction = new KToggleAction( i18n("Q&ueue all new transfers"), 0, this, SLOT( slotQueueAll() ), actionCollection(), "transfer_queue_all" );
	m_queueAllAction->setToolTip( i18n("Queue new transfers, if checked this will override all other queue settings.") );

	m_moveUpAction = new KAction( i18n("Move &up in queue"),"up", 0, this, SLOT( slotMoveUp() ), actionCollection(), "transfer_move_up" );
	m_moveUpAction->setToolTip( i18n("Move selected transfer up in queue.") );
	m_moveUpAction->setEnabled( false );

	m_moveDownAction = new KAction( i18n("Move do&wn in queue"),"down", 0, this, SLOT( slotMoveDown() ), actionCollection(), "transfer_move_down" );
	m_moveDownAction->setToolTip( i18n("Move selected transfer down in queue.") );
	m_moveDownAction->setEnabled( false );

	m_disconnectAction = new KToggleAction( i18n("&Disconnect when queue is empty"), QString::null, KShortcut(), actionCollection(), "transfer_disconnect" );
	m_disconnectAction->setToolTip( i18n("Disconnect when queue is empty") );
//	m_disconnectAction->setEnabled( false );
	m_shutDownActon = new KToggleAction( i18n("S&hutdown when queue is empty"), QString::null, KShortcut(), actionCollection(), "transfer_shutdown" );
	m_shutDownActon->setToolTip( i18n("Shutdown KBear when queue is empty") );
//	m_shutDownActon->setEnabled( false );

	connect( m_api->core(), SIGNAL( systemTrayMenuNeeded( KPopupMenu* ) ),
					this, SLOT( slotSystemTrayMenuNeeded( KPopupMenu* ) ) );
	connect( m_api->transferManager(), SIGNAL( transferAdded( long, Transfer* ) ),
					this, SLOT( slotTransferAdded( long, Transfer* ) ) );
	connect( m_api->transferManager(), SIGNAL( removingTransfer( long ) ),
					this, SLOT( slotRemovingTransfer( long ) ) );
/*
	connect( m_api->transferManager(), SIGNAL( removingTransferGroup( int ) ),
					this, SLOT( slotRemovingTransferGroup( int ) ) );
*/
	connect( m_api->transferManager(), SIGNAL( transferDone( long ) ),
						this, SLOT( slotTransferDone( long ) ) );

	connect( m_queueWidget, SIGNAL( contextMenu(KListView*, QListViewItem*, const QPoint& ) ),
					this, SLOT( slotContextMenu( KListView*, QListViewItem*, const QPoint& ) ) );
	connect( m_queueWidget, SIGNAL( selectionChanged() ),
					this, SLOT( slotSelectionChanged() ) );

	slotUpdateValues();
}
//-----------------------------------------------
KBearTransferQueuePlugin::~KBearTransferQueuePlugin() {
	// This will also save the session
	delete m_session;

	mainWindow()->removeOutputPluginView( m_queueWidget );
	delete m_queueWidget;
	KConfig* config = KBearTransferQueuePluginFactory::instance()->config();
	KConfigGroupSaver( config, config->group() );
	config->setGroup( QString::fromLatin1("TransferQueue" ) );
	config->writeEntry( QString::fromLatin1("ShutdownWhenDone"), m_shutDownActon->isChecked() );
	config->writeEntry( QString::fromLatin1("DisconnectWhenDone"), m_disconnectAction->isChecked() );
	config->writeEntry( QString::fromLatin1("QueueTransfers"), m_queueAllAction->isChecked() );

	m_api->transferManager()->setStartTransfersDirectly( true );
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotInit()  {
	mainWindow()->embedOutputPluginView( m_queueWidget, i18n( "Transfer Queue" ), i18n( "Display the transfer queue." ) );

	m_session->restoreSession();
	m_initialized = true;
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotTransferAdded( long ID, Transfer* transfer ) {
	kdDebug()<<"KBearTransferQueuePlugin::slotTransferAdded" << endl;

	if( m_initialized ) {
		m_session->addTransfer( transfer );
		m_queueWidget->addTransfer( transfer );
	}

	if( m_queueAllAction->isChecked() ) {
		if( m_api->transferManager()->numOfActiveTransfers() <= m_maxNumOfActiveTransfers && m_initialized) {
			m_api->transferManager()->setTransferCommand( ID, Transfer::Start );
		}
		else if( m_initialized ) {
			m_queue.append( transfer );
			m_api->transferManager()->setTransferCommand( ID, Transfer::Queue );
		}
	}

}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotTransferStatusChanged( TransferQueueItem* item, unsigned int status ) {
	m_session->updateTransfer( item->ID(), TransferQueueSession::ATT_STATUS, QString::number( status ) );

	if( status == Transfer::Queued && item->transfer() && ! m_queue.contains( item->transfer() ) )
		m_queue.append( item->transfer() );
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotProgress( TransferQueueItem* item, unsigned long progress ) {
	m_session->updateTransfer( item->ID(), TransferQueueSession::ATT_PROGRESS, QString::number( progress ) );
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotTotalSize( TransferQueueItem* item, KIO::filesize_t size ) {
	m_session->updateTransfer( item->ID(), TransferQueueSession::ATT_SIZE, QString::number( (long unsigned int)size ) );
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotTransferDone( long ) {
	if(  m_queue.count() && m_api->transferManager()->numOfActiveTransfers() < m_maxNumOfActiveTransfers ) {
		Transfer* transfer = m_queue.getFirst();
		m_queue.remove( transfer );
		m_api->transferManager()->setTransferCommand( transfer->transferID(), Transfer::Start );
	}
	if( m_queue.count() == 0 && m_initialized ) {
		if( TransferManager::getInstance()->numOfActiveTransfers() < m_maxNumOfActiveTransfers )
			slotQueueIsEmpty();
	}
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotRemovingTransfer( long ID ) {
	Transfer* transfer;
	for( transfer = m_queue.first(); transfer; transfer = m_queue.next() ) {
		if( transfer->transferID() == ID )
			m_queue.remove( transfer );
	}
//	m_session->removeTransfer( ID );
	if( m_queue.count() == 0 && m_initialized ) {
		if( TransferManager::getInstance()->numOfActiveTransfers() < m_maxNumOfActiveTransfers )
			slotQueueIsEmpty();
	}
}
//-----------------------------------------------
/*
void KBearTransferQueuePlugin::slotRemovingTransferGroup( int ID ) {
	m_session->removeTransferGroup( ID );
}
*/
//-----------------------------------------------
void KBearTransferQueuePlugin::slotSystemTrayMenuNeeded( KPopupMenu* menu )  {
	QPopupMenu* popup = ( factory() ? static_cast<QPopupMenu*>(factory()->container("shutdown_settings", this)) : 0 );
	if( menu && popup )
		menu->insertItem( i18n("Queue settings"), popup );
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotUpdateValues() {
	KConfig* config = KBearTransferQueuePluginFactory::instance()->config();
	KConfigGroupSaver( config, config->group() );
	config->setGroup( QString::fromLatin1("TransferQueue" ) );
	m_sysShutdownWhenDone = config->readBoolEntry( QString::fromLatin1("SysShutdownWhenDone"), false );
	m_disconnectCommand = config->readEntry( QString::fromLatin1("DisconnectCommand"), QString::fromLatin1("kppp -k") );
	m_shutDownActon->setChecked( config->readBoolEntry( QString::fromLatin1("ShutdownWhenDone"), false ) );
	m_disconnectAction->setChecked( config->readBoolEntry( QString::fromLatin1("DisconnectWhenDone"), false ) );
	m_queueAllAction->setChecked( config->readBoolEntry( QString::fromLatin1("QueueTransfers"), false ) );
	m_maxNumOfActiveTransfers = config->readUnsignedNumEntry( QString::fromLatin1("NumberOfTransfers"), 1 );
	slotQueueAll();
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotConfigWidget( KDialogBase* ) {
	KBearConfigWidgetIface* w = m_api->transferManager()->configWidget();
	if( ! w ) {
		QTimer::singleShot( 0, this, SLOT( slotConfigWidget( KDialogBase* ) ) );
		return;
	}
	KConfig* config = KBearTransferQueuePluginFactory::instance()->config();
	TransferQueueConfigWidget* configWidget = new TransferQueueConfigWidget( config, w, "TransferConfigWidget" );
	w->swallow( configWidget );
	connect( configWidget, SIGNAL( newSettings() ), this, SLOT( slotUpdateValues() ) );
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotConfigWidget( KWizard* ) {
	KBearConfigWidgetIface* w = m_api->transferManager()->configWidget();
	if( ! w ) {
		QTimer::singleShot( 0, this, SLOT( slotConfigWidget( KWizard* ) ) );
		return;
	}
	KConfig* config = KBearTransferQueuePluginFactory::instance()->config();
	TransferQueueConfigWidget* configWidget = new TransferQueueConfigWidget( config, w, "TransferConfigWidget" );
	w->swallow( configWidget );
	connect( configWidget, SIGNAL( newSettings() ), this, SLOT( slotUpdateValues() ) );
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotQueueIsEmpty() {
//	m_disconnectAction->setEnabled( false );
//	m_shutDownActon->setEnabled( false );
	if( m_disconnectAction->isChecked() ) {
		system( QFile::encodeName( m_disconnectCommand ) );
	}
	if( m_shutDownActon->isChecked() ) {
		if( m_sysShutdownWhenDone ) {
			kapp->requestShutDown( KApplication::ShutdownConfirmNo,
											KApplication::ShutdownTypeHalt,
											KApplication::ShutdownModeSchedule );
		}
		QTimer::singleShot( 0, m_api->core(), SLOT( requestShutDown() ) );
	}

}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotSelectionChanged() {
	 QListViewItem* item = m_queueWidget->selectedItem();
	 updateActions( item );
}
//-----------------------------------------------
void KBearTransferQueuePlugin::updateActions( QListViewItem* item ) {
	// we dsable all actions by default
	m_startAction->setEnabled( false );
	m_stopAction->setEnabled( false );
	m_queueAction->setEnabled( false );
	m_pauseAction->setEnabled( false );
	m_continueAction->setEnabled( false );
	m_removeAction->setEnabled( false );
	m_removeAllAction->setEnabled( m_queueWidget->childCount() );
	m_moveUpAction->setEnabled( false );
	m_moveDownAction->setEnabled( false );

	if( ! item ) {
		return;
	}
	TransferQueueItem* queueItem = dynamic_cast<TransferQueueItem*>( item );
	Transfer* transfer = 0L;
	if( queueItem )
		transfer = queueItem->transfer();

	unsigned int status = Transfer::Uninitialized;
	if( transfer )
		status = transfer->status();

	m_startAction->setEnabled( status & (Transfer::Queued | Transfer::Canceled ) );
	m_stopAction->setEnabled( status & ( Transfer::Started | Transfer::Queued ) );
	m_queueAction->setEnabled( status & ( Transfer::Started | Transfer::Canceled | Transfer::Paused ) );
	m_pauseAction->setEnabled( ( status == Transfer::Started ) );
	m_continueAction->setEnabled( ( status == Transfer::Paused ) );
	m_removeAction->setEnabled( ( status != Transfer::Started && status != Transfer::Paused ) );
	if( status == Transfer::Queued ) {
		m_moveUpAction->setEnabled( transfer && ( transfer != m_queue.getFirst() )  );
		m_moveDownAction->setEnabled( transfer && ( transfer != m_queue.getLast() ) );
	}
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotContextMenu( KListView*, QListViewItem* item, const QPoint& p ) {
	QPopupMenu* menu = ( factory() ? static_cast<QPopupMenu*>(factory()->container("queue_popup", this)) : 0 );
	if( menu ) {
		updateActions( item );
		menu->popup( p );
	}
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotStop() {
	if( ! m_queueWidget->selectedItem() )
		return;

	TransferQueueItem* item = static_cast<TransferQueueItem*>( m_queueWidget->selectedItem() );
	setCommand( item, Transfer::Cancel,Transfer::Started | Transfer::Paused | Transfer::Queued );
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotStart() {
	if( ! m_queueWidget->selectedItem() )
		return;

	TransferQueueItem* item = static_cast<TransferQueueItem*>( m_queueWidget->selectedItem() );
	setCommand( item, Transfer::Start, Transfer::Queued | Transfer::Canceled );
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotPause() {
	if( ! m_queueWidget->selectedItem() )
		return;

	TransferQueueItem* item = static_cast<TransferQueueItem*>( m_queueWidget->selectedItem() );
	setCommand( item, Transfer::Pause, Transfer::Started );
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotContinue() {
	if( ! m_queueWidget->selectedItem() )
		return;

	TransferQueueItem* item = static_cast<TransferQueueItem*>( m_queueWidget->selectedItem() );
	setCommand( item, Transfer::Resume, Transfer::Paused );
}
//-----------------------------------------------
bool KBearTransferQueuePlugin::setCommand(TransferQueueItem* item, const Transfer::Command& command, unsigned int statusCheck )
{
	if( item ) {
		Transfer* transfer = item->transfer();
		if( transfer ) {
			if( transfer->status() & statusCheck ) {
				m_api->transferManager()->setTransferCommand( item->ID(), command );
				return true;
			}
		}
	}
	return false;
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotQueue() {
	if( ! m_queueWidget->selectedItem() )
		return;

	TransferQueueItem* item = static_cast<TransferQueueItem*>( m_queueWidget->selectedItem() );
	setCommand( item, Transfer::Queue, Transfer::Started | Transfer::Paused | Transfer::Canceled );
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotQueueAll() {
	m_api->transferManager()->setStartTransfersDirectly( ! m_queueAllAction->isChecked() );
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotRemoveAll() {
	QListViewItemIterator it( m_queueWidget );
	QPtrList<TransferQueueItem> itemList;

	TransferQueueItem* item;
	while ( it.current() ) {
		item = static_cast<TransferQueueItem*>( it.current() );
		Transfer* transfer = item->transfer();
		if ( transfer ) {
			unsigned int status = transfer->status();
			if( status & ( Transfer::Paused | Transfer::Started ) )
				itemList.append( item );
		}
  ++it;
	}
	if( itemList.count() > 0 ) {
		int result = KMessageBox::questionYesNoCancel( m_queueWidget, i18n("Do you also want to remove the active transfers ?\n"
											"If so, they will be stopped"), i18n("Remove All...") );
		if( result == KMessageBox::Cancel )
			return;

		if( result == KMessageBox::Yes ) {
			for( item = itemList.first(); item; item = itemList.next() ) {
				setCommand( item, Transfer::Cancel,Transfer::Started | Transfer::Paused );
			}
		}
	}
	QListViewItemIterator it2( m_queueWidget );
	while ( it2.current() ) {
		item = static_cast<TransferQueueItem*>( it2.current() );
		Transfer* transfer =  item->transfer();
		if( transfer && transfer->status() == Transfer::Queued ) {
			// if the transfer is queued we need to also remove it from transferManager
			setCommand( item, Transfer::Cancel, Transfer::Queued );
		}
		m_api->transferManager()->removeTransfer( item->ID() );
		m_session->removeTransfer( item->ID() );
		delete item;
	}
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotRemove() {
	if( ! m_queueWidget->selectedItem() )
		return;

	TransferQueueItem* item = static_cast<TransferQueueItem*>( m_queueWidget->selectedItem() );
	if( item ) {
		Transfer* transfer =  item->transfer();
		if( transfer && transfer->status() == Transfer::Queued ) {
			// if the transfer is queued we need to also remove it from transferManager
			setCommand( item, Transfer::Cancel, Transfer::Queued  );
		}
		m_api->transferManager()->removeTransfer( item->ID() );
		m_session->removeTransfer( item->ID() );
		delete item;
	}
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotMoveUp() {
	if( ! m_queueWidget->selectedItem() )
		return;

	TransferQueueItem* item = static_cast<TransferQueueItem*>( m_queueWidget->selectedItem() );
	if( item ) {
		Transfer* transfer = item->transfer();
		if( m_queue.find( transfer ) != -1 ) {
			if( m_queue.prev() ) {
				int index = m_queue.at();
				m_queue.remove( transfer );
				m_queue.insert( index, transfer );
				m_queueWidget->moveItem( item->itemAbove(), 0L, item );
			}
		}
	}
}
//-----------------------------------------------
void KBearTransferQueuePlugin::slotMoveDown() {
	if( ! m_queueWidget->selectedItem() )
		return;

	TransferQueueItem* item = static_cast<TransferQueueItem*>( m_queueWidget->selectedItem() );
	if( item ) {
		Transfer* transfer = item->transfer();
		if( m_queue.find( transfer ) != -1 ) {
			if( m_queue.next() ) {
				int index = m_queue.at();
				m_queue.remove( transfer );
				m_queue.insert( index, transfer );
				m_queueWidget->moveItem( item, 0L, item->itemBelow() );
			}
		}
	}
}
//-----------------------------------------------

