/*

 BabbleMud - A MUD server

 Author:  Nick Gammon 
          http://www.gammon.com.au/ 

(C) Copyright Nick Gammon 2004. Permission to copy, use, modify, sell and
distribute this software is granted provided this copyright notice appears
in all copies. This software is provided "as is" without express or implied
warranty, and with no claim as to its suitability for any purpose.
 
*/

#ifdef WIN32
#include <time.h>
#endif

#include "commands.h"

//~ PLAYER (number):
  
const string ROOM = "room";     // current room

void EventSendToAll (const Event & e)
  {
  SendToAll ("msg", e.get_sdata (), ThingMap (), NULL, NULL, e.geti ("room")); 
  } // end of EventSendToAll

void EventApplyEffect (const Event & e)
  {
Character * p = FindPlayerID (e.gets ("id"));
  
  if (p == NULL)
     return;    // not there, can't do it  -- TODO: should we delete the event?
  
  string effect = e.gets ("effect");  // what to effect
  int by = e.geti ("by");             // by how much
  
  int value = p->geti (effect);  // current value
  value += by;  // amend it
  if (value < 0)
    value = 0;  // not negative
  p->seti (effect, value);   // set new value

  string msg;
  // send messages if not empty
  msg = e.gets ("msg_target");
  if (!msg.empty ())
    p->send ("msg_target", e.get_sdata ());    // player
  
  // who the target is, for the "msg_room" messages
  ThingMap sub;
  sub ["target"] = *p;
  
  msg = e.gets ("msg_room");
  if (!msg.empty ())
    SendToAll ("msg_room", e.get_sdata (), sub, p, NULL, p->geti (ROOM));    // room he is currently in
  
  } // end of EventApplyEffect

void EventMoveMob (Event & e)
  {
Character * p = FindPlayerID (e.gets ("id"));
     
  if (p == NULL)
    {
    e.SetCount (0); // delete event
    return;    // not there, can't do it 
    }
  
  Room & r = FindRoom (p->geti (ROOM));  // find room it is in

  vector<string> v;
  for (ObjectIter exititer = r.exits ().begin ();
       exititer != r.exits ().end (); 
      ++exititer)
    if (exititer->gets ("handler") == "DoDirection" &&  // a direction exit
        !exititer->getb ("nomob"))      // allowed to mobs
       v.push_back (exititer->gets ("short"));
  
  if (v.empty ())
    {
    warnAdmin ("Mob " + e.gets ("id") + " cannot move, event deleted.");
    e.SetCount (0); // delete event
    return;
    }
  
  // get a random one to the front
  random_shuffle (ISEQ (v));

  p->DoCommand (v [0]);   // send movement command (eg. north)
  
  } // end of EventMoveMob

struct checkIdlePlayers
{
const int connectingLimit_;
const int playingLimit_;

  checkIdlePlayers (const int connectingLimit, 
                    const int playingLimit) 
      : connectingLimit_ (connectingLimit), playingLimit_ (playingLimit) {}
  
  // handle this player
  void operator() (Player * p) 
    {
    // forget it if no connection or leaving us
    if (!p->Connected () || p->closing_)
      return;
    
    // playing players have a different time-limit to connecting ones
    if (p->IsPlaying ())
      {
      if (p->GetLastCommandTime () < playingLimit_)
         {
         p->send ("\n\n" + p->message ("idle_timeout_playing"));
         p->ClosePlayer ();
         }  // end of timeout on playing player
      
      }   // end of playing
    else
      {
      if (p->GetLastCommandTime () < connectingLimit_)
        {
         p->send ("\n\n" + p->message ("idle_timeout_connecting"));
         p->ClosePlayer ();
        } // end of timeout on connecting player
      
      } // end of connecting
       
    } // end of operator()  
      
};  // end of checkIdlePlayers

// check for idle players - the check is done every minute
void EventCheckIdle (const Event & e)
  {
static int connectingIdleTimeoutSeconds = control ().geti ("idle_timeout_minutes_connect") * 60;
static int playingIdleTimeoutSeconds    = control ().geti ("idle_timeout_minutes_playing") * 60;

time_t now = time (NULL);
 
  for_each (ISEQ (playerlist ()), 
            checkIdlePlayers (now - connectingIdleTimeoutSeconds, 
                              now - playingIdleTimeoutSeconds));      
  }

void MainEventHandler (Event & e)
  {
  
  switch (e.GetType ())
    {
    case eSendToAll:  EventSendToAll    (e);  break; 
    case eEffect:     EventApplyEffect  (e);  break;
    case eMoveMob:    EventMoveMob      (e);  break;
    case eCheckIdle:  EventCheckIdle    (e);  break;
    
    } // end of switch on event type
  } // end of MainEventHandler

