/*********************************************************************************
* C++ Implementation: transferqueuesession.cpp
* Description:
*
* Begin : lör maj 31 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 <qfile.h>
#include <qtextstream.h>
#include <qptrlist.h>
//////////////////////////////////////////////////////////////////////
// KDE specific include files
#include <kstandarddirs.h>
#include <kglobal.h>
#include <kmimetype.h>
#include <kicontheme.h>
#include <kurldrag.h>
#include <kio/global.h>
#include <klocale.h>
#include <kdebug.h>
//////////////////////////////////////////////////////////////////////
// System specific include files
//////////////////////////////////////////////////////////////////////
// Application specific include files
#include "transferqueuesession.h"
#include "transferqueuewidget.h"
#include "kbeartransferqueueplugin.h"
#include "transfer.h"
#include "transfergroup.h"
#include "kbeardomhelper.h"
#include "misc.h"
#include "kbearcore.h"
#include "transfermanager.h"
#include "connectionmanager.h"

using namespace KBear;

//-----------------------------------------------
const QString& KBear::TransferQueueSession::TAG_SESSION = KGlobal::staticQString( QString::fromLatin1("session") );
const QString& KBear::TransferQueueSession::TAG_TRANSFER_GROUP = KGlobal::staticQString( QString::fromLatin1("transfer_group") );
const QString& KBear::TransferQueueSession::TAG_TRANSFER = KGlobal::staticQString( QString::fromLatin1("transfer") );
const QString& KBear::TransferQueueSession::TAG_SOURCE_SITE = KGlobal::staticQString( QString::fromLatin1("source_site") );
const QString& KBear::TransferQueueSession::TAG_DEST_SITE = KGlobal::staticQString( QString::fromLatin1("dest_site") );
const QString& KBear::TransferQueueSession::ATT_SOURCE_URL = KGlobal::staticQString( QString::fromLatin1("source_url") );
const QString& KBear::TransferQueueSession::ATT_DEST_URL = KGlobal::staticQString( QString::fromLatin1("dest_url") );
const QString& KBear::TransferQueueSession::ATT_PROGRESS = KGlobal::staticQString( QString::fromLatin1("progress") );
const QString& KBear::TransferQueueSession::ATT_STATUS = KGlobal::staticQString( QString::fromLatin1("status") );
const QString& KBear::TransferQueueSession::ATT_SIZE = KGlobal::staticQString( QString::fromLatin1("size") );
const QString& KBear::TransferQueueSession::ATT_TYPE = KGlobal::staticQString( QString::fromLatin1("type") );
const QString& KBear::TransferQueueSession::ATT_MIMETYPE = KGlobal::staticQString( QString::fromLatin1("mimetype") );
const QString& KBear::TransferQueueSession::ATT_ID = KGlobal::staticQString( QString::fromLatin1("ID") );
const QString& KBear::TransferQueueSession::ATT_VERSION = KGlobal::staticQString( QString::fromLatin1("version") );
//-----------------------------------------------
TransferQueueSession::TransferQueueSession( KBearPlugin* plugin, TransferQueueWidget* w )
 : QDomDocument(), m_widget( w ), m_plugin( plugin ),m_version( 2 )
{
	m_sessionFile = locateLocal( "data", "kbeartransferqueue/queuesession.xml" );
	if( QFile::exists( m_sessionFile ) ) {
		QFile file( m_sessionFile );
		file.open(IO_ReadOnly);
		if( ! setContent( &file ) )
			kdError()<<k_funcinfo<<QString("Could not parse session file:  %1" ).arg( m_sessionFile )<<endl;
		file.close();
	}
	// we need to make sure we have a valid dom tree
	QDomDocument tmpDoc; // We build a new document
	//first we need a <transfers/> element as root
	QDomElement root;
	QDomElement newRoot;
	if( documentElement().isNull() ) // no root
		newRoot = tmpDoc.createElement( TAG_SESSION );
	else {
		QDomElement root = documentElement();
		if( root.tagName() != TAG_SESSION || root.attribute( ATT_VERSION ).toUInt() != m_version ) { // The root isn't a sites tag, sorry ;)
			kdError()<<QString("The file: %1 isn't valid, creating a new. No session will be restored !").arg( m_sessionFile )<<endl;
			newRoot = tmpDoc.createElement( TAG_SESSION );
		}
		else
			newRoot = root.cloneNode( true ).toElement();
	}
	newRoot.setAttribute( ATT_VERSION, QString::number( m_version ) );
	tmpDoc.setContent( QString("<?xml version=\"1.0\" encoding=\"%1\"?>").arg( KGlobal::locale()->encoding() ) );
	tmpDoc.appendChild( newRoot );
	setContent( tmpDoc.toString() );

}
//-----------------------------------------------
TransferQueueSession::~TransferQueueSession() {
	kdDebug()<<k_funcinfo<<endl;

	QDomElement transferElement;
	QDomElement transferGroup;
	QDomNodeList groupList = elementsByTagName( TAG_TRANSFER_GROUP );

	for( unsigned int i = 0; i < groupList.count(); i++ ) {
		transferGroup = groupList.item( i ).toElement();
		QDomNodeList transferList = transferGroup.elementsByTagName( TAG_TRANSFER );

		for( unsigned int j = 0; j < transferList.count(); j++ ) {
			transferElement = transferList.item( j ).toElement();
			transferElement.setAttribute( ATT_ID, QString::number( (long)-1 ) );
			unsigned int status = transferElement.attribute( ATT_STATUS ).toUInt();
			if( status != Transfer::Finished ) {
				transferElement.setAttribute( ATT_STATUS, Transfer::Canceled );
			}
		}
	}

	QFile file( m_sessionFile );
	file.open( IO_WriteOnly );
	QTextStream fileStream( &file );
	save( fileStream, 10 );
	fileStream<<flush;
	file.close();

}
//-----------------------------------------------
void TransferQueueSession::restoreSession() {
	TransferManager::getInstance()->setStartTransfersDirectly( false );
	parse( documentElement() );
}
//-----------------------------------------------
void TransferQueueSession::clear() {
	setContent( QString("<?xml version=\"1.0\" encoding=\"%1\"?><%2>").arg( KGlobal::locale()->encoding() ).arg( TAG_SESSION ) );
	QDomElement root = documentElement();
	root.setAttribute( ATT_VERSION, QString::number( m_version ) );
}
//-----------------------------------------------
void TransferQueueSession::parse( QDomElement parentElement ) {
	TransferQueueItem* item = 0L;
	QDomNode node = parentElement.firstChild();
	SiteInfo sourceInfo;
	SiteInfo destInfo;
	KURL::List urls;
	QMap<QString, QString> metaData;
	while( ! node.isNull() ) {
		if( node.toElement().tagName() == TAG_TRANSFER_GROUP ) {
			// recursive build of the tree
			parse( node.toElement() );
		}
		else if( node.toElement().tagName()  == TAG_TRANSFER ) {
			QString sourceURL = node.toElement().attribute( ATT_SOURCE_URL );
			QString destURL = node.toElement().attribute( ATT_DEST_URL );
			unsigned int status = node.toElement().attribute( ATT_STATUS ).toUInt();
			long unsigned int size = node.toElement().attribute( ATT_SIZE ).toULong();
			unsigned int type = node.toElement().attribute( ATT_TYPE ).toUInt();
			int progress = node.toElement().attribute( ATT_PROGRESS ).toInt();
			QString mimetype = node.toElement().attribute( ATT_MIMETYPE );
			QString typeStr = ( type == Transfer::Move ) ? i18n("Move") : i18n("Copy");
			KURL sTmp = sourceURL;
			if( sTmp.protocol() == QString::fromLatin1("kbearftp") ) {
				sTmp.setProtocol( QString::fromLatin1("ftp") );
			}
			KURL dTmp = destURL;
			if( dTmp.protocol() == QString::fromLatin1("kbearftp") ) {
				dTmp.setProtocol( QString::fromLatin1("ftp") );
			}
			if( status == Transfer::Finished ) {
				if( m_widget->childCount() == 0 )
					item = new TransferQueueItem( 0L, m_widget, i18n("Unknown") , sTmp.prettyURL(), i18n("Unknown") , "", typeStr, dTmp.prettyURL() );
				else
					item = new TransferQueueItem( 0L, m_widget, m_widget->lastItem(), i18n("Unknown"), sTmp.prettyURL(), i18n("Unknown"), "", typeStr, dTmp.prettyURL() );
				if( ! mimetype.isEmpty() ) {
					KMimeType::Ptr ptr = KMimeType::mimeType( mimetype );
					item->setPixmap( 1, ptr->pixmap( KIcon::Small, 16 ) );
				}
				item->setTotalSize( size );
				item->setStatus( status );
				item->setProgress( progress );
			}
			// we only create transfers if they are canceled or queued
			if( status & (Transfer::Canceled | Transfer::Queued ) ) {
				KURL source = sourceURL;
				KURL dest = destURL;
				urls.append( source );
				metaData.insert( source.url(), mimetype );
				metaData.insert( "Action", ( type == Transfer::Move ) ? "move" : "copy" );
				metaData.insert( "SourceID", QString::number( sourceInfo.ID() ) );
				metaData.insert( "DestID", QString::number( destInfo.ID() ) );
				metaData.insert( "DestURL", dest.url() );
			}
		}
		else if( node.toElement().tagName()  == TAG_SOURCE_SITE ) {
			QString tmp;
			QTextStream stream( &tmp, IO_ReadWrite );
			stream << node;
			sourceInfo = SiteInfo( tmp );
			sourceInfo.setPass( decodePassword( sourceInfo.pass() ) );
			if( ! sourceInfo.isLocal() ) {
				ConnectionManager::getInstance()->createNewSite( sourceInfo );
				m_plugin->core()->emitNewSite( sourceInfo );
			}
		}
		else if( node.toElement().tagName()  == TAG_DEST_SITE ) {
			QString tmp;
			QTextStream stream( &tmp, IO_ReadWrite );
			stream << node;
			destInfo = SiteInfo( tmp );
			destInfo.setPass( decodePassword( destInfo.pass() ) );
			if( ! destInfo.isLocal() ) {
				ConnectionManager::getInstance()->createNewSite( destInfo );
				m_plugin->core()->emitNewSite( destInfo );
			}
		}
		node = node.nextSibling();
	}
	if( parentElement != documentElement() && parentElement.attribute( ATT_ID ).toInt() != -1 ) {

		KURLDrag* dragObject = KURLDrag::newDrag( urls, metaData );
		TransferGroup* group = TransferManager::getInstance()->addTransfers( dragObject );

		if( group ) {
			// This will cause the connection to be closed automatically when the transfers are finished
			if( sourceInfo.ID() >= 0 )
				ConnectionManager::getInstance()->closeConnection( sourceInfo.ID() );
			if( destInfo.ID() >= 0 )
				ConnectionManager::getInstance()->closeConnection( destInfo.ID() );

			parentElement.setAttribute( ATT_ID, group->ID() );
			QPtrList<Transfer>* transferList = group->transfers();
			QDomNodeList list = parentElement.elementsByTagName( TAG_TRANSFER );

			for( unsigned int i = 0; i < list.count(); i++ ) {

				QString sourceURL = list.item( i ).toElement().attribute( ATT_SOURCE_URL );
				QString destURL = list.item( i ).toElement().attribute( ATT_DEST_URL );
				unsigned int status = list.item( i ).toElement().attribute( ATT_STATUS ).toUInt();
				long unsigned int size = list.item( i ).toElement().attribute( ATT_SIZE ).toULong();
				unsigned int type = list.item( i ).toElement().attribute( ATT_TYPE ).toUInt();
				int progress = list.item( i ).toElement().attribute( ATT_PROGRESS ).toInt();
				QString mimetype = list.item( i ).toElement().attribute( ATT_MIMETYPE );
				QString typeStr = ( type == Transfer::Move ) ? i18n("Move") : i18n("Copy");

				for( unsigned int j = 0; j < transferList->count(); j++ ) {

					if( sourceURL == transferList->at( j )->sourceURLs().first().prettyURL()
						&& destURL == transferList->at( j )->destURL().prettyURL()
						&& status & ( Transfer::Queued | Transfer::Canceled ) )
					{
						list.item( i ).toElement().setAttribute( ATT_ID, QString::number( (long)transferList->at( j )->transferID() ) );

						KURL sTmp = sourceURL;
						if( sTmp.protocol() == QString::fromLatin1("kbearftp") ) {
							sTmp.setProtocol( QString::fromLatin1("ftp") );
						}
						KURL dTmp = destURL;
						if( dTmp.protocol() == QString::fromLatin1("kbearftp") ) {
							dTmp.setProtocol( QString::fromLatin1("ftp") );
						}
						if( m_widget->childCount() == 0 )
							item = new TransferQueueItem( transferList->at( j ), m_widget, i18n("Unknown") , sTmp.prettyURL(), i18n("Unknown") , "", typeStr, dTmp.prettyURL() );
						else
							item = new TransferQueueItem( transferList->at( j ), m_widget, m_widget->lastItem(), i18n("Unknown"), sTmp.prettyURL(), i18n("Unknown"), "", typeStr, dTmp.prettyURL() );

						QObject::connect( item, SIGNAL( statusChanged( TransferQueueItem*, unsigned int ) ),
										m_plugin, SLOT( slotTransferStatusChanged( TransferQueueItem*, unsigned int ) ) );
						QObject::connect( item, SIGNAL( progress( TransferQueueItem*, unsigned long ) ),
										m_plugin, SLOT( slotProgress( TransferQueueItem*, unsigned long ) ) );
						QObject::connect( item, SIGNAL( totalSize( TransferQueueItem*, KIO::filesize_t ) ),
										m_plugin, SLOT( slotTotalSize( TransferQueueItem*, KIO::filesize_t ) ) );

						item->setTotalSize( size );
						item->setStatus( status );
						item->setProgress( progress );
						if( ! mimetype.isEmpty() ) {
							KMimeType::Ptr ptr = KMimeType::mimeType( mimetype );
							item->setPixmap( 1, ptr->pixmap( KIcon::Small, 16 ) );
						}

						if( status == Transfer::Queued )
							TransferManager::getInstance()->setTransferCommand( transferList->at( j )->transferID(), Transfer::Queue );
						else
							TransferManager::getInstance()->setTransferCommand( transferList->at( j )->transferID(), Transfer::Cancel );

					}
				}
			}
		}
	}
}
//-----------------------------------------------
void TransferQueueSession::addTransfer( const Transfer* transfer ) {
	if( ! transfer )
		return;
	QDomElement transferGroup = findTransferGroup( transfer->group()->ID() );
	if( transferGroup.isNull() ) {
		QDomElement doc = documentElement();
		transferGroup = KBearDomHelper::addEmptyElement( *this, doc, TAG_TRANSFER_GROUP );
		transferGroup.setAttribute( ATT_ID, QString::number( transfer->group()->ID() ) );

		SiteInfo tmp = transfer->sourceInfo();
		tmp.setPass( encodePassword( tmp.pass() ) );
		QDomElement tmpElement = tmp.documentElement();
		transferGroup.appendChild( tmpElement );
		tmpElement.setTagName( TAG_SOURCE_SITE );
		tmp = transfer->destInfo();
		tmp.setPass( encodePassword( tmp.pass() ) );
		tmpElement = tmp.documentElement();
		transferGroup.appendChild( tmpElement );
		tmpElement.setTagName( TAG_DEST_SITE );
	}
	// we should now have a valid group
	QDomElement transferElement = KBearDomHelper::addEmptyElement( *this, transferGroup, TAG_TRANSFER );
	transferElement.setAttribute( ATT_ID, QString::number( transfer->transferID() ) );
	transferElement.setAttribute( ATT_SOURCE_URL, transfer->sourceURLs().first().prettyURL() );
	transferElement.setAttribute( ATT_DEST_URL, transfer->destURL().prettyURL() );
	transferElement.setAttribute( ATT_TYPE, QString::number( transfer->type() ) );
	transferElement.setAttribute( ATT_MIMETYPE, transfer->mimetype() );
	transferElement.setAttribute( ATT_PROGRESS, QString::number( transfer->progress() ) );
	transferElement.setAttribute( ATT_STATUS, QString::number( transfer->status() ) );
	transferElement.setAttribute( ATT_SIZE, QString::number( (long unsigned int)transfer->size() ) );
}
//-----------------------------------------------
QDomElement TransferQueueSession::findTransferGroup( int ID ) {
	QDomNodeList groupList = elementsByTagName( TAG_TRANSFER_GROUP );
	QDomElement transferGroup;
	for( unsigned int i = 0; i < groupList.count(); i++ ) {
		if( groupList.item( i ).toElement().attribute( ATT_ID ).toInt() == ID ) {
			transferGroup = groupList.item( i ).toElement();
			break;
		}
	}
	return transferGroup;
}
//-----------------------------------------------
QDomElement TransferQueueSession::findTransfer( long ID ) {
	QDomElement transferElement;
	QDomElement transferGroup;
	QDomNodeList groupList = elementsByTagName( TAG_TRANSFER_GROUP );
	for( unsigned int i = 0; i < groupList.count(); i++ ) {
		transferGroup = groupList.item( i ).toElement();
		QDomNodeList transferList = transferGroup.elementsByTagName( TAG_TRANSFER );
		for( unsigned int i = 0; i < transferList.count(); i++ ) {
			transferElement = transferList.item( i ).toElement();
			if( transferElement.attribute( ATT_ID ).toInt() == ID ) {
				return transferElement;
			}
		}
	}
	return transferElement;
}
//-----------------------------------------------
void TransferQueueSession::removeTransfer( long ID ) {
	QDomElement transferElement = findTransfer( ID );
	if( transferElement.isNull() )
		return;

	QDomElement parentElement = transferElement.parentNode().toElement();
	parentElement.removeChild( transferElement );
	QDomNodeList list = parentElement.elementsByTagName( TAG_TRANSFER );
	if( ! list.count() ) // if the group is empty remove it as well
		documentElement().removeChild( parentElement );
}
//-----------------------------------------------
void TransferQueueSession::removeTransferGroup( int ID ) {
	QDomElement group = findTransferGroup( ID );
	if( ! group.isNull() ) {
		documentElement().removeChild( group );
	}
}
//-----------------------------------------------
void TransferQueueSession::updateTransfer( long ID, const QString& type, const QString& val ) {
	QDomElement transferElement = findTransfer( ID );
	transferElement.setAttribute( type, val );
	if( transferElement.attribute( ATT_STATUS ).toUInt() == Transfer::Finished ) {
		QDomElement finishedGroup = findTransferGroup( -1 );
		if( finishedGroup.isNull() ) {
			QDomElement doc = documentElement();
			finishedGroup = KBearDomHelper::addEmptyElement( *this, doc, TAG_TRANSFER_GROUP );
			finishedGroup.setAttribute( ATT_ID, QString::number( -1 ) );
		}
		QDomNode tmp = transferElement.cloneNode();
		finishedGroup.appendChild( tmp );
		QDomElement parent = transferElement.parentNode().toElement();
		parent.removeChild( transferElement );
		QDomNodeList transferList = parent.elementsByTagName( TAG_TRANSFER );
		if( transferList.count() == 0 ) {
			documentElement().removeChild( parent );
		}

	}
}
//-----------------------------------------------


