/***************************************************************************
 *   Copyright (C) 2005 by xavier helluy   *
 *   xavier.helluy@web.de   *
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 *   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.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.             *
 ***************************************************************************/


#include "queryfieldmetadata.h"
#include <kstandarddirs.h>
#include <kcombobox.h>
#include <qcombobox.h>
#include <kpushbutton.h>
#include <klineedit.h>
#include <kfilemetainfo.h>
#include <kmimetype.h>
#include <kdebug.h>
#include <qcombobox.h>
#include <qobject.h>
#include <kapplication.h>
#include <kiconloader.h>
#include <qmap.h>

#include <kdesktopfile.h>
#include <kio/netaccess.h>

#include <klocale.h>


///TODO:implement all images , all audio,,info-file: file size, ...file type,...


//helper function, the same for all "plugins"
QString stripLuceneField(QString str)
{
	kdDebug() << "HELPER:"  << str << endl;
	
	str = str.stripWhiteSpace();
	str = str.lower();
	str = str.replace(" ","_");
	str = str.replace(":","_");
	str = str.replace("/","_");
	return str;
}




QueryFieldMetaData::QueryFieldMetaData(QWidget* parent, const char* name, WFlags fl)
	: QueryFieldMetaDataBase(parent,name,fl), m_fileName("")
{
	//the plugin is notifyed of any changes of the query-field and if the user presses return
// 	this->query->setFocus();
	
	connect (this->query , SIGNAL( returnPressed() ) ,      this , SLOT(slotReturnPressed() ));
	
	//why this ? Make sure to have a getParsedQuery()
	connect (this->query , SIGNAL( textChanged(const QString &) ) , 
		 this , SLOT(slotTextChanged(const QString &) ));

	
	connect ( this->supportedMimeTypeCombo , SIGNAL(activated(const QString&)),
		  this, SLOT(slotSetupSupportedKeys(const QString & ) ));
// 	connect ( this->supportedMimeTypeCombo , SIGNAL(highlighted(const QString&)),
// 		  this, SLOT(slotSetupSupportedKeys(const QString & ) ));
	
	connect ( this->reloadMetaData, SIGNAL(clicked()),
		  this, SLOT(slotReloadMetaData()));
	
	
	//check if a metadata file exists. I contains a list of metadata plugins found on the system
	//if not, create one FIXME: multiple calls ???
	QString m_storedMetaData 	= locateLocal("appdata","");
	m_fileName 			= m_storedMetaData + "/" + "storedmedata.txt";
	bool exists = KIO::NetAccess::exists(KURL(m_fileName),TRUE, this);
	if (exists)
	{
		kdDebug() << "QueryFieldMetaData::INIT: FILE EXISTS . USE IT"    << endl;
		this->readMetaDataFromFile();
	}
	else
	{
		kdDebug() << "QueryFieldMetaData::INIT: FILE DOESN'T EXISTS CREATE IT"    << endl;
		this->slotReloadMetaData();
	}
	
	
	 
	 setupSupportedMimeTypes();
	 kdDebug() << "QueryFieldMetaData::GEOMETR:"  << this->geometry() << endl;
	 kdDebug() << "QueryFieldMetaData::Pos:"  << this->pos() << endl;

// 	 move(210,0);
	 this->setShown(TRUE);

// 	 show();
	 slotSetupSupportedKeys("Any type");
	 
}

QueryFieldMetaData::~QueryFieldMetaData()
{
}

//used to pupulate comboboxes
void QueryFieldMetaData::setupSupportedMimeTypes()
{
	//get comments and pattern or ?
	
	
	QMap<QString , QMap<QString,QString> >::Iterator it;
	for ( it = m_commentToSupportedMimeType.begin(); it != m_commentToSupportedMimeType.end(); ++it ) 
	{
		QString icon =  it.data().begin().data();
		QPixmap pix = kapp->iconLoader()->loadIcon( icon, KIcon::Small );
		this->supportedMimeTypeCombo->insertItem( pix , it.key() ); 
		kdDebug() << "QueryFieldMetaData::setupSupportedMimeTypes(): ICON"  << icon << endl;

	}

}

