/***************************************************************************
                          csearchmanager.h  -  description
                             -------------------
    begin                : Thu May 27 2004
    copyright            : (C) 2004 by Mathias Küster
    email                : mathen@users.berlios.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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef CSEARCHMANAGER_H
#define CSEARCHMANAGER_H

/**
  *@author Mathias Küster
  *
  * This whole class is mainly designed for automatically entering, doing
  * the search, and leaving, hubs, from some list. I doubt any other
  * client does this nor any hub would want this behaviour.
  *
  * What this class can not do is match search results to searches, nor can
  * it manage a changing list of searches. Results are either sent to
  * CDownloadManager for auto searches or via a single callback to one
  * search window. There is a list of searches, but that can only be set
  * when starting the search.
  *
  * Valknut may have been modified to allow more than one search window
  * but it does not allow more than one search to be running at a time.
  */

#include <time.h>

#include <dclib/dcos.h>
#include <dclib/core/cstring.h>
#include <dclib/core/cconnection.h>
#include <dclib/core/csingleton.h>
#include <dclib/cclient.h>
#include <dclib/csearchsocket.h>
#include <dclib/core/cstringlist.h>
#include <dclib/core/ccallback.h>

/** */
class CSearchClient : public CClient {
public:
	/** */
	CSearchClient() {
		m_bSearchRemove = false;
		m_bSearchEnable = false;
		m_pCurrentSearchObject = 0;
		m_tSearchTimeout = 0;
	};
	/** */
	virtual ~CSearchClient() {};

	/** */
	bool m_bSearchRemove;
	/** */
	bool m_bSearchEnable;
	/** */
	time_t m_tSearchTimeout;
	/** */
	CDCMessage * m_pCurrentSearchObject;
};

/** search modes */
enum eSearchMode {
	esmCONNECTEDSINGLE = 0,
	esmCONNECTEDALL,
	esmPUBLIC,
	esmBOOKMARK
};

enum eSearchState {
	esNONE = 0,
	esSEARCH,
	esTIMEOUT,
	esSTOP
};

/** */
enum eSearchError {
	eseNONE = 0,
	eseALREADYRUN
};

/** */
enum eSearchType {
	estyNONE = 0,
	estySINGLE,
	estyMULTI,
	estyEXTERNAL
};

/** */
class CSearchManager : public CSingleton<CSearchManager> {
public:
	/** */
	CSearchManager();
	/** */
	virtual ~CSearchManager();

	/** */
	int CallBackManager();
	/** */
	int CallBackClient( CClient * Client, CDCMessage * DCMessage );
	/** */
	int CallBackSearchSocket( CMessageSearchResult* );

	/** */
	eSearchError StartSearch( eSearchMode mode, eSearchType type, CList<CDCMessage> * querylist, CStringList<CString> * serverlist );
	/** */
	void StopSearch();

	/** */
	bool HandleSearch( CDCMessage * message );

	/** */
	enum eSearchType SearchType() { return m_eSearchType; }
	/** */
	long MaxClients() { return m_nMaxClients; }
	/** */
	void MaxClients( long n ) { m_nMaxClients = n; }
	/** */
	void EnableTag( bool b ) { m_bEnableTag = b; }

	/** */
	bool IsSearch() { return (m_eSearchType != estyNONE); }

	/** */
	eSearchState SearchState() { eSearchState e; m_Mutex.Lock(); e = m_eSearchState; m_Mutex.UnLock(); return e; }
	/** */
	void SearchState( eSearchState e ) { m_Mutex.Lock(); m_eSearchState = e; m_Mutex.UnLock(); }

	/** */
	void SetCallBackFunction( _CCallback1<CDCMessage*> * callback );
	/** */
	_CCallback1<CDCMessage*> * GetCallBackFunction();
	
	/** */
	time_t StartTime() { return m_tStartTime; };
	/** */
	long HubCount();
	/** */
	long HubIndex() { return m_nHubIndex; };
	/** */
	long HubError() { return m_nHubError; };
	
protected:

private:
	/** */
	bool AddClients();
	/** */
	bool AddClient();
	/** */
	void UpdateClients();
	/** */
	bool RemoveClients();
	/** */
	void DisconnectClients();
	/** */
	bool DoSearch( CSearchClient * HubSearchClient );
	/** */
	bool SendObject( CDCMessage * DCMessage );
	
	/** manager callback */
	_CCallback0 * m_pCallback;
	/** */
	CMutex m_Mutex;
	/** client list */
	CList<CSearchClient> * m_pClientList;

	/** max simultan clients */
	long m_nMaxClients;
	/** current hub index */
	long m_nHubIndex;
	/** hub with errors */
	long m_nHubError;
	/** current hub */
	CString * m_sCurrentHub;
	
	/** hub list */
	CStringList<CString> * m_pHubList;
	/** */
	CList<CDCMessage> * m_pSearchList;
	/** only for passive searches */
	CDCMessage * m_pCurrentSearchObject;

	/** */
	bool m_bEnableTag;
	/** */
	bool m_bHandleUserList;

	/** */
	CSearchSocket m_SearchSocket;

	/** starttime */
	time_t m_tStartTime;
	/** timeout */
	time_t m_tTimeoutTime;

	/** search type */
	enum eSearchType m_eSearchType;
	/** search state */
	enum eSearchState m_eSearchState;
	/** search mode */
	enum eSearchMode m_eSearchMode;
	/** client mode */
	enum eClientMode m_eClientMode;

	/** callback function */
	_CCallback1<CDCMessage*> * m_pParentCallback;
	/** mutex for changing callback */
	CMutex m_CallbackMutex;
};

/** */
inline void CSearchManager::SetCallBackFunction( _CCallback1<CDCMessage*> * callback )
{ m_CallbackMutex.Lock(); m_pParentCallback = callback; m_CallbackMutex.UnLock(); }
/** */
inline _CCallback1<CDCMessage*> * CSearchManager::GetCallBackFunction()
{ return m_pParentCallback; }

#endif
