/*
* guildmanager.cpp
*
* Copyright (C) 2003 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) 
*
*
* 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 (version 2 of the License)
* 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.
*
*/


#include <psconfig.h>

#include <string.h>
#include <memory.h>
#include <csutil/xmltiny.h>
#include <physicallayer/entity.h>
#include <propclass/mesh.h>

#include "client.h"
#include "clients.h"
#include "util/serverconsole.h"
#include "util/psstring.h"
#include "util/psxmlparser.h"
#include "util/eventmanager.h"
#include "util/psdatabase.h"        // Database
#include "gem.h"
#include "playergroup.h"
#include "guildmanager.h"
#include "cachemanager.h"
#include "util/pserror.h"
#include "util/log.h"
#include "util/psconst.h"
#include "globals.h"

#include "psserver.h"
#include "bulkobjects/pscharacter.h"
#include "bulkobjects/pscharacterloader.h"
#include "bulkobjects/pssectorinfo.h"
#include "bulkobjects/psaccountinfo.h"
#include "chatmanager.h"
#include "netmanager.h"



class PendingGuildInvite : public PendingInvite
{
public:
    int guildID;

    PendingGuildInvite(Client *inviter,
                       Client *invitee,
                       const char *question,
                       int guildID)
        : PendingInvite( inviter, invitee, true, 
                        question,"Accept","Decline",
                        "You have asked %s to join your guild.",
                        "%s has invited you to join a guild.",
                        "%s has joined your guild.",
                        "You have joined the guild.",
                        "%s has declined your invitation.",
                        "You have declined %s's invitation.", 
                        psQuestionMessage::generalConfirm)
    {
        this->guildID = guildID;
    };
    virtual ~PendingGuildInvite() {}

    void HandleAnswer(const csString & answer);
};

/**
 * This invitation isn't really an invitation. It is used when somebody tries to invite a player that is already
 * member of a guild and this guild is secret. We cannot tell the inviter that the player is already in a guild.
 * We must keep this information secret. So we send invitation that explains the situation to the
 * secret member and that cannot be accepted. In this way, his membership in secret guild won't be revealed.
 */
class PendingSecretGuildMemberInvite : public PendingInvite
{
public:
    PendingSecretGuildMemberInvite(Client *inviter,
                       Client *invitee,
                       const char *question,
                       int guildID)
        : PendingInvite( inviter, invitee, true,
                        question,"Decline","",
                        "You have asked %s to join your guild.",
                        "%s has invited you to join a guild. You are already member of a secret guild so you cannot accept this offer.",
                        "",
                        "",
                        "%s has declined your invitation.",
                        "You have declined %s's invitation.",
                        psQuestionMessage::secretGuildNotify)
    {
        cannotAccept = true;
    };
};

/** A structure to hold the clients that are pending on guild war challenges.
 */
class PendingGuildWarInvite : public PendingInvite
{
public:

    PendingGuildWarInvite(Client *inviter,
                          Client *invitee,
                          const char *question)
        : PendingInvite( inviter, invitee, true,
                        question,"Accept","Decline",
                        "You have challenged %s to a guild war.",
                        "%s has challenged you to a guild war.",
                        "%s has accepted your challenge.",
                        "You have accepted %s's challenge.",
                        "%s has declined your challenge.",
                        "You have declined %s's challenge.",
                        psQuestionMessage::generalConfirm)
    {
    }

    virtual ~PendingGuildWarInvite() {}

    virtual void HandleAnswer(const csString & answer);
};

class psGuildCheckEvent : public psGameEvent
{
protected:
    int guildid;
    GuildManager *guildmanager;

public:
    psGuildCheckEvent(int guild_id, GuildManager *gm)
        : psGameEvent(0,GUILD_KICK_GRACE *60*1000,"psGuildCheckEvent")
    {
        guildid      = guild_id;
        guildmanager = gm;
    }

    void Trigger()
    {
        guildmanager->RequirementsDeadline(guildid);
    }
};


/** 
  * Returns guild of 'client'.
  * If he is not in a guild, NULL is returned and text message "You are not in a guild." is sent to the client
  */
psGuildInfo * GetClientGuild(Client * client)
{
    psGuildInfo * guild = client->GetActor()->GetGuild();
    if (!guild)
    {
        psSystemMessage newmsg(client->GetClientNum(),MSG_ERROR,"You are not in a guild.");
        newmsg.SendMessage();
        return NULL;
    }
    return guild;
}









GuildManager::GuildManager(ClientConnectionSet *cs, 
                           ChatManager *chat)
{
    clients    = cs;
    chatserver = chat;  // Needed to GUILDSAY things.

    xml = csPtr<iDocumentSystem>(new csTinyDocumentSystem);
    CS_ASSERT( xml );

    psserver->GetEventManager()->Subscribe(this,MSGTYPE_GUILDCMD,REQUIRE_READY_CLIENT);
    psserver->GetEventManager()->Subscribe(this,MSGTYPE_GUIGUILD,REQUIRE_READY_CLIENT);
    psserver->GetEventManager()->Subscribe(this,MSGTYPE_GUILDMOTDSET,REQUIRE_ANY_CLIENT);
}

GuildManager::~GuildManager()
{
    size_t i;
    
    for (i=0; i < notifySubscr.Length(); i++)
        delete notifySubscr[i];
    notifySubscr.DeleteAll();
    
    psserver->GetEventManager()->Unsubscribe(this,MSGTYPE_GUILDCMD);
    psserver->GetEventManager()->Unsubscribe(this,MSGTYPE_GUIGUILD);
    psserver->GetEventManager()->Unsubscribe(this,MSGTYPE_GUILDMOTDSET);
}

void GuildManager::HandleMessage(MsgEntry *me,Client *client)
{
    switch (me->GetType())
    {
        case MSGTYPE_GUILDCMD:
        {
            psGuildCmdMessage msg(me);
            if (!msg.valid)
            {
                psserver->SendSystemError(me->clientnum, "Command not supported by server yet.");
                Error2("Failed to parse psGuildCmdMessage from client %u.",me->clientnum);
                return;
            }
            HandleCmdMessage(msg,client);
            break;
        }
        case MSGTYPE_GUIGUILD:
        {
            psGUIGuildMessage msg(me);
            if (!msg.valid)
            {
                Error2("Failed to parse psGUIGuildMessage from client %u.",me->clientnum);
                return;
            }
            HandleGUIMessage(msg,client);
            break;
        }
        case MSGTYPE_GUILDMOTDSET:
        {
            psGuildMOTDSetMessage msg(me);
            if (!msg.valid)
            {
                Error2("Failed to parse psGuildMOTDSetMessage from client %u.",me->clientnum);
            }
            HandleMOTDSet(msg,client);
        }
    }
}

void GuildManager::HandleCmdMessage(psGuildCmdMessage& msg, Client* client )
{
    int clientnum = client->GetClientNum();
    
    if (msg.command == "/newguild")
    {
        CreateGuild(msg,client);
    }
    else if (msg.command == "/endguild")
    {
        EndGuild(msg,client);
    }
    else if (msg.command == "/guildname")
    {
        ChangeGuildName(msg,client);
    }
    else if (msg.command == "/guildinvite")
    {
        Invite(msg,client);
    }
    else if (msg.command == "/guildremove")
    {
        Remove(msg,client);
    }
    else if (msg.command == "/guildlevel")
    {
        Rename(msg,client);
    }
    else if (msg.command == "/guildpromote")
    {
        Promote(msg,client);
    }
    else if (msg.command == "/guildmembers")
    {
        ListMembers(msg,client);
    }
    else if (msg.command == "/guildsecret")
    {
        Secret(msg, client);
    }
    else if (msg.command == "/guildweb")
    {
        Web(msg, client);
    }
    else if (msg.command == "/guildmotd")
    {
        MOTD(msg,client);
    }
    else if (msg.command == "/guildwar")
    {
        GuildWar(msg,client);
    }
    else if (msg.command == "/guildyield")
    {
        GuildYield(msg,client);
    }
    else if (msg.command == "/guildpoints")
    {
        SendGuildPoints(msg,client);
    }
    else if (msg.command == "/newalliance")
    {
        NewAlliance(msg,client);
    }
    else if (msg.command == "/allianceinvite")
    {
        AllianceInvite(msg,client);
    }
    else if (msg.command == "/allianceremove")
    {
        AllianceRemove(msg,client);
    }
    else if (msg.command == "/allianceleave")
    {
        AllianceLeave(msg,client);
    }
    else if (msg.command == "/allianceleader")
    {
        AllianceLeader(msg,client);
    }
    else if (msg.command == "/endalliance")
    {
        EndAlliance(msg,client);
    }
    else
    {
        psserver->SendSystemError(clientnum,"Command not supported by server yet.");
    }
}