//used to populate widgets
void QueryFieldMetaData::slotSetupSupportedKeys(const QString & mimeTypeComment)
{
	kdDebug() << "QueryFieldMetaData::slotSetupSupportedKeys CALLED:"  << mimeTypeComment << endl;

	if ( mimeTypeComment == "Any type")
	{
		kdDebug() << "QueryFieldMetaData::slotSetupSupportedKeys ANYTYPE CALLED:"  << endl;

		this->supportedKeys->insertStringList(m_supportedKeys);
	}
	else
	{
		kdDebug() << "QueryFieldMetaData::slotSetupSupportedKeys SINGLETYPE CALLED:"  << endl;
		
		//reset keys list
		this->supportedKeys->clear();
		QStringList list = (m_commentsToFields.find( mimeTypeComment)).data() ;
		if (list.begin()!=list.end())
		{
			this->query->setEnabled(TRUE);
			this->supportedKeys->setEnabled(TRUE);

			this->supportedKeys->insertItem("Any field");
		}
		else
		{
			this->supportedKeys->setEnabled(FALSE);
			this->query->setEnabled(FALSE);
			this->supportedKeys->insertItem("No field exists");
		}
		
		this->supportedKeys->insertStringList( list );
	}
}

void QueryFieldMetaData::slotReturnPressed()
{
	kdDebug() << "QueryFieldMetaData::slotReturnPressed CALLED:"  << endl;

	//to make sure the query has been parsed
// 	parseQuery ( this->query->text() );
	getQuery();
	kdDebug() << "QueryFieldMetaData::slotReturnPressed PARSE:"  << m_query << endl;

	emit returnPressed(stripLuceneField(m_query));

}

void QueryFieldMetaData::slotTextChanged(const QString & /*queryString*/)
{
	//here, the parsing is done each time one writes something. not good.
	//better would be to let the parent starts the parsing when he wants the data.
// 	parseQuery ( queryString );
// 	kdDebug() << "QueryFieldMetaData::slotTextChanged PARSE:"  << m_query << endl;

	//tell the parent that it must update the content of its m_query
// 	emit textChanged(m_query);
}

QString QueryFieldMetaData::parseQuery(const QString & queryString)
{
	///FIXME or TODO: stripWhiteSpace() lower() replace()
	/* problem here: I am using the fields not from the database but from kde kfileplugin
	*/
	
	
	
	kdDebug() << "QueryFieldMetaData::parseQuery CALLED:"  << endl;

	//get the current mimeType Comment
	QString mimeTypeComment = this->supportedMimeTypeCombo->currentText();
	
	//from the comment find the mimetype in the Map
	QString mimeType = m_commentToSupportedMimeType[mimeTypeComment].begin().key();
	
	
	//get the key of the mimetype to look for
	QString field = this->supportedKeys->currentText();
	
	//start parsing

		
	if ( (mimeTypeComment == "Any type") && queryString.isEmpty() )
	{
		//not implemented and this plugin is about MetaData
		return 0;
	}
	else if ( (mimeTypeComment == "Any type") && ( !queryString.isEmpty()) )
	{
		if ( field == "Any field") 
		{
			//Look only at the MetaData not the mimeType, since all are looked at
			kdDebug() << "QueryFieldMetaData::ANY AND ANY:"   << endl;
			
			m_query= QString::null;
			QString tmp(QString::null);
			for ( QStringList::Iterator it = m_supportedKeys.begin();
						   it != m_supportedKeys.end(); ++it )
			{
				QString indexField = stripLuceneField(*(it));
				kdDebug() << "QueryFieldMetaData" <<  indexField << endl;

				tmp.append(  stripLuceneField(indexField) + ":(" + queryString + ") ");
			}
			m_query.append(tmp);
			m_query.append("mimetype:(\"" + queryString + "\") ");
			kdDebug() << "QueryFieldMetaData::ANY AND ANY:PARSED" <<  m_query << endl;

			return 0;
		}
		else
		{
			//FIXME:case Any type and a field and empty query not possible
			//as long as I don't write a clucene field metaInfoFields:list of fields
			m_query= QString::null;
			kdDebug() << "QueryFieldMetaData::ANY AND SINGLE FIELD" <<  m_query << endl;

			//query about a single field only	
			m_query.append(stripLuceneField(field) + ":(" + queryString + ")");
			return 0;
		}
	}
	//at this point, a Mimetype has been chosen, we look at the field
	else if ( (field == "Any field") && queryString.isEmpty() )
	{
		kdDebug() << "QueryFieldMetaData::MIMETYPE:"  << query << endl;
		//ok, query is considered like a MIMETYPE query only, 
		m_query= QString::null;
		m_query = "mimetype:(\"" + mimeType + "\")";
		return 0; 
		
	}
	else if ( (field == "Any field") && ( (! queryString.isEmpty())  ))
	{
		kdDebug() << "QueryFieldMetaData::MIMETYPE+Query:"  << query << endl;
		//   ( mimetype:BLA AND (field1:query field2:query) ) 
		
		//ok, query is considered like a MIMETYPE query only
		m_query= QString::null;
		m_query = "mimetype:(\"" + mimeType + "\") AND ";
		QString tmp(QString::null);
		QStringList list = (m_commentsToFields.find( mimeTypeComment)).data() ;
		for ( QStringList::Iterator it = list.begin();
				    it != list.end(); ++it )
		{
			QString indexField = stripLuceneField(*it);
			tmp.append( stripLuceneField(indexField) + ":(" + stripLuceneField(queryString) + ") ");
		}
		m_query.append(tmp);
// 		m_query.append(") )");
		return 0;
	}
	else if ( field == "No field exists")
	{
		m_query.append( "mimetype:(\"" + mimeType + "\")");
		return 0;
	}
	else
	{
		m_query= QString::null;
		//FIXME:check no bracket escape exists !!!!!!!!
		if (!queryString.isEmpty())
			m_query.append( "mimetype:(\"" + mimeType + "\") AND " + stripLuceneField(field) + ":(" + queryString + ")" );
		else
			m_query.append( "mimetype:(\"" + mimeType + "\")" );
			
		return 0;
	}
	
	
	
}


