/***************************************************************************
 *   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 "kclucenethread.h"
#include <dcopobject.h>
#include <dcopclient.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qapplication.h>
#include <kurl.h>
#include <kdebug.h>

//highlight
// #include "..\contributions\highlighter\QueryTermExtractor.h"
// #include "..\contributions\highlighter\QueryScorer.h"
// #include "..\contributions\highlighter\Highlighter.h"
// #include "..\contributions\highlighter\SimpleHTMLFormatter.h"



KCLuceneThread::KCLuceneThread(	QObject * o , const QString & query , QString  socketPath  ,
 			QDict <ClientList> * QueryList  ,
			KCLuceneDaemon kclucenedaemon,
			QStringList indexesPathList,
			const bool & peer2peer) 
	:
		    SearchThread (o, query, socketPath, QueryList, peer2peer),
		    m_indexesPathList(indexesPathList),
		    m_indexSingleSearchersList(kclucenedaemon.m_indexSingleSearchersList),
		    m_indexMultiSearchersList(kclucenedaemon.m_indexMultiSearchersList)
			    
{
	kdDebug() << "KCLuceneThread::KCLuceneThread  - m_socketPath : " <<  m_socketPath << endl;
	
	m_queryList = QueryList;
}

KCLuceneThread::~KCLuceneThread()
{
    terminate();
    wait();

}

// the next lucene specific functions from latest SVN were not compiling
// copied from kio-clucene-0.1.0 release
// ************** CHANGE THEM TO RECENT SVN ***********************

void KCLuceneThread::run()
{
	
	//QString results_type could allow to return error messages
	//FIXME TODO tests that the list of indexes points to existing and valid indexes
	bool multiIndex = FALSE;
	if (m_indexesPathList.count()==1)
	{
		multiIndex = FALSE;
		runMultiIndexQuery(multiIndex);
	}
	else if (m_indexesPathList.count() >1)
	{
		kdDebug() << "MyThread2::run THREAD: MULTI-INDEX SEARCH STARTED" << endl;
		multiIndex = TRUE;
		runMultiIndexQuery(multiIndex);
	}
	else
	{
		kdDebug() << "MyThread2::run THREAD: EMPTY LIST OF INDEX" << endl;
		kdWarning() << "MyThread2::run NO INDEX PATH GIVEN" << endl;		
	}
	
	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() << "MyThread2::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();
	}
	
	//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);
// 	terminate();
// 	wait();
}

void KCLuceneThread::runMultiIndexQuery(bool multiIndex)
{

	// QueryParser : NOT THREAD-SAFE !! so init here and not in main
	/*
	WARNING: the analyser used for searching indexes should be the same as the one 
	used to build the database !
	*/
	standard::StandardAnalyzer analyzer;  //FIXME: is it THREAD-SAFE ???
	char_t * input = (char*) (const char*) (m_query).latin1();//FIXME:same UNICODE problem
	
	const char_t* buf;
	
	Query& q = lucene::queryParser::QueryParser::Parse(input , _T("contents"),analyzer);
	buf = q.toString(_T("contents"));
	
	kdDebug() << "MyThread2::runMultiIndexQuery _ query is : " << buf << endl;
	delete[] buf;
	
	Hits * h;
	lucene::search::MultiSearcher * s = 0;
	if (multiIndex == FALSE)
	{
		kdDebug() << "MyThread2::runMultiIndexQuery START SINGLESEARCH" << endl;
		//start a single index search
		h = &(m_indexSingleSearchersList[*(m_indexesPathList.begin())]->search(q));
				kdDebug() << "MyThread2::runMultiIndexQuery START SINGLESEARCH BBBB" << endl;

	}
	else
	{
		kdDebug() << "MyThread2::runMultiIndexQuery START MULTISEARCH" << endl;

		//start a multiIndex search
		// ---- build the array of IndexSearchers
		// FIXME:this should be done in MAIN , not HERE
		pointerToSearcher*  myarray = new  pointerToSearcher[m_indexesPathList.count()];
	
		int count=0;
		for ( QStringList::Iterator it = m_indexesPathList.begin(); it != m_indexesPathList.end(); ++it )
		{
			kdDebug() << "MyThread2::runMultiIndexQuery ADDING INDEX" << *it <<  endl;
			kdDebug() << "MyThread2::runMultiIndexQuery ADDING INDEX" << m_indexSingleSearchersList.find(*it) <<  endl;

			myarray[count] = m_indexSingleSearchersList.find(*it);
			count++;
		}
		kdDebug() << "MyThread2::runMultiIndexQuery BEFORE SEARCH" << endl;
		//FIXME: search limit
		s = new lucene::search::MultiSearcher(myarray , m_indexesPathList.count());
		kdDebug() << "MyThread2::runMultiIndexQuery AFTER CREATING MULTIINDEX" <<  endl;
		h = &( s->search(q) );
 		
 		kdDebug() << "MyThread2::runMultiIndexQuery AFTER SEARCH" << endl;

 		// FIXME: LEAK  ??
//  		delete[] myarray;
	}
	
	//encode results
	if ( h->Length() > 0 );
	{
		encodeHits( h );
	}
	
	//cleaning
	kdDebug() << "MyThread2::runMultiIndexQuery NOT DELETING hits" <<  endl;