void GuildManager::HandleGUIMessage(psGUIGuildMessage& msg,Client *client)
{
    csRef<iDocument> doc  = xml->CreateDocument();

    const char* error = doc->Parse( msg.commandData);
    if ( error )
    {
        Error2("Error in XML: %s", error );
        return;
    }

    switch(msg.command)
    {
    case psGUIGuildMessage::SUBSCRIBE_GUILD_DATA:
        HandleSubscribeGuildData(client, doc->GetRoot());
        break;
    case psGUIGuildMessage::UNSUBSCRIBE_GUILD_DATA:
        UnsubscribeGuildData(client);
        break;
    case psGUIGuildMessage::SET_ONLINE:
        HandleSetOnline(client, doc->GetRoot());
        break;
    case psGUIGuildMessage::SET_LEVEL_RIGHT:
        HandleSetLevelRight(client, doc->GetRoot());
        break;
    case psGUIGuildMessage::SET_MEMBER_POINTS:
        HandleSetMemberPoints(client, doc->GetRoot());
        break;
    case psGUIGuildMessage::SET_MEMBER_PUBLIC_NOTES:
        HandleSetMemberNotes(client, doc->GetRoot(), true);
        break;
    case psGUIGuildMessage::SET_MEMBER_PRIVATE_NOTES:
        HandleSetMemberNotes(client, doc->GetRoot(), false);
        break;
    }
}

void GuildManager::HandleMOTDSet(psGuildMOTDSetMessage& msg,Client *client)
{
    if (CheckClientRights(client,RIGHTS_EDIT_GUILD,"You don't have permission to change settings of your guild.")) {
        psGuildInfo *gi = client->GetActor()->GetGuild();
        gi->SetMOTD(msg.guildmotd);
        //Send notify to all guild members
        psSystemMessage newmsg(client->GetClientNum(), MSG_INFO,
                       "Guild message of the day updated");
        psserver->GetEventManager()->Broadcast(newmsg.msg,NetBase::BC_GUILD,gi->id);
    }
}

/** Returns guild level of character connected as 'client' (zero if he has no level)
  */
int GuildManager::GetClientLevel(Client * client)
{
    psGuildLevel * level;
    
    level = client->GetActor()->GetGuildLevel();
    if (level != NULL)
        return level->level;
    else
        return 0;
}

/** Checks if 'client' has priviledge 'priv' in his guild.
  */
bool GuildManager::CheckClientRights(Client * client, GUILD_PRIVILEGE priv)
{
    psGuildLevel * level;

    level = client->GetActor()->GetGuildLevel();
    if (level == NULL)
        return false;

    if (level->HasRights(priv))
        return true;
    else
        return false;
}

/** Checks if 'client' has priviledge 'priv' in his guild.
  * If not, he is sent 'denialMsg'.
  */
bool GuildManager::CheckClientRights(Client * client, GUILD_PRIVILEGE priv, const char * denialMsg)
{
    if (CheckClientRights(client, priv))
        return true;
    else
    {
        psserver->SendSystemError(client->GetClientNum(),denialMsg);
        return false;
    }
}

bool RetrieveOnlineOnly(iDocumentNode * root)
{
    csRef<iDocumentNode> topNode = root->GetNode("r");
    if (!topNode)
         return true;
    
    csString onlineOnly = topNode->GetAttributeValue("onlineonly");
    return (onlineOnly == "yes");
}

void GuildManager::HandleSubscribeGuildData(Client *client,iDocumentNode * root)
{
    int clientnum = client->GetClientNum();

    psGuildInfo * guild = client->GetCharacterData()->GetGuild();
    if (guild == NULL)
    {
        psGUIGuildMessage cmd(clientnum,psGUIGuildMessage::NOT_IN_GUILD,"");
        cmd.SendMessage();
        return;
    }
    
    // check if already subscribed
    GuildNotifySubscription * subscr = FindNotifySubscr(client);
    if (subscr != NULL)
        return;
   
    subscr = 
                new GuildNotifySubscription(guild->id, client->GetClientNum(), RetrieveOnlineOnly(root));
    notifySubscr.Push(subscr);

    SendGuildData(client);    
    SendLevelData(client);
    SendMemberData(client, subscr->onlineOnly);
    SendAllianceData(client);
}

void GuildManager::UnsubscribeGuildData(Client *client)
{
    GuildNotifySubscription * subscr = FindNotifySubscr(client);
    if (subscr == NULL)
        return;

    delete subscr;
    notifySubscr.Delete(subscr);
}

void GuildManager::HandleSetOnline(Client *client,iDocumentNode * root)
{
    GuildNotifySubscription * subscr = FindNotifySubscr(client);
    
    if (subscr != NULL)
    {
        subscr->onlineOnly = RetrieveOnlineOnly(root);
        SendMemberData(client, subscr->onlineOnly);
    }
}

void GuildManager::SendNotifications(int guild, int msg)
{
    Client * client;
    size_t i;

    for (i=0; i < notifySubscr.Length(); i++)
        if (notifySubscr[i]->guild == guild)
        {
            client = clients->Find( notifySubscr[i]->clientnum );
            if (!client)
                continue;

            psGuildInfo * guild = client->GetCharacterData()->GetGuild();
            if (guild == NULL)
            {
                Error2("Error - character %s is not in any guild but it has guild notifications subscribed", client->GetName());
                continue;
            }
            
            psUpdatePlayerGuildMessage update( client->GetClientNum(),
                                               client->GetActor()->GetEntity()->GetID(),
                                               guild->GetName() );

            if (guild->IsSecret())  // If this is a secret guild, we should only broadcast to members
                psserver->GetEventManager()->Broadcast( update.msg, NetBase::BC_GUILD, guild->id );
            else
                psserver->GetEventManager()->Broadcast( update.msg, NetBase::BC_EVERYONE );

            switch (msg)
            {
                case psGUIGuildMessage::GUILD_DATA:
                    SendGuildData(client);
                    break;
                case psGUIGuildMessage::LEVEL_DATA:
                    SendLevelData(client);
                    break;
                case psGUIGuildMessage::MEMBER_DATA:
                    SendMemberData(client, notifySubscr[i]->onlineOnly);
                    break;
                case psGUIGuildMessage::ALLIANCE_DATA:
                    SendAllianceData(client);
                    break;
            }
        }
}

void GuildManager::SendAllianceNotifications(psGuildAlliance * alliance)
{
    int memberNum;
    
    for (memberNum=0; memberNum < (int)alliance->GetMemberCount(); memberNum++)
        SendNotifications(alliance->GetMember(memberNum)->id, psGUIGuildMessage::ALLIANCE_DATA);
}

void GuildManager::SendNoAllianceNotifications(psGuildAlliance * alliance)
{
    int memberNum;
    
    for (memberNum=0; memberNum < (int)alliance->GetMemberCount(); memberNum++)
    {
        SendNoAllianceNotifications(alliance->GetMember(memberNum));
    }
}

void GuildManager::SendNoAllianceNotifications(psGuildInfo * guild)
{
    size_t notifNum;
    
    for (notifNum=0; notifNum < notifySubscr.Length(); notifNum++)
        if (notifySubscr[notifNum]->guild == guild->id)
        {
            Client * client = clients->Find( notifySubscr[notifNum]->clientnum );
            if (client != NULL)
            {
                psGUIGuildMessage cmd(client->GetClientNum(),psGUIGuildMessage::ALLIANCE_DATA,"<alliance name=\"\"></alliance>");
                cmd.SendMessage();
            }
        }
}

GuildNotifySubscription * GuildManager::FindNotifySubscr(Client * client)
{
    int clientnum;
    size_t i;
    
    clientnum = client->GetClientNum();
    
    for (i=0; i < notifySubscr.Length(); i++)
        if (notifySubscr[i]->clientnum == clientnum)
            return notifySubscr[i];
    return NULL;
}

void GuildManager::HandleSetLevelRight(Client * client, iDocumentNode* root)
{
    csRef<iDocumentNode> topNode = root->GetNode("l");
    if (!topNode)
    {
        Error1("Error in XML: Can't find node l");       
        return;
    }
    int level = topNode->GetAttributeValueAsInt("level");
    csString privilege = topNode->GetAttributeValue("privilege");
    csString state = topNode->GetAttributeValue("state");

    psGuildInfo * guild = client->GetCharacterData()->GetGuild();
    if (guild == NULL)
    {
        psserver->SendSystemError(client->GetClientNum(),"You are not in a guild.");
        return;
    }
    
    if ( ! IsLeader(client))
    {
        if ( ! CheckClientRights(client, RIGHTS_EDIT_LEVEL, "You do not have the rights to edit priviledges in your guild."))
            return;
        if ( GetClientLevel(client) <= level )
        {
            psserver->SendSystemError(client->GetClientNum(),"You do not have the rights to edit priviledges of this level in your guild.");
            return;
        }
    }
    
    GUILD_PRIVILEGE right;
    if (privilege == "view_chat")
    {
        right = RIGHTS_VIEW_CHAT;
    } else if (privilege == "chat")
    {
        right = RIGHTS_CHAT;
    } else if (privilege == "invite")
    {
        right = RIGHTS_INVITE;
    } else if (privilege == "remove")
    {
        right = RIGHTS_REMOVE;
    } else if (privilege == "promote")
    {
        right = RIGHTS_PROMOTE;
    } else if (privilege == "edit_level")
    {
        right = RIGHTS_EDIT_LEVEL;
    } else if (privilege == "edit_points")
    {
        right = RIGHTS_EDIT_POINTS;
    } else if (privilege == "edit_guild")
    {
        right = RIGHTS_EDIT_GUILD;
    } else if (privilege == "edit_public")
    {
        right = RIGHTS_EDIT_PUBLIC;
    } else if (privilege == "edit_private")
    {
        right = RIGHTS_EDIT_PRIVATE;
    } else
    {
        Error2("Unkown privilege %s",privilege.GetData());
        return;
    }

    if (guild->SetPrivilege(level,right,state=="on"))
    {
        psGuildLevel *lev = guild->FindLevel(level);
        
        if (lev != NULL)
            psserver->SendSystemInfo(client->GetClientNum(),"Privilege %s for level %s was turned %s",
                                     privilege.GetData(),lev->title.GetData(),state.GetData());
    }
    
    SendNotifications(guild->id, psGUIGuildMessage::LEVEL_DATA);
}