QString QueryFieldMetaData::getQuery()
{
	QString str1 = this->query->text();
	
	parseQuery(stripLuceneField(str1));
	
	QString str2 = m_query;
	kdDebug() << "QueryFieldMetaData::slotTextChanged getQuery:"  << str2<< endl;
	
	return str2;
}


void QueryFieldMetaData::readMetaDataFromFile()
{
	
	KDesktopFile * d = new KDesktopFile(m_fileName,FALSE);
	
	QMap<QString, QString>  l_entryMap = d->entryMap("Mime_Comments_Icons");
	QMap<QString , QString>::Iterator itEntry;
	
	//create m_commentToSupportedMimeType
	for ( itEntry= l_entryMap.begin(); itEntry != l_entryMap.end(); ++itEntry ) 
	{
		QString comment  = itEntry.key();
 		//kdDebug() << "QueryFieldMetaData::readMetaDataFromFile() data:"  <<  itEntry.data() << endl;

		QStringList list = QStringList::split(",", itEntry.data(), FALSE);
		//allow empty entries
		//kdDebug() << "QueryFieldMetaData::readMetaDataFromFile() list:"  <<  list << endl;

		QString mimeName;
		QString icon;
		mimeName = *(list.begin());
		//kdDebug() << "QueryFieldMetaData::readMetaDataFromFile() mime: "  <<  mimeName << endl;

		if (list.at(1)!=list.end())
		{
			icon = *(list.at(1));
			//kdDebug() << "QueryFieldMetaData::readMetaDataFromFile() icon:"  <<  icon << endl;

		}
		else 
			icon = "unknown";
		QMap<QString , QString > m;
		m.insert(mimeName ,icon );
		m_commentToSupportedMimeType.insert ( comment , m );
	}
	
	/*//clean up a bit 
	//remove unwanted mime
	m_commentToSupportedMimeType.remove(tr2i18n("All Files"));	
	m_commentToSupportedMimeType.remove(tr2i18n("All Files and Folders"));*/	

	// read metadata-fields
	QMap<QString , QString > allFields;
	l_entryMap.clear();
	m_commentsToFields.clear();
	l_entryMap = d->entryMap("MimeComments_Fields");
	for ( itEntry= l_entryMap.begin(); itEntry != l_entryMap.end(); ++itEntry ) 
	{
		QString comment  = itEntry.key();
		QStringList list = QStringList::split(",", itEntry.data(), FALSE);
		if (list.begin()!=list.end())
		{
			//map of "single-entries" 
			m_commentsToFields.insert(comment , list);
		}
	
		//map of all possible fields
		//add everything to the map , with OVERWRITE=TRUE, so _no_ duplicate :-)
		for ( QStringList::Iterator it_fields = list.begin(); it_fields != list.end(); ++it_fields )
		{
			//the map is <key : a field>
// 			kdDebug() << "QueryFieldMetaData:: ANYTYPE KEY:"  << *(it_fields) << endl;
			allFields.insert ( *(it_fields) , "useless" );
		}
	}	
		
	// get a list of all possible fields out of the map FIXME:why use m_supportedKeys ???
	m_supportedKeys.clear();
	QMap<QString , QString>::Iterator it2;
// 	kdDebug() << "QueryFieldMetaData::slotSetupSupportedKeys ANYTYPE MAP:"  
// 			<< allFields.count() << endl;

	for (it2 = allFields.begin(); it2 != allFields.end(); ++it2)
	{
		m_supportedKeys.append( it2.key() );
	}
	
	delete d;
}