// 	delete h;
	
	delete &q;
	if ( s != 0 )
	{
		delete s;	
		s = 0;
	}
}

void KCLuceneThread::encodeHits( lucene::search::Hits * h )
{
	QString results;
	QStringList resultsList;
	QStringList resultsDisplay;
	QStringList resultsMimeType;
	QStringList resultsModTime;
	QStringList resultsMode;
	QStringList resultsSize;
	QStringList resultsStoredPreview;
// 	QStringList resultsItem;
	kdDebug() << "MyThread2::runMultiIndexQuery There are  " << h->Length() << " results " << endl;

	for ( int_t i=0;i < h->Length();i++)
	{
		kdDebug() << "MyThread2::runMultiIndexQuery  i=" << i  << endl;

		lucene::document::Document& doc = (*h).doc(i);
// 		std::stringstream stream;
		
		QString urlkey = doc.get(_T("URLKey"));
		//separate URL value from mediaType and MediaName
		QStringList list = QStringList::split(  "/", urlkey ,TRUE);
		QString media;
		media.append(list.first() + "-");
		list.remove(list.begin());
		media.append(list.first());
		//only remove first element pointed by iterator do NOT use first() !!!
		list.remove(list.begin());
		QString url = list.join("/");
		
		KURL myU = KURL::fromPathOrURL(url);
		QString dir = myU.directory();
		QString filename= myU.fileName();
		
		//get the display name to be used for this url
		const QString name = filename + " , " + " " + media + dir ;

		resultsList.append    ( myU.pathOrURL());
		resultsDisplay.append ( name );
		resultsMimeType.append( doc.get(_T("mimetype"     ) ) );	
		resultsModTime.append ( doc.get(_T("ModTimeIntKey") ) );
		resultsMode.append    ( doc.get(_T("Mode_T"       ) ) );
		resultsSize.append    ( doc.get(_T("FileSize"     ) ) );
		//FIXME:someday get read of this StoredPreview field. Add indexLocation to URL ???
		resultsStoredPreview.append(doc.get(_T("StoredPreview" ) ) );
// 		resultsItem.append    ( doc.get(_T("KFileItem"     ) ) );

		kdDebug() << "MyThread2::runMultiIndexQuery  Res[" << i << "] = " << doc.get(_T("URLKey")) << endl;
	}
	
	QDataStream in(m_byteResults, IO_WriteOnly);
	in << (QStringList) resultsList;
	in << (QStringList) resultsDisplay;
	kdDebug() << "MyThread2::runMultiIndexQuery resultsMimeType " << resultsMimeType.count()<< endl;
	in << (QStringList) resultsMimeType;
	kdDebug() << "MyThread2::runMultiIndexQuery  resultsModTime" << resultsModTime.count()<< endl;
	in << (QStringList) resultsModTime;
	kdDebug() << "MyThread2::runMultiIndexQuery  resultsMode" << resultsMode.count()<< endl;
	in << (QStringList) resultsMode;
	kdDebug() << "MyThread2::runMultiIndexQuery  resultsSize" << resultsSize.count()<< endl;
	in << (QStringList) resultsSize;
	kdDebug() << "MyThread2::runMultiIndexQuery  resultsStoredPreview" << resultsStoredPreview.count()<< endl;
	in << (QStringList) resultsStoredPreview;
	kdDebug() << "MyThread2::runMultiIndexQuery  resultsStoredPreview" << resultsStoredPreview<< endl;
	
// 	in << (QStringList) resultsItem;

}

// KCLuceneThread::doHighLigthing()
// {
// 	const int FRAGMENT_SIZE = 400;
// 	SimpleAnalyzer analyzer;
// 
// 	Highlighter highlighter( new SimpleHTMLFormatter(_T("<b>"), _T("</b>")),
// 				 new QueryScorer(query.get()), 
// 				 new SimpleFragmenter(FRAGMENT_SIZE));
// 	//need afieldname and a reader
// 	TokenStream& ts = analyzer.tokenStream(_T("contents"), &r);
// 	
// 	TCHAR * highlighted_text = highlighter.getBestFragments(&ts, test_texts[j], 2, _T("..."));
// 	
// 	
// }




