bool CmdHandler::Process( BotReceiver& rcver, std::string& line )
	{
		std::string cmd;
		size_t off = 0;
		while( off < line.length() && line[off] == ' ' )
			++ off;
		if(off == line.length())
			return true;
		std::vector<std::string> plist;
		size_t pos = line.find(' ', off);
		if(pos == std::string::npos)
		{
			cmd = std::string(line.begin() + off, line.end());
		}
		else
		{
			cmd = std::string(line.begin() + off, line.begin() + pos);
			off = pos + 1;
			Text::SeperateString(plist, line, ' ', off);
		}
		for(size_t i = 0; i < cmd.length(); ++ i)
		{
			cmd[i] = tolower(cmd[i]);
		}
		std::map<std::string, Proc_t>::iterator it = _handlers.find(cmd);
		if(it == _handlers.end())
		{
			return CmdHelp(rcver, plist);
		}
		else
		{
			Proc_t proc = it->second;
			return (this->*proc)(rcver, plist);
		}
	}
/// Perform a numeric command.
/// cmdData - The command data we're processing.
/// cmdLength - The length of the command token, so we can drop it if we need to
/// cmdID - The command number we're handling
/// crnID - The ID number of the timed event, if there is one
/// Return - Whether we did anything with it (T/F)
bool ParlourBBGame::DoCommand(QueueData &cmdData, int cmdLength, int cmdID, int crnID)
{
    if (cmdID == PFBB_CMD_STOP) /// Received a stop command.
    {
        if (cmdData.getNick() != owner) return false; /// Only the game's owner can stop the game
        AddToSendQueue("Bargain Bin now stopping. Goodbye!"); /// Say goodbye
        stopping = true; /// Announce to the core program that we're ready to stop the game
        return true;
    }

    /// Request for help; get help!
    if (cmdID == PFBB_CMD_HELP) return CmdHelp(cmdData);

    /// The remaining commands can only happen during certain game states.
    switch (state)
    {
    case PFBB_STATE_INVITE: /// During the invite phase:
        switch (cmdID)
        {
        /// Request to join game
        case PFBB_CMD_JOIN:
            return CmdJoin(cmdData);
            break;
        /// Request to start game
        case PFBB_CMD_START:
            if (cmdData.getNick() != owner) return false;
            return CmdStart(cmdData);
            break;
        /// We don't accept any other commands here, so return false. This line is present
        /// in all of our sub-switches, for safety's sake.
        default:
            return false;
            break;
        }
        break;
    case PFBB_STATE_INTURN: /// During the turn phase:
        switch (cmdID)
        {
        /// Request to play a card
        case PFBB_CMD_PLAY:
            return CmdPlay(cmdData);
            break;
        /// Request for game status
        case PFBB_CMD_STATUS:
            /// If there's no request for a specific player, get current player status
            if (cmdData.getPost().find(" ") == std::string::npos) return CmdStatus();
            /// Otherwise, send the full request to the function
            else return CmdStatus(cmdData.getPost().substr(cmdData.getPost().find(" ") + 1));
            break;

        /// Request for player's hand; always get the requester's hand
        case PFBB_CMD_HAND:
            return CmdHand(cmdData.getNick());
            break;
        /// Request for current turn
        case PFBB_CMD_TURN:
            return CmdCurTurn();
            break;
        default:
            return false;
            break; /// Catchall safety
        }
        break;

    case PFBB_STATE_ENDHAND: /// End of hand pause
        /// Timed event to end hand
        if (cmdID == PFBB_CMD_CHRONO_ENDHAND)
        {
            Tally(); /// Tally our scores
            return true;
        }
        else return false;
        break;

    case PFBB_STATE_TALLY: /// Tally phase
        /// Request to resume game
        if (cmdID == PFBB_CMD_START) return CmdStart(cmdData);
        else return false;
        break;

    default:
        return false;
        break; /// State catchall
    }

    return false; /// We did nothing; return false
}