/***************************************************************************
 *   Copyright (C) 2003 by Dan Muller                                      *
 *   dan at verliba dot cz                                                        *
 *                                                                         *
 *   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 NDIRECTCONNECTCUSERCOLLECTION_H
#define NDIRECTCONNECTCUSERCOLLECTION_H

#if defined _WIN32
namespace std{
inline unsigned long 
_Atomic_swap(unsigned long * __p, unsigned long __q) 
{
    // __gthread_mutex_lock(&_Swap_lock_struct<0>::_S_swap_lock);
    unsigned long __result = *__p;
    *__p = __q;
    // __gthread_mutex_unlock(&_Swap_lock_struct<0>::_S_swap_lock);
    return __result;
}
};
#endif

#include <string>
#include <functional>
#include "thasharray.h"

using namespace nUtils;
using std::string;
using std::unary_function;

namespace nDirectConnect {

class cUser;

/**
a structure that allows to insert and remove users, to quickly iterate and hold common sendall buffer, provides also number of sendall functions

supports: quick iterating with (restrained) constant time increment (see std::slist) , logaritmic finding, adding, removing, testing for existence.... (see std::hash_map)

@author Daniel Muller
*/

class cUserCollection : public tHashArray<cUser*>
{
public:

	/**
		Unary function foe sending Data to a user's connection
	*/
	template <class DATA_T> struct ufSend : public unary_function<void, iterator>
	{
		//Data to send
		DATA_T &mData;
		/** a constructor
			\param Data Data to be sent for to each user
		*/
		ufSend(DATA_T &Data):mData(Data){};
		/**
			\fn operator() (cUser *User)
			The sending  method
			\param User destination for sent data
		*/
		void operator() (cUser *User){ if(User && User->mInList && User->mxConn && User->mxConn->ok) User->mxConn->Send(mData, false); }
	};

	/**
		Unary function that sends DataS+Nick+DataE to every user
	*/
	template <class DATA_T> struct ufSendWithNick : public unary_function<void, iterator>
	{
		//Data to send
		DATA_T &mDataStart, &mDataEnd;

		ufSendWithNick(DATA_T &DataS,DATA_T &DataE):mDataStart(DataS), mDataEnd(DataE){};
		void operator() (cUser *User)
		{
			if(User && User->mxConn && User->mxConn->ok && User->mInList )
			{
				User->mxConn->Send(mDataStart, false);
				User->mxConn->Send(User->mNick, false);
				User->mxConn->Send(mDataEnd, true);
			}
		}
	};

	/** Unary function that constructs a nick list
	*/
	struct ufDoNickList : public unary_function<void, iterator>
	{
		ufDoNickList(string &List):mList(List){}

		void Clear() {
			mList.erase(0,mList.size());
			mList.append(mStart.data(), mStart.size());
		}
		void operator() (cUser *usr){ AppendList(mList, usr);};
		virtual void AppendList(string &List, cUser *User);

		string mStart;
		string mSep;
		string &mList;
	};

	/**
	  * Creates MyInfo List ( for the Quick list extension )
	  */
	struct ufDoINFOList : ufDoNickList
	{
		bool mComplete;
		ufDoINFOList(string &List):ufDoNickList(List), mComplete(false){mSep="|";}
		virtual void AppendList(string &List, cUser *User);
	};

	/**
	  * Creates IP List ( for the UserIP list extension )
	  */
	struct ufDoIpList : ufDoNickList
	{
		ufDoIpList(string &List):ufDoNickList(List){mSep="$$";mStart="$UserIP ";}
		virtual void AppendList(string &List, cUser *User);
	};

private:
	string mSendAllCache;
	string mNickList;
	string mINFOList;
	string mIpList;
	ufDoNickList mNickListMaker;
	ufDoINFOList mINFOListMaker;
	ufDoIpList mIpListMaker;
	bool mKeepNickList;
	bool mKeepInfoList;
	bool mRemakeNextNickList;
	bool mRemakeNextInfoList;

public:
	cUserCollection(bool KeepNickList=false, bool KeepINFOList = false);
	~cUserCollection();

	virtual int StrLog(ostream & ostr, int level);
	void SetNickListStart(const string &Start){mNickListMaker.mStart = Start;}
	void SetNickListSeparator(const string &Separator){mNickListMaker.mSep = Separator;}
	string &GetNickList();
	string &GetInfoList(bool complete=false);
	string &GetIPList();
	const char *GetNickListChar() {return GetNickList().data();}

	void   Nick2Hash(const std::string &Nick, size_t &Hash);
	size_t Nick2Hash(const std::string &Nick){string Key; Nick2Key(Nick,Key); return Key2Hash(Key); }
	void   Nick2Key (const std::string &Nick, std::string &Key);

	cUser* GetUserByKey (const string &Key ){ return GetByHash(Key2Hash(Key));}
	cUser* GetUserByNick(const string &Nick){ return GetByHash(Nick2Hash(Nick));}
	cUser* operator []  (const string &Nick){ return GetUserByNick(Nick);}

	bool   ContainsKey (const string &Key ){ return ContainsHash(Key2Hash(Key)); }
	bool   ContainsNick(const string &Nick){ return ContainsHash(Nick2Hash(Nick)); }

	bool   AddWithKey (cUser *User, const string &Key ){ return AddWithHash(User, Key2Hash(Key));}
	bool   AddWithNick(cUser *User, const string &Nick){ return AddWithHash(User, Nick2Hash(Nick)); }
	bool   Add        (cUser *User                    );

	bool   RemoveByKey (const string &Key ){ return RemoveByHash(Key2Hash(Key)); }
	bool   RemoveByNick(const string &Nick){ return RemoveByHash(Nick2Hash(Nick));}
	bool   Remove      (cUser *User       );

	void   SendToAllWithNick(string &Start, string &End);
	void   SendToAll(string &Data, bool UseCache = false, bool AddPipe=true);
	void   FlushCache();

	virtual void OnAdd(cUser *User)
	{
		if( !mRemakeNextNickList && mKeepNickList ) mNickListMaker(User);
		if( !mRemakeNextInfoList && mKeepInfoList ) mINFOListMaker(User);
	}
	virtual void OnRemove(cUser *)
	{
		mRemakeNextNickList = mKeepNickList;
		mRemakeNextInfoList = mKeepInfoList;
	}

};

/*
template <class ItemType>
class cCondIterator
{
public:
   cCondIterator() { mCur = 0; }
   virtual bool BasicStepOne() = 0;
   virtual bool IsEnd() { return mCur != 0; };
   virtual bool Advance() {
      if (BasicStepOne()) while (!Verifies() && BasicStepOne());
      return !IsEnd();
   }
   virtual bool Verifies() = 0;
   ItemType mCur;
};

class cUserRangeIterator() : public cCondIterator<cUser*>
{
public:

   cUserRangeIterator(const string &MinIP, const string &MaxIP)
   {
      mMinIP = cBanList::Ip2Num(MinIP);
      mMaxIP = cBanList::Ip2Num(MaxIP);
   }
   
   virtual bool Verifies() {
      if (mCur && mCur->mxConn) {
         long ip = cBanlist::Ip2Num(mCur->mxConn->AddrIP());
         return (ip <= mMaxIP) && (ip >= mMinIP);
      } else return false;
   }

   long mMinIP;
   long mMaxIP;
};
*/
};

#endif