void GuildManager::HandleSetMemberPoints(Client *client,iDocumentNode * root)
{
    csRef<iDocumentNode> topNode = root->GetNode("p");
    if (topNode == NULL) return;

    unsigned int char_id = topNode->GetAttributeValueAsInt("char_id");
    int points = topNode->GetAttributeValueAsInt("points");

    psGuildInfo * guild = client->GetCharacterData()->GetGuild();
    if (guild == NULL) 
        return;
    
    psGuildMember * member = guild->FindMember(char_id);
    if (member == NULL) 
        return;
    
    if ( ! IsLeader(client))
    {
        if ( !CheckClientRights(client, RIGHTS_EDIT_POINTS, "You do not have the rights to edit points in your guild."))
            return;
        if (GetClientLevel(client) <= member->guildlevel->level )
        {
            psserver->SendSystemError(client->GetClientNum(),"You do not have the rights to edit points of this member.");
            return;
        }
    }
    
    guild->SetMemberPoints(member, points);
    
    SendNotifications(guild->id, psGUIGuildMessage::MEMBER_DATA);
}

void GuildManager::HandleSetMemberNotes(Client *client,iDocumentNode * root, bool isPublic)
{    
    csRef<iDocumentNode> topNode = root->GetNode("n");
    if (topNode == NULL) return;

    int char_id = topNode->GetAttributeValueAsInt("char_id");
    csString notes = topNode->GetAttributeValue("notes");

    psGuildInfo * guild = client->GetCharacterData()->GetGuild();
    if (guild == NULL) 
        return;

    psGuildMember * member = guild->FindMember(char_id);
    if (member == NULL) 
        return;

    if (isPublic)
    {
        if ( ! IsLeader(client))
        {
            if ( !CheckClientRights(client, RIGHTS_EDIT_PUBLIC)
                    ||
                ( GetClientLevel(client) < member->guildlevel->level ) )
            {
                psserver->SendSystemError(client->GetClientNum(),"You do not have the rights to edit public notes of this member.");
                return;
            }
        }
    }
    else
    {
        if ( !CheckClientRights(client, RIGHTS_EDIT_PRIVATE) )
        {
            psserver->SendSystemError(client->GetClientNum(),"You do not have the rights to edit private notes.");
            return;
        }
        if (client->GetPlayerID() != char_id)// if this is not my info
            notes = member->private_notes + notes+ "\n";// append the notes to the end
    }

    guild->SetMemberNotes(member, notes, isPublic);

    SendNotifications(guild->id, psGUIGuildMessage::MEMBER_DATA);
}

const char * DeNULL(const char * str)
{
    return (str == NULL) ? "" : str;
}

void GuildManager::SendGuildData(Client *client)
{
    int clientnum = client->GetClientNum();
    psString open;

    psGuildInfo * guild = client->GetCharacterData()->GetGuild();
    if (guild == NULL) 
        return;
    
    csString escpxml_guild = EscpXML(guild->GetName());
    csString escpxml_webpage = EscpXML(guild->web_page);
    open.AppendFmt("<guild name=\"%s\" secret=\"%s\" web_page=\"%s\"/>",
                      escpxml_guild.GetData(),
                      guild->IsSecret()?"yes":"no",
                      escpxml_webpage.GetData());

    psGUIGuildMessage cmd(clientnum,psGUIGuildMessage::GUILD_DATA,open);
    cmd.SendMessage();
}

const char * BoolToText(bool b)
{
    return b ? "true" : "false";
}

