/***************************************************************************
 *   Copyright (C) 2005 by xavier helluy                                   *
 *   xavier.helluy@web.de                                                  *
 *   dbera.web@gmail.com                                                   *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "beaglethread.h"
#include <dcopobject.h>
#include <dcopclient.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qapplication.h>

#include <kdebug.h>

QString get_uri_from_file_hit(BeagleHit *hit)
{
	return QString (beagle_hit_get_uri (hit));
}

QString get_uri_from_feed_hit(BeagleHit *hit)
{
	return QString ("not implemented");
	//return QString (beagle_hit_get_property (hit, "fixme:itemuri"));
}

BeagleThread::BeagleThread(	QObject * o , const QString & query , QString  socketPath  ,
 			QDict <ClientList> * QueryList  ,
			const bool & peer2peer):SearchThread (o, query, socketPath, QueryList, peer2peer)
{
	kdDebug() << "BeagleThread::BeagleThread  - m_socketPath : " <<  m_socketPath << endl;
	
	m_queryList = QueryList;
	g_type_init ();
	m_beagleClient = beagle_client_new (NULL);
	if (m_beagleClient == NULL)
		throw -2;
	kdDebug() << "Creating beagleclient" << endl;
}

BeagleThread::~BeagleThread()
{
    kdDebug() << "Removing beagleclient" << endl;
    g_object_unref (m_beagleClient);

}

void BeagleThread::run()
{
	
	//QString results_type could allow to return error messages
	BeagleQuery *m_beagle_query = beagle_query_new ();
	beagle_query_add_text (m_beagle_query, m_query);
	kdDebug () << "Added query:[" << m_query << "]" << endl;

	GError *err = NULL;
	
	g_signal_connect (m_beagle_query, "hits-added",
		  G_CALLBACK (hits_added_cb),
		  this);

	g_signal_connect (m_beagle_query, "finished",
		  G_CALLBACK (finished_cb),
		  this);
	m_mainloop = g_main_loop_new (NULL, FALSE);
	kdDebug() << "BeagleThread: creating mainloop" << endl;
	beagle_client_send_request_async (m_beagleClient, BEAGLE_REQUEST (m_beagle_query),
				  &err);
	if (err) {
		kdDebug() << "-------- err:" << err->message << endl;
		std::string err_msg (err->message);
		g_error_free (err);
		kdDebug() << "BeagleThread: Error in searching! quitting mainloop" << endl;
		g_main_loop_quit (m_mainloop);
		throw err_msg;
	}

	g_main_loop_run (m_mainloop);
	kdDebug() << "BeagleThread: Phew! mainloop over" << endl;
	g_main_loop_unref (m_mainloop);
	
}

void BeagleThread::encodeHits( void *hit_list )
{
	GSList *hits = (GSList *) hit_list;
	QString results;
	kdDebug() << "BeagleThread::search There are  " << g_slist_length (hits) << " results " << endl;

	GSList *l;
	gint i;
	for ( i=0, l=hits; l;i++, l=l->next)
	{
		BeagleHit *hit = BEAGLE_HIT (l->data);
		const char *hit_type = beagle_hit_get_type (hit);
		kdDebug() << "BeagleThread::search  i=" << i << "hit=" << hit_type << endl;
		// the only thing beagle backend can provide is the title (for relevant hits)
		// and url
		// title only makes sense for
		//     1. webhistory
		//     2. feeditem
		if (strcmp (hit_type, "FeedItem") == 0) {
			const char *url_value;
			if (beagle_hit_get_one_property (hit, "dc:identifier", & url_value) == FALSE)
				continue;
			m_resultsList.append ( QString (url_value));
			const char *name_value;
			if (beagle_hit_get_one_property (hit, "dc:title", & name_value) == FALSE)
				m_resultsDisplay.append ( QString (url_value));
			else
				m_resultsDisplay.append ( QString (name_value));
			m_resultsMimeType.append( "text/html" );
			
		} else if (strcmp (hit_type, "WebHistory") == 0) {
			m_resultsList.append (QString (beagle_hit_get_uri (hit)));
			const char *name;
			if (beagle_hit_get_one_property (hit, "dc:title", &name) == FALSE)
				m_resultsDisplay.append ( QString (beagle_hit_get_uri (hit)));
			else
				m_resultsDisplay.append ( QString (name));
			m_resultsMimeType.append( "text/html" );
			
	        } else if (strcmp (hit_type, "MailMessage") == 0) {
			const char *parent_uri = beagle_hit_get_parent_uri (hit);
			char *title_key;
			const char *title_value;
			if (parent_uri != NULL) {
				m_resultsList.append ( QString (parent_uri));
				title_key = "parent:dc:title";
			} else {
				m_resultsList.append ( QString (beagle_hit_get_uri (hit)));
				title_key = "dc:title";
			}
			if (beagle_hit_get_one_property (hit, title_key, &title_value) == FALSE)
				m_resultsDisplay.append ("No subject");
			else
				m_resultsDisplay.append ( QString (title_value));
			m_resultsMimeType.append( "message/rfc822" );
			
		} else if (strcmp (hit_type, "File") == 0) {
	               	m_resultsList.append ( QString (beagle_hit_get_uri (hit)));
			const char *name;
			if (beagle_hit_get_one_property (hit, "beagle:ExactFilename", &name) == FALSE)
				m_resultsDisplay.append (QString (beagle_hit_get_uri (hit)));
			else
				m_resultsDisplay.append (QString (name));
			m_resultsMimeType.append( QString (beagle_hit_get_mime_type(hit)));
		} else // drop the results as of now - dont know what to display
			continue;	
		    

		m_resultsModTime.append	    ( "" ); // empty string - FIXME: pass timestamp ?
		m_resultsMode.append	    ( "" ); // empty string
		m_resultsSize.append	    ( "" ); // empty string
		m_resultsStoredPreview.append ( "" ); // empty string	
	}
		
	kdDebug() << "BeagleThread::runMultiIndexQuery done" << endl;
	
// 	in << (QStringList) resultsItem;

}

void hits_added_cb(BeagleQuery *query, BeagleHitsAddedResponse *response, BeagleThread *thread)
{
	kdDebug() << "BeagleThread: Hits added!" << endl;
	if (thread != NULL)
		thread->hitsAddedCallback ( query, response);
}

void BeagleThread::hitsAddedCallback (BeagleQuery *query, BeagleHitsAddedResponse *response) 
{
	kdDebug() << "BeagleThread: thread->hitsAddedCallback" << endl;
	GSList *hits, *l;
	gint    i;
	gint    nr_hits;
	
	hits = beagle_hits_added_response_get_hits (response);
	encodeHits (hits);
}

void finished_cb (BeagleQuery *query, BeagleFinishedResponse *response, BeagleThread *thread)
{
	kdDebug() << "BeagleThread: search finished!" << endl;
	if (thread != NULL) {
		g_main_loop_quit (thread->m_mainloop);
		thread->searchFinishedCallback (query, response);
	}
}

void BeagleThread::searchFinishedCallback(BeagleQuery *query, BeagleFinishedResponse *response)
{
	kdDebug() << "BeagleThread: thread->searchFinishedCallback" << endl;

	g_object_unref (query);

	QDataStream in(m_byteResults, IO_WriteOnly);
	in << (QStringList) m_resultsList;
	kdDebug() << "BeagleThread::runMultiIndexQuery m_resultsDisplay " << m_resultsDisplay.count() << endl;
	in << (QStringList) m_resultsDisplay;
	kdDebug() << "BeagleThread::runMultiIndexQuery m_resultsMimeType " << m_resultsMimeType.count()<< endl;
	in << (QStringList) m_resultsMimeType;
	kdDebug() << "BeagleThread::runMultiIndexQuery  m_resultsModTime " << m_resultsModTime.count()<< endl;
	in << (QStringList) m_resultsModTime;
	kdDebug() << "BeagleThread::runMultiIndexQuery  m_resultsMode " << m_resultsMode.count()<< endl;
	in << (QStringList) m_resultsMode;
	kdDebug() << "BeagleThread::runMultiIndexQuery  m_resultsSize " << m_resultsSize.count()<< endl;
	in << (QStringList) m_resultsSize;
	kdDebug() << "BeagleThread::runMultiIndexQuery  m_resultsStoredPreview " << m_resultsStoredPreview.count()<< endl;
	in << (QStringList) m_resultsStoredPreview;

	runTransfer( m_socketPath , m_byteResults );
	
	//deregister the client-socket associated to this query
	//QDict<ClientList>  QueryList[newQuery]->insert( SocketPath , new int(1)); // int value is egal
	mutex.lock();
	m_queryList->find(m_query)->remove(m_socketPath); 
	mutex.unlock();
	
	//process queued same queries	
	while (	!( m_queryList->find(m_query)->isEmpty() ) )
	{
		QDictIterator<int>  ClientIt( *(m_queryList->find(m_query)) ); // init at begin
		kdDebug() << "BeagleThread::run Processing Queued Query " << ClientIt.currentKey() << endl;

		runTransfer( ClientIt.currentKey()  , m_byteResults );
		
		mutex.lock();
		m_queryList->find(m_query)->remove( ClientIt.currentKey() ); //this will increment the iterator
		mutex.unlock();
	}

	// cleanup m_byteResults, and other lists
	m_resultsList.clear ();
	m_resultsDisplay.clear ();
	m_resultsMimeType.clear ();
	m_resultsModTime.clear ();
	m_resultsMode.clear ();
	m_resultsSize.clear ();
	m_resultsStoredPreview.clear ();
	m_byteResults.resize (0);
	
	//sends finished customEvent telling that all queries m_query have been processed
	//the cleaning will be done later when the event will be received
	QCustomEvent *event = new QCustomEvent(12346); //number is random !!! > XXX
	event->setData(new QString(m_query));
	QApplication::postEvent(m_receiver, event);
}
