/***************************************************************************
                          kbearimportfilterplugin.cpp  -  description
                             -------------------
    begin                : tis mar 19 2002
    copyright            : (C) 2003 by Björn Sahlström
    email                : kbjorn@users.sourceforge.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

//////////////////////////////////////////////////////
// Qt specific includes
#include <qfile.h>
#include <qdir.h>
#include <qmap.h>
#include <qdom.h>
#include <qstringlist.h>
//////////////////////////////////////////////////////
// KDE specific includes
#include <klocale.h>
#include <kconfig.h>
#include <kmdcodec.h>
#include <kmessagebox.h>
#include <kinstance.h>
#include <kgenericfactory.h>
#include <kdebug.h>
//////////////////////////////////////////////////////
// Application specific includes
#include "kbearimportfilterplugin.h"
#include "kbeartags.h"
#include "misc.h"

#include "kbearimportfilterplugin.moc"

using namespace KBear;

///////////////////////////////////////////////////////
enum KBearImportFilterPlugin::SITEMANAGER_VERSION KBearImportFilterPlugin::SITEMANAGER_VERSION = OLD;
///////////////////////////////////////////////////////

typedef struct KBearImportConnectInfo;
struct KBearImportConnectInfo{
	QString label;
	QString protocol;
	QString host;
	int port;
	int sleep;
	int numRetries;
	bool anonym;
	bool passiveMode;
	bool extendedPassiveMode;
	bool markPartial;
	bool singleConnection;
	bool autoReconnect;
	bool listA;
	QString user;
	QString pass;
	QString remotePath;
	QString localPath;
	QString filesysEncoding;
};
///////////////////////////////////////////////////////
inline QDataStream& operator >> ( QDataStream& s, struct KBearImportConnectInfo& inf ) {
	s >> inf.label;
	s >> inf.host;
	s >> inf.port;
	QString str;
	s >> str;
	if(str =="true")
		inf.anonym = true;
	else
		inf.anonym = false;
	s >> inf.user;
	s >> inf.pass;
	s >> inf.remotePath;
	if( KBearImportFilterPlugin::SITEMANAGER_VERSION == KBearImportFilterPlugin::OLD ){
		inf.protocol="ftp";
		inf.localPath = QDir::homeDirPath();
		inf.passiveMode = true;
	}
	else{
		s >> inf.localPath;
		inf.protocol="ftp";
		inf.passiveMode = true;
	}
	return s;
}		
///////////////////////////////////////////////////////
typedef struct KBearImportSiteInfo;
struct KBearImportSiteInfo {
	QString parent;
	KBearImportConnectInfo info;
	QString description;
};
///////////////////////////////////////////////////////
inline QDataStream& operator >> ( QDataStream& s, struct KBearImportSiteInfo& inf ) {
	s >> inf.parent;
	s >> inf.info;
	s >> inf.description;
	return s;
}
///////////////////////////////////////////////////////
inline QDataStream& operator>>( QDataStream& s, QMap<QString, KBearImportSiteInfo>& m) {
	m.clear();
	Q_UINT32 c;
	s >> c;
	for( Q_UINT32 i = 0; i < c; ++i ) {
		QString k;
		KBearImportSiteInfo t;
		s >> k;
		s >> t;
		m.insert( k, t );
	}
	return s;
}
///////////////////////////////////////////////////////
void readDomTree( QMap<QString, KBearImportSiteInfo>& m, QDomElement element ) {
	QString k;
	KBearImportSiteInfo t;
	t.info.anonym = t.info.markPartial = t.info.singleConnection = t.info.autoReconnect = false;
	if( element.tagName() == TAG_GROUP ) {
		k = element.attribute( ATT_LABEL );
		t.description = TAG_GROUP;
		t.info.label = k;
		if( element.parentNode().toElement().tagName() == TAG_SITES )
			t.parent = "Root";
		else
			t.parent = element.parentNode().toElement().attribute( ATT_LABEL );
		m.insert( k, t );
		for( uint i = 0; i < element.elementsByTagName( TAG_GROUP ).count(); i++ )
			readDomTree( m, element.elementsByTagName( TAG_GROUP ).item( i ).toElement() );
		for( uint n = 0; n < element.elementsByTagName( TAG_SITE ).count(); n++ )
			readDomTree( m, element.elementsByTagName( TAG_SITE).item( n ).toElement() );
	} else if( element.tagName() == TAG_SITE ) {
		k = element.attribute( ATT_LABEL );
		t.info.label = k;
		if( element.parentNode().toElement().tagName() == TAG_SITES )
			t.parent = "Root";
		else
			t.parent = element.parentNode().toElement().attribute( ATT_LABEL );

		QDomNodeList nodeList = element.childNodes();
		for( uint i = 0; i < nodeList.count(); i++ ) {
			QString tag = nodeList.item( i ).toElement().tagName();
			if( tag == TAG_HOST )
				t.info.host = nodeList.item( i ).toElement().text();
			else if( tag == TAG_LOCAL_PATH )
				t.info.localPath = nodeList.item( i ).toElement().text();
			else if( tag == TAG_PASS )
				t.info.pass = nodeList.item( i ).toElement().text();
			else if( tag == TAG_PROTOCOL )
				t.info.protocol = nodeList.item( i ).toElement().text();
			else if( tag == TAG_REMOTE_PATH )
				t.info.remotePath = nodeList.item( i ).toElement().text();
			else if( tag == TAG_USER )
				t.info.user = nodeList.item( i ).toElement().text();
			else if( tag == TAG_ANONYMOUS )
				t.info.anonym = true;
			else if( tag == TAG_DISABLE_PASV )
				t.info.passiveMode = false;
			else if( tag == TAG_DISABLE_EPASV )
				t.info.extendedPassiveMode = false;
			else if( tag == TAG_PORT )
				t.info.port = nodeList.item( i ).toElement().text().toInt();
			else if( tag == TAG_DESCRIPTION )
				t.description = nodeList.item( i ).toElement().text();
			else if( tag == TAG_MARK_PARTIAL )
				t.info.markPartial = true;
			else if( tag == TAG_AUTO_RECONNECT ) {
				t.info.autoReconnect = true;
				t.info.sleep = nodeList.item( i ).toElement().attribute( ATT_SLEEP ).toInt();
				t.info.numRetries = nodeList.item( i ).toElement().attribute( ATT_COUNT ).toInt();
			} else if( tag == TAG_FILESYS_ENCODING )
				t.info.filesysEncoding = nodeList.item( i ).toElement().text();
			else if( tag == TAG_SINGLE_CONNECTION )
				t.info.singleConnection = true;
			else if( tag == "disable_list_a" )
				t.info.listA = false;
			else
				kdDebug()<<"readDomTree(): Unrecognised Tag:"<<
					nodeList.item( i ).toElement().tagName()<<endl;
		}
		m.insert( k, t );
	}
}
///////////////////////////////////////////////////////
inline QString operator>>( QString domContent, QMap<QString, KBearImportSiteInfo>& m) {
	QDomDocument *doc = new QDomDocument;
	doc->setContent( domContent );
	QDomNodeList nodeList = doc->childNodes().item( 1 ).childNodes();
	for( uint i = 0; i < nodeList.count(); i++ ) {
		readDomTree( m, nodeList.item( i ).toElement() );
	}
	return domContent;
}
///////////////////////////////////////////////////////
typedef KGenericFactory<KBearImportFilterPlugin> KBearImportFilterPluginFactory;
K_EXPORT_COMPONENT_FACTORY( kbearimportfilter, KBearImportFilterPluginFactory( "KBearImportFilterPlugin" ) );
//-----------------------------------------------
KBearImportFilterPlugin::KBearImportFilterPlugin(QObject *parent, const char *name,const QStringList& )
	:	SiteImportFilterPluginIface(parent,name),
		m_hasError( false )
{
//	setXMLFile("kbearimportfilterui.rc");
	KGlobal::locale()->insertCatalogue("kbear");
}
//-----------------------------------------------
KBearImportFilterPlugin::~KBearImportFilterPlugin(){
}
//-----------------------------------------------
QString KBearImportFilterPlugin::getDomDocument() {
	return m_domDocument.toString();
}
//-----------------------------------------------
void KBearImportFilterPlugin::import( const QString& fileName ) {
	kdDebug()<<"KBearImportFilterPlugin::import() fileName = "<<fileName<<endl;
	if( fileName.isEmpty() || fileName.isNull() ) {
		KMessageBox::sorry( 0, i18n("You have to select a file to import."), i18n("No file") );
		m_hasError = true;
		emit progress( 100 );
		return;
	}
	//Check version of sitemanager
	QStringList list = QStringList::split( "/", fileName );
	if( list.last().contains( QString::fromLatin1("sitemanager_1_3")) )
		SITEMANAGER_VERSION = NEWER;
	else if( list.last().contains( QString::fromLatin1("sitemanager.xml")) )
		SITEMANAGER_VERSION = XML;
	else if( list.last().contains( QString::fromLatin1("sitemanager")) )
		SITEMANAGER_VERSION = OLD;
	else { // Not a KBear sitemanager file
		invalidFileError( fileName );
		m_hasError = true;
	}
	if( ! m_hasError ) {
		QFile file( fileName );
		file.open(IO_ReadOnly);
		QMap<QString, KBearImportSiteInfo> mySiteMap;
		QString version;
		if( SITEMANAGER_VERSION == XML ) {
			QTextStream fileStream( &file );
			fileStream.read() >> mySiteMap;
			version = "2.x.x";
		} else {
			QDataStream fileStream( &file );
			fileStream >> mySiteMap;
			version = "1.x.x";
		}
		file.close();

		m_domDocument.setContent( QString("<%1 %2=\"%3\"/>").arg(TAG_GROUP).arg(ATT_LABEL).
			arg(i18n("KBear %1 import").arg( version )) );

		size = (float)mySiteMap.count();
		counter = 0;
		if( size <= 0 ) {
			invalidFileError( fileName );
			m_hasError = true;
		}
		else
			createTree( &mySiteMap, m_domDocument.firstChild().toElement() );
		int answer = KMessageBox::questionYesNo( 0, i18n("The old sitemanager has now been imported.\n"
									"Do you want to remove the old sitemanager file now ?"), i18n("Remove file") );
		if( answer == KMessageBox::Yes ) {
			file.remove();
		}
	}
	emit progress( 100 );
}
//-----------------------------------------------
void KBearImportFilterPlugin::createTree( QMap<QString, KBearImportSiteInfo>* mySiteMap , QDomElement parentElement ){
	const QString rootStr = QString::fromLatin1( "Root" );
	KBearImportSiteInfo groupInf, siteInf;
	QDomElement tmpElement;
	QMapIterator<QString, KBearImportSiteInfo> siteIter, groupIter;
	for( groupIter = mySiteMap->begin(); groupIter != mySiteMap->end(); ++groupIter )  {
		groupInf = groupIter.data();
		if( groupInf.description == TAG_GROUP ) {
			if( ( groupInf.parent == rootStr && parentElement == m_domDocument.firstChild().toElement() )
				|| groupInf.parent == parentElement.attribute( ATT_LABEL ) )
			{
				tmpElement = m_domDocument.createElement( TAG_GROUP );
				tmpElement.setAttribute( ATT_LABEL, groupInf.info.label );
				parentElement.appendChild( tmpElement );
				createTree( mySiteMap, tmpElement );
			}
		}
		else {
			for( siteIter = mySiteMap->begin(); siteIter != mySiteMap->end(); ++siteIter )  {
				siteInf = siteIter.data();
				if( siteInf.description == TAG_GROUP ) // is it a group  item
					;                                            // do nothing
				else if( ( siteInf.parent == rootStr && parentElement == m_domDocument.firstChild().toElement() )
					|| siteInf.parent == parentElement.attribute( ATT_LABEL ) )
				{          // is this a root item ?
					if( addSite( siteInf, parentElement ) ) {
						emit progress( int(float(counter) / size * 100) );
						counter++;
					}
				}
			}
		}
	}
}
//-----------------------------------------------
bool KBearImportFilterPlugin::addSite( KBearImportSiteInfo siteInf, QDomElement parentElement ) {
	QDomNodeList list = parentElement.childNodes();
	for( unsigned int i = 0; i < list.count(); i++ ) {
		if( list.item( i ).toElement().attribute(ATT_LABEL) == siteInf.info.label )
			return false; // site already exists
	}
	// first  check so the site has a host, if not ignore it
	if( siteInf.info.host.isNull() || siteInf.info.host.isEmpty() )  // no host
		return false;

	// set site
	QDomElement siteElement = m_domDocument.createElement( TAG_SITE );
	siteElement.setAttribute( ATT_LABEL, siteInf.info.label );
	parentElement.appendChild( siteElement );
	// set host
	QString tmp = siteInf.info.host;
	QDomElement tmpElement = m_domDocument.createElement( TAG_HOST );
	QDomText txtNode = m_domDocument.createTextNode( tmp );
	tmpElement.appendChild( txtNode );
	siteElement.appendChild( tmpElement );	
	// set port
	int p = siteInf.info.port;
	tmpElement = m_domDocument.createElement( TAG_PORT );
	txtNode = m_domDocument.createTextNode( QString::number( p ) );
	tmpElement.appendChild( txtNode );
	siteElement.appendChild( tmpElement );	
	// set protocol
	tmp = siteInf.info.protocol;
	tmpElement = m_domDocument.createElement( TAG_PROTOCOL );
	txtNode = m_domDocument.createTextNode( tmp );
	tmpElement.appendChild( txtNode );
	siteElement.appendChild( tmpElement );	
	// set remote directory
	tmp = siteInf.info.remotePath;
	tmpElement = m_domDocument.createElement( TAG_REMOTE_PATH );
	txtNode = m_domDocument.createTextNode( tmp );
	tmpElement.appendChild( txtNode );
	siteElement.appendChild( tmpElement );	
	// set local directory
	if( !siteInf.info.localPath.isEmpty() ) {
	tmp = siteInf.info.localPath;
	tmpElement = m_domDocument.createElement( TAG_LOCAL_PATH );
	txtNode = m_domDocument.createTextNode( tmp );
	tmpElement.appendChild( txtNode );
	siteElement.appendChild( tmpElement );
	}
	// set username
	if( !siteInf.info.user.isEmpty() ) {
	tmp = siteInf.info.user;
	tmpElement = m_domDocument.createElement( TAG_USER );
	txtNode = m_domDocument.createTextNode( tmp );
	tmpElement.appendChild( txtNode );
	siteElement.appendChild( tmpElement );
	}
	// set password
	if( !siteInf.info.pass.isEmpty() ) {
	tmp = encodePassword( siteInf.info.pass );
	tmpElement = m_domDocument.createElement( TAG_PASS );
	txtNode = m_domDocument.createTextNode( tmp );
	tmpElement.appendChild( txtNode );
	siteElement.appendChild( tmpElement );
	}
	// set description
	if( !siteInf.description.isEmpty() ) {
	tmp = siteInf.description;
	tmpElement = m_domDocument.createElement( TAG_DESCRIPTION );
	txtNode = m_domDocument.createTextNode( tmp );
	tmpElement.appendChild( txtNode );
	siteElement.appendChild( tmpElement );
	}
	// set filesys Encoding
	if( !siteInf.info.filesysEncoding.isEmpty() ) {
	tmp = siteInf.info.filesysEncoding;
	tmpElement = m_domDocument.createElement( TAG_FILESYS_ENCODING );
	txtNode = m_domDocument.createTextNode( tmp );
	tmpElement.appendChild( txtNode );
	siteElement.appendChild( tmpElement );
	}
	// set list command
	if( !siteInf.info.listA ) {
	tmp = "ls";
	tmpElement = m_domDocument.createElement( TAG_LIST_COMMAND );
	txtNode = m_domDocument.createTextNode( tmp );
	tmpElement.appendChild( txtNode );
	siteElement.appendChild( tmpElement );
	}
	// set anonym
	if( siteInf.info.anonym ) {
		tmpElement = m_domDocument.createElement( TAG_ANONYMOUS );
		siteElement.appendChild( tmpElement );	
	}
	// set PASV
	if( ! siteInf.info.passiveMode ) {
		tmpElement = m_domDocument.createElement( TAG_DISABLE_PASV );
		siteElement.appendChild( tmpElement );
	}
	// set EPASV
	if( !siteInf.info.extendedPassiveMode ) {
		tmpElement = m_domDocument.createElement( TAG_DISABLE_EPASV );
		siteElement.appendChild( tmpElement );
	}
	// set mark partial
	if( siteInf.info.markPartial ) {
		tmpElement = m_domDocument.createElement( TAG_MARK_PARTIAL );
		siteElement.appendChild( tmpElement );
	}
	// set single connection
	if( siteInf.info.singleConnection ) {
		tmpElement = m_domDocument.createElement( TAG_SINGLE_CONNECTION );
		siteElement.appendChild( tmpElement );
	}
	// set auto reconnect
	if( siteInf.info.autoReconnect ) {
		tmpElement = m_domDocument.createElement( TAG_AUTO_RECONNECT );
		tmpElement.setAttribute( ATT_SLEEP, siteInf.info.sleep );
		tmpElement.setAttribute( ATT_COUNT, siteInf.info.numRetries );
		siteElement.appendChild( tmpElement );
	}
	return true;
}
//-----------------------------------------------
void KBearImportFilterPlugin::invalidFileError(const QString& fileName){
	KMessageBox::sorry( 0, i18n("The file: %1\nis not a valid KBear sitemanager file.").arg(fileName), i18n("Invalid import file") );
}
//-----------------------------------------------