void GuildManager::SendLevelData(Client *client)
{
    int clientnum = client->GetClientNum();
    psString open;

    psGuildInfo * guild = client->GetCharacterData()->GetGuild();
    if (guild == NULL) 
        return;
    
    open.Append("<levellist>");
    csArray<psGuildLevel*>::Iterator lIter = guild->levels.GetIterator();
    while (lIter.HasNext())
    {
        open.Append("<l>");
        psGuildLevel* level = lIter.Next();
    csString escpxml = EscpXML(level->title);
        open.AppendFmt("<title text=\"%s\"/>",escpxml.GetData());
        open.AppendFmt("<level text=\"%d\"/>",level->level);
        open.AppendFmt("<view_chat down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_VIEW_CHAT)));
        open.AppendFmt("<chat down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_CHAT)));
        open.AppendFmt("<invite down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_INVITE)));
        open.AppendFmt("<remove down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_REMOVE)));
        open.AppendFmt("<promote down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_PROMOTE)));
        open.AppendFmt("<edit_level down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_EDIT_LEVEL)));
        open.AppendFmt("<edit_points down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_EDIT_POINTS)));
        open.AppendFmt("<edit_guild down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_EDIT_GUILD)));
        open.AppendFmt("<edit_public down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_EDIT_PUBLIC)));
        open.AppendFmt("<edit_private down=\"%s\"/>",BoolToText(level->HasRights(RIGHTS_EDIT_PRIVATE)));

        open.Append("</l>");
    }
    open.Append("</levellist>");

    psGUIGuildMessage cmd(clientnum,psGUIGuildMessage::LEVEL_DATA,open);
    cmd.SendMessage();
}

void GuildManager::SendMemberData(Client *client,bool onlineOnly)
{
    int clientnum = client->GetClientNum();
    
    csString online, lastOnline;
    psString sectorName;
    psSectorInfo * sector = NULL;
    psString open;

    psGuildInfo * guild = client->GetCharacterData()->GetGuild();
    if (guild == NULL) 
        return;
    
    psGuildLevel * level = client->GetCharacterData()->GetGuildLevel();
    if (level == NULL) 
        return;
    
    // Member list
    open.Append("<memberlist>");
    csArray<psGuildMember*>::Iterator mIter = guild->members.GetIterator();
    while (mIter.HasNext())
    {
        sectorName.Clear();
        
        psGuildMember* member = mIter.Next();
        Client * memberClient = clients->FindPlayer(member->char_id);
        if (memberClient != NULL)
        {
            online = "yes";
            psCharacter* character = memberClient->GetCharacterData();
            if(character)
            {
                sector = character->location.loc_sector;
                lastOnline = character->GetLastLoginTime();
                lastOnline.Truncate(16); 
            }
            if (sector != NULL)
                sectorName = sector->name; 
        }
        else
        {
            online = "no";
            lastOnline = "";
        //The guild member can be NOT online, in this case we have to query the db directly
             Result result(db->Select("SELECT last_login FROM characters WHERE id = '%d'",member->char_id));
             if (result.Count() > 0)
             {
                 lastOnline = result[0][0];
                 lastOnline.Truncate(16);    // cut date+time string to date only
             }
        }
        //account = CacheManager::GetSingleton().GetAccountInfoByCharID(member->char_id);                        

        /*if (account != NULL)
        {
            lastOnline = account->lastlogintime;
            lastOnline.Truncate(16);    // cut date+time string to date only
           delete account;
        }                
        else
            Error2("Could not find account info for player %s !", member->name.GetData());*/

        if (online=="yes"  ||  !onlineOnly)
        {
            open.Append("<m>");
            csString escpxml = EscpXML(member->name);
            open.AppendFmt("<name text=\"%s\"/>",escpxml.GetData());
            escpxml = EscpXML(member->guildlevel->title);
            open.AppendFmt("<level text=\"%s\"/>",escpxml.GetData());
            open.AppendFmt("<online text=\"%s\"/>",online.GetData());            
            open.AppendFmt("<sector text=\"%s\"/>",sectorName.EscapeXML());            
            open.AppendFmt("<lastonline text=\"%s\"/>",lastOnline.GetData());
            open.AppendFmt("<points text=\"%d\"/>",member->guild_points);
            open.Append("</m>");
        }
    }
    open.Append("</memberlist>");

    // Information about members that is not in the member listbox
    open.Append("<memberinfo>");
    csArray<psGuildMember*>::Iterator mIter2 = guild->members.GetIterator();
    while (mIter2.HasNext())
    {
        psGuildMember* member = mIter2.Next();
        
        csString escpxml_name = EscpXML(member->name);
        csString escpxml_publicnotes = EscpXML(member->public_notes);
        csString escpxml_privatenotes;

        if (client->GetPlayerID() == member->char_id)//only show private notes to yourself
            escpxml_privatenotes = EscpXML(member->private_notes);
        else escpxml_privatenotes = "";

    open.AppendFmt("<m char_id=\"%i\" name=\"%s\" public=\"%s\" private=\"%s\" points=\"%i\" level=\"%i\"/>",
                          member->char_id, escpxml_name.GetData(),
                          escpxml_publicnotes.GetData(), escpxml_privatenotes.GetData(),
                          member->guild_points, member->guildlevel->level);
    }
    open.Append("</memberinfo>");
    
    open.AppendFmt("<playerinfo char_id=\"%i\"/>", client->GetPlayerID());

    psGUIGuildMessage cmd(clientnum,psGUIGuildMessage::MEMBER_DATA,open);
    cmd.SendMessage();
}

csString GuildManager::MakeAllianceMemberXML(psGuildInfo * member, bool allianceLeader)
{
    psString xml;
    csString name, isLeader, leaderName, online;
    psGuildMember * leader;
    
    name = member->name;

    if (allianceLeader)
        isLeader = "leader";
    else
        isLeader = "";

    leader = member->FindLeader();
    if (leader != NULL)
    {
        leaderName = leader->name;
        
        if (clients->FindPlayer(leader->char_id) != NULL)
            online = "yes";
        else
            online = "no";
    }
    
    csString escpxml_name = EscpXML(name);
    csString escpxml_isleader = EscpXML(isLeader);
    csString escpxml_leadername = EscpXML(leaderName);
    xml.AppendFmt("<member name=\"%s\" isleader=\"%s\" leadername=\"%s\" online=\"%s\"/>",
                     escpxml_name.GetData(), escpxml_isleader.GetData(), escpxml_leadername.GetData(), online.GetData());
    return xml;
}

void GuildManager::SendAllianceData(Client *client)
{
    int clientnum = client->GetClientNum();
    psGuildAlliance * alliance;
    psString xml;
    int memberNum;

    
    psGuildInfo * guild = client->GetCharacterData()->GetGuild();
    if (guild == NULL) 
        return;

    if (guild->alliance != 0)
    {
        alliance = CacheManager::GetSingleton().FindAlliance(guild->alliance);
        if (alliance == NULL) return;
        
    csString escpxml = EscpXML(alliance->GetName());
        xml.AppendFmt("<alliance IamLeader=\"%i\" name=\"%s\">", guild==alliance->GetLeader(), escpxml.GetData());
        for (memberNum=0; memberNum < (int)alliance->GetMemberCount(); memberNum++)
        {
            psGuildInfo * member = alliance->GetMember(memberNum);
            xml += MakeAllianceMemberXML(member, member == alliance->GetLeader());
        }
    }
    else
        xml.Append("<alliance IamLeader=\"0\">");
    xml.Append("</alliance>");
    
    psGUIGuildMessage cmd(clientnum,psGUIGuildMessage::ALLIANCE_DATA,xml);
    cmd.SendMessage();
}

void GuildManager::CheckMinimumRequirements(psGuildInfo *guild, gemActor *notify)
{
    int clientid=0;

    if (!guild->MeetsMinimumRequirements())
    {
        printf("*****************************************************************************\n"
               "Guild %s has %d members and will be deleted in %d minutes.\n"
               "*****************************************************************************\n",
               (const char *)guild->name, guild->members.Length(), GUILD_KICK_GRACE );

        if (!notify) // If not auto-notifying the leader, find the leader if online
        {
            if (guild->FindLeader() && guild->FindLeader()->actor && guild->FindLeader()->actor->GetActor())
                clientid = guild->FindLeader()->actor->GetActor()->GetClientID();
        }
        else
            clientid = notify->GetClientID();

        if (clientid)
            psserver->SendSystemInfo(clientid,
            "You have %d minutes to meet guild minimum requirements "
            "(%d+ members) or your guild will be disbanded.",
            GUILD_KICK_GRACE, GUILD_MIN_MEMBERS );

        psGuildCheckEvent *event = new psGuildCheckEvent(guild->id, this);
        psserver->GetEventManager()->Push(event);
    }
    else
    {
        // guild ok. do nothing
    }
}

void GuildManager::RequirementsDeadline(int guild_id)
{
    psGuildInfo *guild = CacheManager::GetSingleton().FindGuild(guild_id);

    if (!guild)
        return;

    if (!guild->MeetsMinimumRequirements())
    {
        printf("Removing guild <%s> for failure to meet minimum requirements.\n",guild->GetName().GetDataSafe() );
        EndGuild(guild,0);
    }
}

void GuildManager::CreateGuild(psGuildCmdMessage& msg,Client *client)
{
    int clientnum = client->GetClientNum();
    
    // check if the player is already in a guild
    if (client->GetCharacterData()->GetGuild() != NULL)
    {
        psserver->SendSystemError(clientnum,"You are already in a guild.");
        return;
    }

    if (msg.guildname.Length()==0)
    {
        psserver->SendSystemError(clientnum,"Please specify a guild name.");
        return;
    }

    if (msg.guildname.Length()<5)
    {
        psserver->SendSystemError(clientnum,"Guild name must be at least five characters.");
        return;
    }

    if (msg.guildname.Length() > 25)
    {
        psserver->SendSystemError(clientnum,"Guild name must be at under 25 characters.");
        return;
    }

    if(!FilterGuildName(msg.guildname))
    {
        psserver->SendSystemError(clientnum,"Guild name contains invaild characters (A-Z,a-z and space is allowed).");
        return;
    }

    psCharacter *chardata=client->GetCharacterData();
    if (chardata==NULL)
    {
        Error2("Guild creation attempted by character '%s' with no character data!",client->GetName());
        psserver->SendSystemError(clientnum,"An internal server error occcured (could not find your character data).");
        return;
    }

    if (CacheManager::GetSingleton().FindGuild(msg.guildname))
    {
        psserver->SendSystemError(clientnum,"A guild already exists with that name.");
        return;
    }

    if (chardata->Money().GetTotal() < GUILD_FEE)
    {
        psserver->SendSystemError(clientnum,"It costs %d trias to create a guild.",GUILD_FEE);
        return;
    }
    
    if (!CacheManager::GetSingleton().CreateGuild(msg.guildname, client) )
    {
        psserver->SendSystemError(clientnum, db->GetLastError());
        return;
    }
    else
    {
        psserver->SendSystemInfo(clientnum,"Guild '%s' created.  You have been charged %d tria.", (const char *)msg.guildname, GUILD_FEE);
    }

    // Charge the price now
    chardata->SetMoney(chardata->Money() - GUILD_FEE); 
    
    
    // subscribe client to updates of his guild
    psGuildInfo * guild = client->GetCharacterData()->GetGuild();
    if (guild == NULL) return;
    
    GuildNotifySubscription * subscr = 
                new GuildNotifySubscription(guild->id, client->GetClientNum(), true);
    notifySubscr.Push(subscr);

    // send client data about guild - this will open GuildWindow for him
    SendGuildData(client);
    SendLevelData(client);
    SendMemberData(client, false);
    SendAllianceData(client);

    // Update the player's label
    psUpdatePlayerGuildMessage update(client->GetClientNum(),
                                      client->GetActor()->GetEntity()->GetID(),
                                      guild->GetName());

    update.Multicast(client->GetActor()->GetMulticastClients(),0,0 );

    // Now kick off guild minimum requirement timer
    CheckMinimumRequirements(guild,client->GetActor() );
}

void GuildManager::EndGuild(psGuildCmdMessage& msg,Client *client)
{
    int clientnum = client->GetClientNum();

    psGuildInfo * guild = client->GetCharacterData()->GetGuild();
    if (guild == NULL)
    {
        psserver->SendSystemError(clientnum,"You are not in a guild.");
        return;
    }
    
    if (!(const char *)msg.guildname || msg.guildname=="" )
    {
        psserver->SendSystemError(clientnum,"Guild name must be specified for confirmation purposes.");
        return;
    }

    if ( ! IsLeader(client))
        if ( ! CheckClientRights(client, RIGHTS_EDIT_GUILD, "You do not have the rights to disband your guild."))
            return;

    if (!guild->GetName().CompareNoCase(msg.guildname))
    {
        psserver->SendSystemError(clientnum,"The guild name you specified did not match the guild you are in. The guild was not disbanded.");
        return;
    }

    EndGuild(guild,clientnum);
}

void GuildManager::EndGuild(psGuildInfo *guild,int clientnum)
{
    if (!guild->RemoveGuild() )
    {
        psserver->SendSystemError(clientnum,db->GetLastError());
        return;
    }

    if (clientnum)
        psserver->SendSystemInfo(clientnum, "Guild has been disbanded.");

    UnsubscribeWholeGuild(guild);

    Client *p;
    ClientIterator i(*clients);

    for (p = i.First(); p; p = i.Next())
    {    
        if (p->GetActor() && (p->GetActor()->GetGuild() == guild))
        {
            psUpdatePlayerGuildMessage update(p->GetClientNum(),
                                              p->GetActor()->GetEntity()->GetID(),
                                              "");

            update.Multicast(p->GetActor()->GetMulticastClients(),0,0 );

            psserver->SendSystemInfo(p->GetClientNum(),"Your guild has been disbanded.");
            guild->Disconnect(p->GetActor()->GetCharacterData());
        }
    }

    CacheManager::GetSingleton().RemoveGuild(guild);
}

void GuildManager::UnsubscribeWholeGuild(psGuildInfo * guild)
{
    size_t subscrNum=0;
    while (subscrNum < notifySubscr.Length())
    {
        if (notifySubscr[subscrNum]->guild == guild->id)
        {
            Client * member = clients->Find( notifySubscr[subscrNum]->clientnum );
            if (member != NULL)
            {
                psGUIGuildMessage msg(member->GetClientNum(), psGUIGuildMessage::CLOSE_WINDOW, "<x/>");
                msg.SendMessage();
            }

            delete notifySubscr[subscrNum];
            notifySubscr.Delete(notifySubscr[subscrNum]);
        }
        else
            subscrNum++;
    }
}

void GuildManager::ChangeGuildName(psGuildCmdMessage& msg,Client *client)
{
    int clientnum = client->GetClientNum();

    psGuildInfo * guild = client->GetCharacterData()->GetGuild();
    if (guild == NULL)
    {
        psserver->SendSystemError(clientnum,"You are not in a guild.");
        return;
    }
    
    if (!(const char *)msg.guildname || msg.guildname=="" )
    {
        psserver->SendSystemError(clientnum,"New guild name must be specified.");
        return;
    }

    if ( ! IsLeader(client))    
        if (!CheckClientRights(client, RIGHTS_EDIT_GUILD, "You do not have the rights to edit the name of your guild."))
            return;
    
    if (msg.guildname.Length()<5)
    {
        psserver->SendSystemError(clientnum,"Guild name must be at least five characters.");
        return;
    }

    if (msg.guildname.Length() > 25)
    {
        psserver->SendSystemError(clientnum,"Guild name must be at under 25 characters.");
        return;
    }

    if(!FilterGuildName(msg.guildname))
    {
        psserver->SendSystemError(clientnum,"Guild name contains invalid characters (A-Z,a-z and space is allowed).");
        return;
    }

    if(CacheManager::GetSingleton().FindGuild(msg.guildname))
    {
        psserver->SendSystemError(clientnum,"A guild already exists with that name");
        return;
    }

    if (guild->SetName(msg.guildname))
    {
        psserver->SendSystemInfo(clientnum,"Your guild name has been changed to: %s",msg.guildname.GetData());
    }
    
    SendNotifications(guild->id, psGUIGuildMessage::GUILD_DATA);
}

void GuildManager::Invite(psGuildCmdMessage& msg,Client *client)
{
    csString playerName;
    int clientnum = client->GetClientNum();
    
    playerName = NormalizeCharacterName(msg.player);

    psGuildInfo * guild = client->GetCharacterData()->GetGuild();
    if (!guild)
    {
        psserver->SendSystemError(clientnum,"You have to be in a guild to invite someone.");
        return;
    }

    if ( ! IsLeader(client))
        if ( ! CheckClientRights(client, RIGHTS_INVITE, "You do not have the rights to invite players into your guild."))
            return;

    // invited player must be online when invited
    Client *invitee = clients->Find(playerName);
    if (!invitee)
    {
        psserver->SendSystemError(clientnum,"%s is not online right now.",
                                    (const char*) msg.player);
        return;
    }

    if (invitee == client)
    {
        psserver->SendSystemError(clientnum,"You can't invite yourself.", invitee->GetName());
        return;
    }

    bool inviteeIsAlreadyInSecretGuild = false;

    psGuildInfo * inviteeGuild = invitee->GetCharacterData()->GetGuild();
    if (inviteeGuild != NULL)
    {
        if (!inviteeGuild->IsSecret() )
        {
            psserver->SendSystemError(clientnum, "That player is already a member of a guild.");
            return;
        }
        else
            inviteeIsAlreadyInSecretGuild = true;
    }

    PendingInvite *pnew;
    csString invitation;

    invitation.Format("You have been invited to join the %s.  Click Accept to join this guild.",client->GetActor()->GetGuild()->name.GetData() );
    if (inviteeIsAlreadyInSecretGuild)
        pnew = new PendingSecretGuildMemberInvite(client,invitee,invitation,guild->id);
    else
        pnew = new PendingGuildInvite(client,invitee,invitation,guild->id);

    // Track who is invited where, to verify confirmations
    psserver->questionmanager->SendQuestion(pnew);
}

void PendingGuildInvite::HandleAnswer(const csString & answer)
{
    Client * client = psserver->GetConnections()->Find(clientnum);
    if (!client  ||  client->GetCharacterData()->GetGuild() != NULL)
        return;
    
    PendingInvite::HandleAnswer(answer);
    if (answer == "yes")
        psserver->guildmanager->HandleJoinGuild(this);
}


void GuildManager::HandleJoinGuild(PendingGuildInvite *invite)
{
    Client * inviteeClient = clients->Find(invite->clientnum);
    if (inviteeClient == NULL)
        return;
    
    psGuildInfo * guild = CacheManager::GetSingleton().FindGuild(invite->guildID);
    if (guild == NULL)
        return;
    
    if ( !guild->AddNewMember(inviteeClient->GetActor()->GetCharacterData() ) )
    {
        psserver->SendSystemError(invite->inviterClientNum, "Error joining guild! (%s)", db->GetLastError());
        Error2("Error joining guild! (%s)",db->GetLastError() );
        return;
    }

    csString text;
    text.Format("Player %s has joined the guild!",invite->inviteeName.GetData() );
    psChatMessage guildmsg(invite->inviterClientNum,"System",text,CHAT_GUILD, false);
    chatserver->SendGuild(inviteeClient->GetCharacterData()->GetCharName(), guild, guildmsg);

    SendNotifications(guild->id, psGUIGuildMessage::MEMBER_DATA);

    if (!guild->IsSecret())// update guild labels
    {
        psUpdatePlayerGuildMessage update(
                inviteeClient->GetClientNum(),
                inviteeClient->GetActor()->GetEntity()->GetID(),
                guild->GetName() );
        psserver->GetEventManager()->Broadcast(update.msg,NetBase::BC_EVERYONE);  
    }    

    // forward new motd
    csString tip("");
    csString motdMsg(psserver->GetMOTD());
    csString guildMOTD(guild->GetMOTD());
    csString guildName(guild->GetName());
    psMOTDMessage motd(inviteeClient->GetClientNum(),tip,motdMsg,guildMOTD,guildName);
    motd.SendMessage();
}

void GuildManager::Remove(psGuildCmdMessage& msg,Client *client)
{
    Client * targetClient;
    csString name;
    int clientnum = client->GetClientNum();
    
    psGuildInfo *gi = client->GetActor()->GetGuild();
    if (!gi)
    {
        psserver->SendSystemError(clientnum,"You are not in a guild.");
        return;
    }

    if ( msg.player.Length() )
        name = NormalizeCharacterName(msg.player);
    else
        name = client->GetName();

    // Find the named player in guild
    psGuildMember *target = gi->FindMember(name);
    if (!target)
    {
        psserver->SendSystemError(clientnum,"That player is not member of your guild.");
        return;
    }

    // Verify rights if the player is removing someone else from the guild
    if (client->GetPlayerID() != (int)target->char_id )
    {
        if ( ! IsLeader(client))
        {
            if ( !CheckClientRights(client, RIGHTS_REMOVE, "You do not have rights to remove someone from your guild."))
                return;
            if (GetClientLevel(client) <= target->guildlevel->level)
            {
                psserver->SendSystemError(clientnum,"You can't remove players of same or higher level.");
                return;
            }
        }
        targetClient = clients->Find(target->name);
    }
    else
        targetClient = client;

    if (target->guildlevel->level == MAX_GUILD_LEVEL)
    {
        psserver->SendSystemError(clientnum,"The leader cannot simply leave his guild. He must appoint a new leader first.");
        return;
    }

    gi->RemoveMember(target);

    if (targetClient != NULL)
    {
        psserver->SendSystemInfo(targetClient->GetClientNum(),"You have been removed from your guild.");
        UnsubscribeGuildData(targetClient);

        // forward blank MOTD to remove old
        csString blank("");
        csString motdMsg(psserver->GetMOTD());
        psMOTDMessage motd(targetClient->GetClientNum(),blank,motdMsg,blank,blank);
        motd.SendMessage();
    }

    csString text;
    text.Format("Player %s has left the guild.", (const char *)msg.player );
    psChatMessage guildmsg(0,"System",text,CHAT_GUILD, false);
    chatserver->SendGuild("server", gi, guildmsg);
    
    SendNotifications(gi->id, psGUIGuildMessage::MEMBER_DATA);

    // Now kick off guild minimum requirement timer
    CheckMinimumRequirements(gi,NULL);
}

/**
 * Called when player issues /guildlevel command
 * 
 * Syntax:
 * /guildlevel <level> <levelname>
 * or
 * /guildlevel  (this will show all current level names)
 */
void GuildManager::Rename(psGuildCmdMessage& msg,Client *client)
{
    int clientnum = client->GetClientNum();

    psGuildInfo *gi = client->GetActor()->GetGuild();
    if (!gi)
    {
        psserver->SendSystemError(clientnum,"You are not in a guild.");
        return;
    }

    // checks if levelnumber has been specified
    if (msg.level <= 0 || msg.level > 9)
    {
        psserver->SendSystemInfo(clientnum,"Your guild has these titles defined:");
        for (size_t i=0; i<gi->levels.Length(); i++)
        {
            psserver->SendSystemInfo(clientnum,"%i: %s",gi->levels[i]->level,gi->levels[i]->title.GetData() );
        }
        return;
    }

    if ( ! IsLeader(client))
        if ( ! CheckClientRights(client, RIGHTS_EDIT_LEVEL, "You do not have the rights to rename levels of your guild."))
            return;

    // checks if levelname has been specified
    if (! (const char *)msg.levelname)
    {
        psserver->SendSystemError(clientnum,"You must specify the name after the level to rename a guild level.");
        return;
    }

    if(!FilterGuildName(msg.levelname))
    {
        psserver->SendSystemError(clientnum,"Level name contains invaild characters (A-Z,a-z and space is allowed).");
        return;
    }
    
    if (msg.levelname.Length()<3)
    {
        psserver->SendSystemError(clientnum,"Guild level name must be at least three characters.");
        return;
    }

    if (msg.levelname.Length() > 25)
    {
        psserver->SendSystemError(clientnum,"Guild level name must be at under 25 characters.");
        return;
    }
    
    if (!gi->RenameLevel(msg.level,msg.levelname))
    {
        psserver->SendSystemError(clientnum,"SQL Error: %s",db->GetLastError());
        return;
    }

    psserver->SendSystemInfo(clientnum,"Guild level rename was successful.");

    csString text;
    text.Format("Guild level %d is now called: %s", msg.level, (const char *)msg.levelname );
    psChatMessage guildmsg(clientnum,"System",text,CHAT_GUILD, false);
    if (guildmsg.valid)
        chatserver->SendGuild(client->GetCharacterData()->GetCharName(), gi, guildmsg);

    SendNotifications(gi->id, psGUIGuildMessage::LEVEL_DATA);
}

void GuildManager::Promote(psGuildCmdMessage& msg,Client *client)
{
    int clientnum = client->GetClientNum();

    psGuildInfo *guild = client->GetActor()->GetGuild();
    if (!guild)
    {
        psserver->SendSystemError(clientnum,"You are not in a guild.");
        return;
    }

    if (! (const char *)msg.player)
    {
        psserver->SendSystemError(clientnum,"You must specify the player to promote someone.");
        return;
    }

    if (msg.level <= 0 || msg.level > 9)
    {
        psserver->SendSystemError(clientnum,"You must specify a level between 1 and 9 to promote someone.");
        return;
    }

    psGuildMember *target = guild->FindMember(msg.player);
    if (!target)
    {
        psserver->SendSystemError(clientnum,"Player %s is not a member of your guild.",(const char *)msg.player);
        return;
    }

    if (target->guildlevel->level == MAX_GUILD_LEVEL)
    {
        psserver->SendSystemError(clientnum,"You can't just put leader to lower level. You must promote someone else to his place.");
        return;
    }

    if ( ! IsLeader(client))    
    {
        if ( ! CheckClientRights(client, RIGHTS_PROMOTE, "You do not have the rights in your guild to promote someone."))
            return;
        if (GetClientLevel(client) <= target->guildlevel->level)
        {
            psserver->SendSystemError(clientnum,"You can't promote players of higher or equal level.",(const char *)msg.player);
            return;
        }
        if (GetClientLevel(client) <= msg.level)
        {
            psserver->SendSystemError(clientnum,"You can't promote players to higher or equal level.",(const char *)msg.player);
            return;
        }
    }

    if (!guild->UpdateMemberLevel(target,msg.level))
    {
        psserver->SendSystemError(clientnum,"SQL Error: %s",db->GetLastError());
        return;
    }

    // If we just promoted someone to highest level, we must also demote the current leader
    // (i.e. the player who did this action).
    if (msg.level == MAX_GUILD_LEVEL)
    {
        psGuildMember *clientMembership = guild->FindMember(client->GetPlayerID());
        if (!clientMembership)
        {
            psserver->SendSystemError(clientnum,"Internal error: membership of player not found.");
            return;
        }
        if (!guild->UpdateMemberLevel(clientMembership, MAX_GUILD_LEVEL-1))
        {
            psserver->SendSystemError(clientnum,"SQL Error: %s",db->GetLastError());
            return;
        }
    }

    psserver->SendSystemInfo(clientnum,"Promotion successful.");

    csString text;
    text.Format("%s has been promoted to '%s'", (const char *)msg.player, target->guildlevel->title.GetData() );
    psChatMessage guildmsg(clientnum,"System",text,CHAT_GUILD, false);
    if (guildmsg.valid)
        chatserver->SendGuild(client->GetCharacterData()->GetCharName(), guild, guildmsg);

    SendNotifications(guild->id, psGUIGuildMessage::MEMBER_DATA);
}

/** Sends list of guild members of given level as text messages to client
  */
void ListMembersOfLevel(psGuildInfo * guild, int clientnum, int level)
{
    psGuildMember * member;
    
    for (size_t i=0; i < guild->members.Length(); i++)
    {
        member = guild->members[i];
        if (member->guildlevel->level == level)
            psserver->SendSystemInfo(clientnum,"%s: %s",
                                     member->name.GetData(),
                                     member->guildlevel->title.GetData() );
    }
}

void GuildManager::ListMembers(psGuildCmdMessage& msg,Client *client)
{
    int clientnum = client->GetClientNum();

    psGuildInfo *guild = client->GetActor()->GetGuild();
    if (guild == NULL)
    {
        psserver->SendSystemError(clientnum,"You are not in a guild.");
        return;
    }

    if (!msg.level)
        for (int i=9; i>0; i--)
            ListMembersOfLevel(guild, clientnum, i);
    else
        ListMembersOfLevel(guild, clientnum, msg.level);
}

void GuildManager::Secret(psGuildCmdMessage &msg, Client *client)
{
    int clientnum = client->GetClientNum();

    psGuildInfo *guild = client->GetActor()->GetGuild();
    if (!guild)
    {
        psserver->SendSystemError(clientnum, "You are not in a guild.");
        return;
    }

    // If the player doesn't provide an argument, just report the current
    // status of the secrecy flag.
    if (msg.secret == "")
    {
        psserver->SendSystemInfo(clientnum,
                                 "Your guild's secrecy setting is: %s",
                                 (client->GetActor()->GetGuild()->IsSecret() ? "ON" : "OFF"));
        return;
    }

    if ( ! IsLeader(client))
        if ( ! CheckClientRights(client, RIGHTS_EDIT_GUILD, "You do not have rights to change secrecy of your guild."))
            return;

    // Change the argument to lowercase to get a case-insensitive match.
    msg.secret.Downcase();

    // Check for invalid arguments.
    if (msg.secret != "on" && msg.secret != "off")
    {
        psserver->SendSystemError(clientnum,
                                "Unrecognized /guildsecret argument \"%s\". Choose \"on\" or \"off\".",
                                msg.secret.GetData());
        return;
    }

    bool new_secrecy_value = (msg.secret == "on");

    // Only update the database if the value is really being changed.
    if (new_secrecy_value != guild->IsSecret() )
    {
        if (!guild->SetSecret(new_secrecy_value))
        {
            psserver->SendSystemError(clientnum, "SQL Error: %s",
                                    db->GetLastError());
            return;
        }
    }

    // Report the new value to the player.
    psserver->SendSystemInfo(clientnum, "Your guild's secrecy setting is now: %s",
                             (new_secrecy_value ? "ON" : "OFF"));

    SendNotifications(guild->id, psGUIGuildMessage::GUILD_DATA);
    
    // If secrecy is on send a message to all others clearing guild name
    // else send a message to all others to show the guild name.
    if ( new_secrecy_value == true )
    {
        // Turn label off for everybody
        psUpdatePlayerGuildMessage update(
                clientnum,
                client->GetActor()->GetEntity()->GetID(),
                "");
        psserver->GetEventManager()->Broadcast(update.msg,NetBase::BC_EVERYONE);
        
        // Update guild members with the label 
        psUpdatePlayerGuildMessage update2(
                clientnum,
                client->GetActor()->GetEntity()->GetID(),
                guild->GetName() );
        psserver->GetEventManager()->Broadcast(update2.msg,NetBase::BC_GUILD,guild->id);                  
    }                        
    else
    {
        // turn label on for everybody
        psUpdatePlayerGuildMessage update(
                clientnum,
                client->GetActor()->GetEntity()->GetID(),
                guild->GetName() );
        psserver->GetEventManager()->Broadcast(update.msg,NetBase::BC_EVERYONE);          
    }
            
    
}

void GuildManager::Web(psGuildCmdMessage &msg, Client *client)
{
    int clientnum = client->GetClientNum();

    psGuildInfo *guild = client->GetActor()->GetGuild();
    if (!guild)
    {
        psserver->SendSystemError(clientnum,"You are not in a guild.");
        return;
    }

    if ( ! IsLeader(client))
        if ( ! CheckClientRights(client, RIGHTS_EDIT_GUILD, "You do not have rights to change web page of your guild."))
            return;

    if (!msg.web_page.Length())
    {
        psserver->SendSystemError(clientnum,"You did not specify anything as your url.");
        return;
    }

    // Only update the database if the value is really being changed.
    if (msg.web_page != guild->web_page )
    {
        if (!guild->SetWebPage(msg.web_page))
        {
            psserver->SendSystemError(clientnum, "Setting of web page failed");
            return;
        }
    }

    // Report the new value to the player.
    psserver->SendSystemInfo(clientnum, "Your guild's web page url is now: %s", guild->web_page.GetData());
    
    SendNotifications(guild->id, psGUIGuildMessage::GUILD_DATA);
}

bool GuildManager::IsLeader(Client * client)
{
    return GetClientLevel(client) == MAX_GUILD_LEVEL;
}

void GuildManager::MOTD(psGuildCmdMessage &msg, Client *client)
{
    int clientnum = client->GetClientNum();

    psGuildInfo *guild = client->GetActor()->GetGuild();
    if (!guild)
    {
        psSystemMessage newmsg(clientnum,MSG_ERROR,"You are not in a guild.");
        newmsg.SendMessage();
        return;
    }

    if (msg.motd == "")
    {
        psserver->SendSystemInfo(clientnum,
            "Guild Message Of The Day: %s",
                                 (client->GetActor()->GetGuild()->GetMOTD()));
        return;
    }

    if ( ! IsLeader(client))
        if ( ! CheckClientRights(client, RIGHTS_EDIT_PUBLIC, "You do not have rights to change the message of the day in your guild."))
            return;

    //All fine, let's change it already
    guild->SetMOTD(msg.motd);

    //Send notify to all guild members
    psSystemMessage newmsg(clientnum, MSG_INFO,
                            "Guild message of the day updated");
    psserver->GetEventManager()->Broadcast(newmsg.msg,NetBase::BC_GUILD,guild->id);

    
    SendNotifications(guild->id, psGUIGuildMessage::GUILD_DATA);
}

void GuildManager::GuildWar(psGuildCmdMessage &msg, Client *client)
{
    int clientnum = client->GetClientNum();

    // Check target dead
    gemObject *target = client->GetTargetObject();
    if (!target)
    {
        psserver->SendSystemError(clientnum,"You don't have another player targeted.");
        return;
    }

    if (!target->IsAlive())
    {
        psserver->SendSystemError(clientnum, "You can't challenge a dead person");
        return;
    }

    Client * targetClient = psserver->GetNetManager()->GetClient(target->GetClientID());
    if (!targetClient)
    {
        psserver->SendSystemError(clientnum, "You can challenge other players only");
        return;
    }

    if (targetClient == client)
    {
        psserver->SendSystemError(clientnum,"You can't begin war with yourself.", targetClient->GetName());
        return;
    }

    gemActor *wartarget = targetClient->GetActor();

    // Check for pre-existing war with this person
    psGuildInfo *attackguild = GetClientGuild(client);
    if (attackguild == NULL)
        return;

    psGuildInfo *targetguild = wartarget->GetGuild();
    if (!targetguild)
    {
        psserver->SendSystemError(clientnum, "This player is not in a guild");
        return;
    }

    if (attackguild->FindLeader()->actor != client->GetActor()->GetCharacterData() )
    {
        psserver->SendSystemError(clientnum, "You are not guild leader");
        return;
    }

    // Check to see if it can find a leader.  If no leader is found then the guild is in a bad
    // state and needs to be fixed by an admin. 
    if ( targetguild->FindLeader() == NULL )
    {
        psserver->SendSystemError(clientnum, "The guild %s has no leader. Please inform PlaneShift admins", targetguild->GetName().GetData() );
        return;    
    }
    
    if (targetguild->FindLeader()->actor != wartarget->GetCharacterData() )
    {
        psserver->SendSystemError(clientnum, "This player is not guild leader");
        return;
    }

    if (attackguild->IsGuildWarActive(targetguild))
    {
        psserver->SendSystemError(clientnum,"You are already in a guild war with your target.");
        return;
    }

    // Challenge
    csString question;
    question.Format("%s has challenged your guild to a war!  Click on Accept to allow the war or Reject to ignore it.",
                    client->GetName() );
    PendingGuildWarInvite *invite = new PendingGuildWarInvite(client,
                                                              targetClient,
                                                              question);
    psserver->questionmanager->SendQuestion(invite);
}

void GuildManager::AcceptWar(PendingGuildWarInvite *invite)
{
    Client * inviteeClient = clients->Find(invite->clientnum);
    Client * inviterClient = clients->Find(invite->inviterClientNum);
    
    if (!inviteeClient  ||  !inviterClient)
        return;
    
    psGuildInfo *attackguild = inviterClient->GetActor()->GetGuild();
    psGuildInfo *targetguild = inviteeClient->GetActor()->GetGuild();

    if (!attackguild || !targetguild)
        return;

    attackguild->AddGuildWar(targetguild);
    targetguild->AddGuildWar(attackguild);

    psSystemMessage sys(0,MSG_INFO,"%s and %s have started a guild war!", 
                        attackguild->GetName().GetData(),
                        targetguild->GetName().GetData() );
    psserver->GetEventManager()->Broadcast(sys.msg,NetBase::BC_GUILD,attackguild->id);
    psserver->GetEventManager()->Broadcast(sys.msg,NetBase::BC_GUILD,targetguild->id);
}

void PendingGuildWarInvite::HandleAnswer(const csString & answer)
{
    Client * client = psserver->GetConnections()->Find(inviterClientNum);
    if (!client) return;
    psGuildInfo *attackguild = GetClientGuild(client);
    if (!attackguild) return;

    Client * targetClient = psserver->GetConnections()->Find(clientnum);
    if (!targetClient) return;
    psGuildInfo *targetguild = GetClientGuild(targetClient);
    if (!targetguild) return;
    
    if (attackguild->IsGuildWarActive(targetguild)) 
        return;

    PendingInvite::HandleAnswer(answer);
    if (answer == "yes")
        psserver->guildmanager->AcceptWar(this);
}

void GuildManager::GuildYield(psGuildCmdMessage &msg, Client *client)
{
    int clientnum = client->GetClientNum();

    int winnerid = client->GetTargetClientID();
    if (!winnerid)
    {
        psserver->SendSystemError(client->GetClientNum(),"You don't have another player targeted.");
        return;
    }

    psGuildInfo *loserguild = client->GetActor()->GetGuild();
    if (!loserguild)
    {
        psserver->SendSystemError(clientnum, "You are not in a guild");
        return;
    }

    if (loserguild->FindLeader()->actor != client->GetActor()->GetCharacterData() )
    {
        psserver->SendSystemError(clientnum, "You are not guild leader");
        return;
    }

    if ( client->GetTargetObject() == NULL )
    {
        psserver->SendSystemError(clientnum, "You must target the leader of the guild.");
        return;        
    }
    
    gemActor *target = client->GetTargetObject()->GetActorPtr();
    if (!target)
        return;

    psGuildInfo *winnerguild = target->GetGuild();
    if (!winnerguild)
    {
        psserver->SendSystemError(clientnum, "Your target is not in a guild");
        return;
    }

    if (!loserguild->IsGuildWarActive(winnerguild))
    {
        psserver->SendSystemError(clientnum,"You are not in a guild war with your target.");
        return;
    }

    // Remove the duel from both sides.
    loserguild->RemoveGuildWar(winnerguild);
    winnerguild->RemoveGuildWar(loserguild);

    // TODO: Stop all fights in progress.
    //client->GetActor()->SetMode(PSCHARACTER_MODE_PEACE);

    // Award guild karma points (33% of lower-ranked guild's points)
    float delta = loserguild->karma_points;
    if (winnerguild->karma_points < delta)
        delta = winnerguild->karma_points;
    delta /= 3;

    if (!(int)delta)
        delta=1;

    csString str;
    str.Format("%1.0f karma points from %s awarded to %s.",
               delta,loserguild->GetName().GetData(),winnerguild->GetName().GetData() );

    CPrintf(CON_DEBUG, str);

    psSystemMessage sys(0,MSG_INFO,str);
    psserver->GetEventManager()->Broadcast(sys.msg,NetBase::BC_GUILD,loserguild->id);
    psserver->GetEventManager()->Broadcast(sys.msg,NetBase::BC_GUILD,winnerguild->id);

    loserguild->karma_points -= (int)delta;
    winnerguild->karma_points += (int)delta;

    if (delta)
    {
        db->Command("update guilds set karma_points=%1.0f where id=%d",
                    loserguild->karma_points,
                    loserguild->id);

        db->Command("update guilds set karma_points=%1.0f where id=%d",
                    winnerguild->karma_points,
                    winnerguild->id);
    }
}




/******************************************************************************
*
*                Handlers of alliance management network messages
*
******************************************************************************/

class PendingAllianceInvite : public PendingInvite
{
public:
    int allianceID;

    PendingAllianceInvite(Client *inviter,
                          Client *invitee,
                          const char *question,
                          int allianceID)
        : PendingInvite( inviter, invitee, true, 
                        question,"Accept","Decline",
                        "You have asked %s to join your alliance.",
                        "%s has invited you to join an alliance.",
                        "%s has joined your alliance.",
                        "You have joined the alliance.",
                        "%s has declined your invitation.",
                        "You have declined %s's invitation.",
                        psQuestionMessage::generalConfirm)
    {
        this->allianceID = allianceID;
    }

    void HandleAnswer(const csString & answer)
    {
        Client * client = psserver->GetConnections()->Find(clientnum);
        if (!client) return;
        psGuildInfo * guild = GetClientGuild(client);
        if (!guild) return;
        if (guild->GetAllianceID() != 0)
            return;
        
        PendingInvite::HandleAnswer(answer);
        if (answer != "yes")
            return;
        
        Client * inviteeClient = psserver->GetConnections()->Find(clientnum);
        if (inviteeClient == NULL) return;
        
        psGuildInfo * inviteeGuild = GetClientGuild(inviteeClient);
        if (inviteeGuild == NULL) return;
        
        psGuildAlliance * alliance = CacheManager::GetSingleton().FindAlliance(allianceID);
        if (alliance == NULL) return;

        alliance->AddNewMember(inviteeGuild);
        psserver->GetGuildManager()->SendAllianceNotifications(alliance);
    }
};


/** Does common checks needed for most alliance operations.
  * If one of the checks fails, then the user is sent text description of the problem.
  *
  * Parameter 'checkLeaderGuild' says if we should check that player's guild is leader in the alliance.
  *
  * This function also returns pointers to player's guild and alliance as a secondary product.
  */
bool GuildManager::CheckAllianceOperation(Client * client, bool checkLeaderGuild, psGuildInfo * & guild, psGuildAlliance * & alliance)
{
    int clientnum = client->GetClientNum();
    
    guild = NULL;
    alliance = NULL;
    
    guild = GetClientGuild(client);
    if (guild == NULL) return false;
    
    if (guild->alliance == 0)
    {
        psserver->SendSystemError(clientnum,"You guild is not in an alliance.");
        return false;
    }

    if (GetClientLevel(client) != MAX_GUILD_LEVEL)
    {
        psserver->SendSystemError(clientnum,"You are not guild leader.");
        return false;
    }

    alliance = CacheManager::GetSingleton().FindAlliance(guild->alliance);
    if (alliance == NULL)
    {
        psserver->SendSystemError(clientnum,"Internal error - alliance %d not found.", guild->alliance);
        return false;
    }
    
    if (checkLeaderGuild   &&   alliance->GetLeader() != guild)
    {
        psserver->SendSystemError(clientnum,"Your guild is not alliance leader.");
        return false;
    }
    
    return true;
}


void GuildManager::NewAlliance(psGuildCmdMessage &msg, Client *client)
{
    int clientnum = client->GetClientNum();
    
    psGuildInfo * guild = GetClientGuild(client);
    if (guild == NULL) return;
    
    if (GetClientLevel(client) != MAX_GUILD_LEVEL)
    {
        psserver->SendSystemError(clientnum,"You are not guild leader.");
        return;
    }

    if (guild->alliance != 0)
    {
        psserver->SendSystemError(clientnum,"Your guild is already member of an alliance.");
        return;
    }

    if (msg.alliancename.Length()==0)
    {
        psserver->SendSystemError(clientnum,"Please specify name of the alliance.");
        return;
    }

    if (CacheManager::GetSingleton().CreateAlliance(msg.alliancename, guild, client))
        psserver->SendSystemInfo(clientnum, "Alliance \"%s\" was created.", msg.alliancename.GetData());
    else
        psserver->SendSystemInfo(clientnum, "Alliance creation failed: %s", psGuildAlliance::lastError.GetData());
    

    psGuildAlliance * alliance = CacheManager::GetSingleton().FindAlliance(guild->alliance);
    if (alliance != NULL)
        SendAllianceNotifications(alliance);
}

void GuildManager::AllianceInvite(psGuildCmdMessage &msg, Client *client)
{
    psGuildInfo * guild;
    psGuildAlliance * alliance;
    csString inviteeName;

    int clientnum = client->GetClientNum();
    
    if ( ! CheckAllianceOperation(client, true, guild, alliance))
        return;
    
    if (msg.player.Length()==0)
    {
        psserver->SendSystemError(clientnum,"Please specify name of guild leader to be invited.");
        return;
    }

    inviteeName = NormalizeCharacterName(msg.player);
    
    Client * inviteeClient = clients->Find(inviteeName);
    if (inviteeClient == NULL)
    {
        psserver->SendSystemError(clientnum,"\"%s\" is not online right now.", inviteeName.GetData());
        return;
    }
    
    if (inviteeClient == client)
    {
        psserver->SendSystemError(clientnum,"You can't invite yourself.", inviteeName.GetData());
        return;
    }

    psGuildInfo * inviteeGuild = GetClientGuild(inviteeClient);
    if (inviteeGuild == NULL)
    {
        psserver->SendSystemError(clientnum,"Player \"%s\" is not member of any guild.", inviteeName.GetData());
        return;
    }

    if (alliance->CheckMembership(inviteeGuild))
    {
        psserver->SendSystemError(clientnum,"They are already members of your alliance.");
        return;
    }

    if (inviteeGuild->GetAllianceID() != 0)
    {
        psserver->SendSystemError(clientnum,"%s is already a member of an alliance.", inviteeName.GetData());
        return;
    }

    if (GetClientLevel(inviteeClient) != MAX_GUILD_LEVEL)
    {
        psserver->SendSystemError(clientnum,"Player \"%s\" is not guild leader.", inviteeName.GetData());
        return;
    }


    csString invitation;
    invitation.Format("You have been invited to join the %s alliance.  Click Accept to join this alliance.",alliance->GetName().GetData() );
    PendingAllianceInvite *pnew = new PendingAllianceInvite(client, inviteeClient, invitation, alliance->GetID());
    psserver->questionmanager->SendQuestion(pnew);
}

void GuildManager::AllianceRemove(psGuildCmdMessage &msg, Client *client)
{
    psGuildInfo * guild;
    psGuildAlliance * alliance;

    int clientnum = client->GetClientNum();
    
    if ( ! CheckAllianceOperation(client, false, guild, alliance))
        return;
    
    if (msg.guildname.Length()==0)
    {
        psserver->SendSystemError(clientnum,"Please specify name of the guild to be removed from alliance.");
        return;
    }

    psGuildInfo * removedGuild = CacheManager::GetSingleton().FindGuild(msg.guildname);
    if (removedGuild == NULL)
    {
        psserver->SendSystemError(clientnum,"No such guild exists.");
        return;
    }
    
    RemoveMemberFromAlliance(client, guild, alliance, removedGuild);
}

void GuildManager::AllianceLeave(psGuildCmdMessage &msg, Client *client)
{
    psGuildInfo * guild;
    psGuildAlliance * alliance;

    if ( ! CheckAllianceOperation(client, false, guild, alliance))
        return;

    RemoveMemberFromAlliance(client, guild, alliance, guild);
}

void GuildManager::RemoveMemberFromAlliance(Client * client, psGuildInfo * guild, psGuildAlliance * alliance, 
                                            psGuildInfo * removedGuild)
{
    int clientnum = client->GetClientNum();
    
    if (removedGuild == alliance->GetLeader())
    {
        psserver->SendSystemError(clientnum,"Alliance leader cannot leave. Choose another leader first.");
        return;
    }
    
    // if one guild removes another one (and not just itself), it must be alliance leader
    if (guild != removedGuild)
        if (alliance->GetLeader() != guild)
        {
            psserver->SendSystemError(clientnum,"Your guild must be alliance leader to be able to remove other guilds.");
            return;
        }

    if (alliance->RemoveMember(removedGuild))
        psserver->SendSystemInfo(clientnum,"Guild \"%s\" was removed from alliance.", removedGuild->name.GetData());
    else
        psserver->SendSystemInfo(clientnum,"Failed to remove guild from alliance: %s", psGuildAlliance::lastError.GetData());
    
    SendNoAllianceNotifications(removedGuild);
    SendAllianceNotifications(alliance);
}

void GuildManager::AllianceLeader(psGuildCmdMessage &msg, Client *client)
{
    psGuildInfo * guild;
    psGuildAlliance * alliance;

    int clientnum = client->GetClientNum();
    
    if ( ! CheckAllianceOperation(client, true, guild, alliance))
        return;
    
    if (msg.guildname.Length()==0)
    {
        psserver->SendSystemError(clientnum,"Please specify name of the guild to be new alliance leader.");
        return;
    }

    psGuildInfo * newLeader = CacheManager::GetSingleton().FindGuild(msg.guildname);
    if (newLeader == NULL)
    {
        psserver->SendSystemError(clientnum,"No such guild exists.");
        return;
    }
    
    if (guild == newLeader)
    {
        psserver->SendSystemError(clientnum,"You must specify other guild than your own.");
        return;
    }
    
    if ( ! alliance->CheckMembership(newLeader))
    {
        psserver->SendSystemError(clientnum,"This guild is not member of your alliance !");
        return;
    }
    
    if (alliance->SetLeader(newLeader))
        psserver->SendSystemInfo(clientnum,"Alliance leadership was transfered to %s.", newLeader->name.GetData());
    else
        psserver->SendSystemInfo(clientnum,"Failed to transfer alliance leadership: %s.", psGuildAlliance::lastError.GetData());
    
    SendAllianceNotifications(alliance);
}

void GuildManager::EndAlliance(psGuildCmdMessage &msg, Client *client)
{
    psGuildInfo * guild;
    psGuildAlliance * alliance;

    int clientnum = client->GetClientNum();
    
    if ( ! CheckAllianceOperation(client, true, guild, alliance))
        return;

    SendNoAllianceNotifications(alliance);
    
    if (CacheManager::GetSingleton().RemoveAlliance(alliance))
        psserver->SendSystemInfo(clientnum,"Alliance was disbanded.");
    else
        psserver->SendSystemInfo(clientnum,"Failed to disband alliance: %s.", psGuildAlliance::lastError.GetData());
}

bool GuildManager::FilterGuildName(const char* name)
{
    if (name == NULL)
        return false;

    size_t len = strlen(name);

    if ( (strspn(name,"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ")
                != len) )
        return false;

    if ((strspn(((const char*)name)+1,
                     (const char*)"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ") != len - 1))
        return false;

    return true;
}

void GuildManager::SendGuildPoints(psGuildCmdMessage& msg,Client *client)
{
    psGuildInfo* guild = NULL;

    if(msg.guildname.Length() == 0)
        guild = CacheManager::GetSingleton().FindGuild(client->GetGuildID());
    else
        guild = CacheManager::GetSingleton().FindGuild(msg.guildname);

    if(!guild)
    {
        csString error;
        error = "Couldn't find the guild " + msg.guildname;
        error += "you specified";

        psserver->SendSystemError(client->GetClientNum(),error);
        return;
    }

    csString info;
    info.Format("The guild %s has %d karma points",guild->GetName().GetData(),guild->karma_points);

    psserver->SendSystemInfo(client->GetClientNum(),info);
}

void GuildManager::ResendGuildData(int id)
{
    SendNotifications(id, psGUIGuildMessage::GUILD_DATA);
}

