/**
 * LISTCommand.cc
 * Gives list of all kind of stuff to the oper
 *
 * 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.
 *
 * $Id: LISTCommand.cc,v 1.24 2008/08/06 19:35:58 hidden1 Exp $
 */

#include	<string>
#include        <iomanip>

#include	<cstdlib>

#include	"ccontrol.h"
#include	"Network.h"
#include	"Channel.h"
#include	"CControlCommands.h"
#include	"StringTokenizer.h"
#include	"gnuworld_config.h"

RCSTAG( "$Id: LISTCommand.cc,v 1.24 2008/08/06 19:35:58 hidden1 Exp $" ) ;

namespace gnuworld
{

using std::string ;

namespace uworld
{

bool LISTCommand::Exec( iClient* theClient, const string& Message)
{	 
typedef list<const Channel*> channelListT;
const Channel* curChannel;
channelListT channelList;
unsigned int count = 0;
const char *c;
char ch;
string Mask;
bool isValid = false;

StringTokenizer st( Message ) ;
if(st.size() < 2)
	{
	Usage(theClient);
	return true;
	}

bot->MsgChanLog("LIST %s\n",st.assemble(1).c_str());
if(!strcasecmp(st[1].c_str(),"glines"))
	{
	bot->listGlines(theClient);
	}
else if(!strcasecmp(st[1].c_str(),"suspended"))
	{
	bot->listSuspended(theClient);
	}
else if(!strcasecmp(st[1].c_str(),"servers"))
	{
	bot->listServers(theClient);
	}
else if(!strcasecmp(st[1].c_str(),"badchannels"))
	{
	bot->Notice(theClient,"Please use LIST nomodechannels to get a list of the channels which are marked as no mode");
	}
else if(!strcasecmp(st[1].c_str(),"nomodechannels"))
	{
	bot->listBadChannels(theClient);
	}
else if(!strcasecmp(st[1].c_str(),"exceptions"))
	{
	bot->listExceptions(theClient);
	}
else if(!strcasecmp(st[1].c_str(),"channels"))
	{
		/* new "list channels" command */
		if (st.size() < 3)
		{
			/* not enough parameters */
#ifdef TOPIC_TRACK
			bot->Notice(theClient, "'list channels' requires 'key', 'modes', 'topic' or 'topicby'");
#else
			bot->Notice(theClient, "'list channels' requires 'key' or 'modes'");
#endif
			return false;
		}
		if (!strcasecmp(st[2].c_str(),"key"))
		{
			if (st.size() < 4)
			{
				bot->Notice(theClient, "for 'list channels key', you must supply the key to search for!");
				return false;
			}
			/* ok, we have the key to search for in st[3] */
			channelList = Network->getChannelsWithKey(st[3]);

			if (channelList.empty())
			{
				bot->Notice(theClient, "I'm sorry, no channels have a key matching '%s'", st[3].c_str());
				return false;
			}

			bot->Notice(theClient, "--==[ Channels matching key '%s' %s]==--", st[3].c_str(),
				(channelList.size() > 15)?"- showing first 15 only":"");

			for (channelListT::iterator cptr = channelList.begin(); (cptr != channelList.end()) && (count < 15); cptr++)
			{
				curChannel = *cptr;
				bot->Notice(theClient, "Channel: [%4d] %s", 
					curChannel->size(),
					curChannel->getName().c_str());
				count++;
			}
			bot->Notice(theClient, "--==[ End of 'list channels key %s' - %d found ]==--",
				st[3].c_str(), channelList.size());
		}
		else if (!strcasecmp(st[2].c_str(),"modes"))
		{
			if (st.size() < 4)
			{
				bot->Notice(theClient, "for 'list channels modes', you must supply the modes to match against!");
				bot->Notice(theClient, "e.g. 'list channels modes +tns-m' to require +tns and require not to have +m");
				bot->Notice(theClient, "(other modes may be set unless explicitly not required as above)");
				return false;
			}
			if ((st.size() > 4) && (string_lower(st[4]) != "-size"))
			{
					bot->Notice(theClient, "You supplied too many arguments.  arguments such as +k or +l here may not contain the key or limit!");
					return false;
			}
			/* ok, we have the modes to search for in st[3] - validate them */
			if ((!match("+", st[3].substr(0,1))) && (!match("-", st[3].substr(0,1))))
			{
				bot->Notice(theClient, "The modes must start with + or - (e.g. +tns or -s)");
				return false;
			}
			isValid = true;
			c = st[3].c_str();
			while ((ch = *c++))
			{
				switch (ch) {
					case '+':
					case '-':
					case 'k':
					case 'l':
					case 'i':
					case 'm':
					case 'n':
					case 'p':
					case 's':
					case 't':
					case 'r':
					case 'D':	/* acceptable modes */
							break;
					default:	/* unacceptable modes */
							isValid = false;
							break;
				}
			}
			if (!isValid)
			{
				bot->Notice(theClient, "The modes given are invalid (you supplied '%s', valid modes are klimnpstrD)",
					st[3].c_str());
				return false;
			}
			/* ok, validated them */
			channelList = Network->getChannelsWithModes(st[3]);

			if (channelList.empty())
			{
				bot->Notice(theClient, "I'm sorry, no channels have modes matching '%s'", st[3].c_str());
				return false;
			}

			int maxListChannels = bot->getMaxListChannels();
			if (maxListChannels > 0)
				bot->Notice(theClient, "--==[ Channels matching modes '%s' - showing first %i only]==--",
						st[3].c_str(),maxListChannels);
			else
				bot->Notice(theClient, "--==[ Channels matching modes '%s' Showing All]==--", st[3].c_str());

			/*if (string_lower(st[4]) == "-size")
			{
				//std::vector<std::pair<size_t, const string> > indexList;
				std::list<std::pair<size_t, const string> > indexList;
				for (channelListT::iterator cptr = channelList.begin(); (cptr != channelList.end()); cptr++)
				{
					curChannel = *cptr;
					indexList.push_back(std::make_pair(curChannel->size(),curChannel->getName().c_str()));
				}
				//std::sort(indexList.begin(), indexList.end());
				//for (size_t i = indexList.size() - 1; i >= 0; i--)
				//for (std::vector<std::pair<size_t, const string> >::iterator it = indexList.end(); it >= indexList.begin(); it--)
				//	bot->Notice(theClient, "Channel: [%4d] %s",
				//		indexList.at(i).first,
				//		indexList.at(i).second.c_str());
				indexList.sort();
				//for (list<std::pair<size_t, const string> >::iterator it = indexList.end(); it != indexList.begin(); it--)
				for (list<std::pair<size_t, const string> >::iterator it = indexList.begin(); it != indexList.end(); it++)
					bot->Notice(theClient, "Channel: [%4d] %s",
						it->first,
						it->second.c_str());
			}
			else
			*/for (channelListT::iterator cptr = channelList.begin(); (cptr != channelList.end()); cptr++)
			{
				curChannel = *cptr;
				bot->Notice(theClient, "Channel: [%4d] %s",
					curChannel->size(),
					curChannel->getName().c_str());
				count++;
				if ((count >= maxListChannels) && (maxListChannels > 0))
					break;
			}
			bot->Notice(theClient, "--==[ End of 'list channels modes %s' - %d found ]==--",
				st[3].c_str(), channelList.size());
		}
#ifdef TOPIC_TRACK
		else if (!strcasecmp(st[2].c_str(),"topic"))
		{
			if (st.size() < 4)
			{
				bot->Notice(theClient, "for 'list channels topic', you must supply the topic to search for!");
				return false;
			}
			/* ok, we have the topic to search for in st[3] */
			channelList = Network->getChannelsWithTopic(st[3]);

			if (channelList.empty())
			{
				bot->Notice(theClient, "I'm sorry, no channels have a topic matching '%s'", st[3].c_str());
				return false;
			}

			bot->Notice(theClient, "--==[ Channels matching topic '%s' %s]==--", st[3].c_str(),
				(channelList.size() > 15)?"- showing first 15 only":"");

			for (channelListT::iterator cptr = channelList.begin(); (cptr != channelList.end()) && (count < 15); cptr++)
			{
				curChannel = *cptr;
				bot->Notice(theClient, "Channel: [%4d] %s",
					curChannel->size(),
					curChannel->getName().c_str());
				count++;
			}
			bot->Notice(theClient, "--==[ End of 'list channels topic '%s' - %d found ]==--",
				st[3].c_str(), channelList.size());
		}
		else if (!strcasecmp(st[2].c_str(),"topicby"))
		{
			if (st.size() < 4)
			{
				bot->Notice(theClient, "for 'list channels topicby', you must supply the nick!user@host mask to search for!");
				return false;
			}
			/* validate the nick!user@host */
			string::size_type atPos = st[3].find_first_of('!');
			if (string::npos == atPos)
			{
				/* not in nick!user@host format */
				/* assume they want to check nick only, but tell them just in case */
				Mask = "";
				Mask += st[3].c_str();
				Mask += "!*@*";
				bot->Notice(theClient, "Mask was not in nick!user@host format, re-writing mask to '%s'.  This may not be what you want!",
					Mask.c_str());
			} else {
				/* we have nick!..., check for user@host! */
				string::size_type atPos2 = st[3].find_first_of('@');
				if ((string::npos == atPos2) || (atPos2 < atPos))
				{
					/* either no '@' or it's before the first '!' */
					/* assume they want to check nick!user only, but tell them just in case */
					Mask = "";
					Mask += st[3].c_str();
					/* if the '!' is at the end of the line, we need to add a * */
					if (atPos == (st[3].length()-1))
						Mask += "*";
					Mask += "@*";
					bot->Notice(theClient, "Mask was not in nick!user@host format, re-writing mask to '%s'.  This may not be what you want!",
						Mask.c_str());
				} else {
					/* we have a full nick!user@host - we dont need to alter it */
					Mask = st[3].c_str();
				}
			}
			/* ok, we have a valid topicby to search for in Mask */
			channelList = Network->getChannelsWithTopicBy(Mask);

			if (channelList.empty())
			{
				bot->Notice(theClient, "I'm sorry, no channels have a topic matching '%s'", Mask.c_str());
				return false;
			}

			bot->Notice(theClient, "--==[ Channels with topics set by '%s' %s]==--", Mask.c_str(),
				(channelList.size() > 15)?"- showing first 15 only":"");

			for (channelListT::iterator cptr = channelList.begin(); (cptr != channelList.end()) && (count < 15); cptr++)
			{
				curChannel = *cptr;
				bot->Notice(theClient, "Channel: [%4d] %s",
					curChannel->size(),
					curChannel->getName().c_str());
				count++;
			}
			bot->Notice(theClient, "--==[ End of 'list channels topicby '%s' - %d found ]==--",
				Mask.c_str(), channelList.size());
		} else {
			bot->Notice(theClient,"'list channels' requires 'key', 'modes', 'topic' or 'topicby'");
			return false;
#else
		else {
			bot->Notice(theClient,"'list channels' requires 'key' or 'modes'");
			return false;
#endif
		}
	}
else
	{
	bot->Notice(theClient,"Unknown list type - see HELP");
	}

return true ;
}

}
}