void QueryFieldMetaData::slotReloadMetaData()
{
	kdDebug() << "QueryFieldMetaData::slotReloadMetaData() CALLED.";  

	//init desktop file
	QString m_storedMetaData = locateLocal("appdata","");
	QString fileName = m_storedMetaData + "/" + "storedmedata.txt";
	KDesktopFile * d = new KDesktopFile(fileName,FALSE);

	
	d->setGroup("Mime_Comments_Icons");
	//init qmap
	m_commentToSupportedMimeType.clear();
	
	//add special "Mimetypes" . 
	//Those are easely search with clucene because mimetype ares tolenised fields
	// of the form ffffff/gggg like image/png
	QMap<QString , QString > m;
	QString l_icon;
	QString l_mime;
	QString comment;
	
	//All images
	comment = tr2i18n( "All images" );
	l_icon = "image";
	l_mime = "image";
	//don't insert here but directly in the combobox at the begining of the list
	m.insert( l_mime , l_icon );
	m_commentToSupportedMimeType.insert ( comment , m );
	m.clear();
	QString entry =  l_mime + "," + l_icon;
	d->writeEntry(comment , entry);
	
	//all sound
	comment =   tr2i18n( "All sounds" );
	l_icon = "sound";
	l_mime = "audio";
	//don't insert here but directly in the combobox at the begining of the list
	m.insert( l_mime , l_icon );
	m_commentToSupportedMimeType.insert ( comment, m );
	m.clear();
	entry =  l_mime + "," + l_icon;
	d->writeEntry(comment , entry);
	
	//All video
	comment =  tr2i18n( "All video" );
	l_icon = "video";
	l_mime = "video";
	//don't insert here but directly in the combobox at the begining of the list	
	m.insert( l_mime , l_icon );
	m_commentToSupportedMimeType.insert ( comment, m );
	m.clear();
	entry =  l_mime + "," + l_icon;
	d->writeEntry(comment , entry);
	
	
	//init automatic mimetype-plugins
	KFileMetaInfoProvider* mip = KFileMetaInfoProvider::self();
	
	//init list of all mimetypes and mimetypes-comments	
	allMimeTypes.clear();
	KMimeType::List mimeTypesList = KMimeType::allMimeTypes();
	QValueListIterator<KMimeType::Ptr> itL2(mimeTypesList.begin());
	for (; itL2 != mimeTypesList.end(); ++itL2) 
	{
		QString mimetype = (*itL2)->name();
		allMimeTypes.append(mimetype);
	}
	mimeTypesList.clear();
		//remove unwanted fields

	allMimeTypes.remove("all/all");
	allMimeTypes.remove(tr2i18n("all/allfiles"));
	//init list of mimetypes and mimetypes-comments	
// 	allMimeTypes = KFileMetaInfoProvider::self()->supportedMimeTypes();
	
	for ( QStringList::Iterator it = allMimeTypes.begin(); it != allMimeTypes.end(); ++it ) 
	{
		KMimeType::Ptr mime = KMimeType::mimeType( *(it) );
		QString comment =  mime->comment();
		QString icon = mime->icon( QString::null, true );
		QString mimeName = *(it);
		QMap<QString , QString > m;
		m.insert(mimeName ,icon );
		m_commentToSupportedMimeType.insert ( comment , m );//map comment key to  mimetype
// 		 m_mimeTypeToIcon.insert ( *(it) , mime->icon( QString::null, true ) );
		//comment()
		//pattern()
		
		//write mimetype and icons
		QString entry = mimeName + "," + icon;
		d->writeEntry(comment , entry);
	}
	

	d->setGroup("MimeComments_Fields");

	
	//build a list of all existing fields for all MetaData
	QMap<QString , QString > allFields;
	
	//
	QMap<QString, QString> allImagesKeys;
	QMap<QString, QString> allVideoKeys;
	QMap<QString, QString> allSoundKeys;

	QMap<QString , QMap<QString,QString> >::Iterator it;
	
	for ( it = m_commentToSupportedMimeType.begin(); 
		     it != m_commentToSupportedMimeType.end(); ++it ) 
	{
		//get the mimetype name from the comment iterator
		QString mimeType = it.data().begin().key();
// 		kdDebug() << "QueryFieldMetaData:: ANYTYPE MIMETYPE:"  << mimeType << endl;

		//get the list of keys from mimeType
		const KFileMimeTypeInfo* info = mip->mimeTypeInfo( mimeType );
		QStringList listSupportedKeys;
		

		if( !info )
		{
			d->writeEntry(it.key(), listSupportedKeys);
		}
		else
		{       
		
			kdDebug() << "INFO OK" << endl;         
			listSupportedKeys = info->supportedKeys();
			
			//digikam hack
			if (mimeType.startsWith("image") || mimeType.startsWith("video"))
			{
				listSupportedKeys.append("Digikamtags");
			}
			
			kdDebug() << "GROUPS: " << info->supportedGroups() << endl;         

			// hand-made plugins groups
			//All images
			if (mimeType.startsWith("image/"))
			{
				QStringList::Iterator it;
				for (it = listSupportedKeys.begin(); it != listSupportedKeys.end(); ++it)
				{
					allImagesKeys.insert(*it , "useless");
				}
			}
			else if (mimeType.startsWith("video/"))
			{
				QStringList::Iterator it;
				for (it = listSupportedKeys.begin(); it != listSupportedKeys.end(); ++it)
				{
					allVideoKeys.insert(*it , "useless");
				}
			}
			else if (mimeType.startsWith("audio/"))
			{
				QStringList::Iterator it;
				for (it = listSupportedKeys.begin(); it != listSupportedKeys.end(); ++it)
				{
					allSoundKeys.insert(*it , "useless");
				}
			}
		}

		
		d->writeEntry(it.key(), listSupportedKeys);
			// MimeTypeComment MimeType
					
		//add everything to the map , with OVERWRITE=TRUE, so _no_ duplicate :-)
		for ( QStringList::Iterator it_fields = listSupportedKeys.begin();
				    it_fields != listSupportedKeys.end(); ++it_fields )
		{
			//the map is <key : a field>
			kdDebug() << "QueryFieldMetaData:: ANYTYPE KEY:"  << *(it_fields) << endl;
			allFields.insert ( *(it_fields) , "useless" );
		}
	}	

	//find fields of groups All images and All audio...
// 	for (it2 = allSoundKeys.begin(); it2 != allSoundKeys.end(); ++it2)
// 	{
// 	}
	QStringList l;
	l = allVideoKeys.keys();
	d->writeEntry("All video", l);
	l.clear();
	l = allSoundKeys.keys();
	d->writeEntry("All sounds", l);
	l.clear();
	l = allImagesKeys.keys();
	d->writeEntry("All images", l);
	l.clear();
	
	//digikam hack
	allFields.insert ( "Digikamtags" , "useless" );
	
	// get a list out of the map FIXME:why use m_supportedKeys ???
	m_supportedKeys.clear();
	kdDebug() << "QueryFieldMetaData::slotSetupSupportedKeys ANYTYPE MAP:"  
			<< allFields.count() << endl;
	QMap<QString , QString>::Iterator it2;

	for (it2 = allFields.begin(); it2 != allFields.end(); ++it2)
	{
		m_supportedKeys.append( it2.key() );
	}
	this->supportedKeys->insertStringList(m_supportedKeys);
	
	
	d->sync();	
	delete d;
	
	
}


/*$SPECIALIZATION$*/


#include "queryfieldmetadata.moc"

