/*

 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.
 
*/

#include "commands.h"
#include "resets.h"

void ResetMob (Object & reset)
  {
  string target = reset.gets ("target");
  
  // find the mob in the prototype list
  ObjectIter iWhat = FindObject (mobs (), "id", target);
  if (iWhat == mobs ().end ())
    throw runtime_error ("Mob " + target + " not found in mobs list");
  
  // create a copy
  auto_ptr<Character> mob (new Character);

  // copy base attributes
  CopyThing (*iWhat, *mob);
  int room = reset.geti ("vnum");
  
  // put in the room indicated by the reset
  mob->seti ("room", room);

//  cout << "Creating mob " << mob->gets ("name") << " in room " << room << endl;
  
  // give it a unique ID
  string id = UniqueID ();    // another id for the copy of the mob
  mob->sets ("id", id);

  // release auto-ptr, put into mob list
  Character * m = mob.release ();
  moblist ().push_back (m);
  playing () [id] = m;

  // if not a sentinel mob, generate a move event for it
  if (!m->getb ("sentinel"))
    {
    Event e ("EventMoveMob", 30000, -1, 0);  // make it move around indefinitely
    e.sets ("id", id); // which mob
    eventQueue ().push (e); // queue it
    } // end of making event
  
  } // end of ResetMob

void ResetObject (Object & reset)
{
  string target = reset.gets ("target");

  // find the object in the prototype list
  ObjectIter iWhat = FindObject (objects (), "id", target);
  if (iWhat == objects ().end ())
    throw runtime_error ("Object " + target + " not found in objects list");

  // find room to put it into
  World & room = FindRoom (reset.geti ("vnum"));
  
  // make a copy of it
  Object obj = *iWhat;
  
  // give it a unique ID
  GiveUniqueID (obj); // give object and all its children unique IDs
  
  // put object into room
  room.contents ().push_back (obj);   // put it into the room
  
} // end of ResetObject

void fProcessReset (Object & reset)
  {  
  string type = tolower (reset.gets ("type"));
  
  try
    {
    try
      {
      if (type == "m")
        ResetMob (reset);
      else if (type == "o")
        ResetObject (reset);
      else
        throw runtime_error ("Unknown reset type: " + type);
      
      } // end of try for msg exceptions
    catch (msg & e)
      {
      // re-throw with code substitution
      throw runtime_error (convertErrorCode (e.what ()));
      }    
    } // end of try for exceptions
  // catch exceptions during events
  
// we need to catch exceptions here because we are not in the main player loop
// if we don't the program ends... blah!
// we hope to not get them, so we will output a fair bit of debugging stuff
  
  catch (exception & e)
    {
    ThingMap t;
    
    t ["vnum"].sets ("short", MAKE_STRING (reset.geti ("vnum")));
    
    // substitute (eg. which vnum is missing)
    string message = FixMessage (control ().gets ("default_prefix"), e.what (), t, false);
        
    // notify admins
    SendToAll (MAKE_STRING ("`RNOTIFY: Exception during reset " << type 
                << ": " <<  message << "`X\n"), "notify_admin");
    
    // log it
    gamelog (MAKE_STRING ("Reset (" << type << ") exception: " <<  message));

    // output to stderr
    cerr << "EXCEPTION during reset type " << type << endl;
    cerr << "          Error: " << message << endl;
    if (!reset.empty ())    // output reset parameters, if any
      {
      cerr << " <reset>\n";
      cerr << reset;
      cerr << " </reset>" << endl;
      }

    } // end of catch
  
  } // end of fProcessReset

void ProcessResets ()
  {
  cout << "Resetting MUD ..." << endl;
  // process entire resets list
  for_each (ISEQ (resets ()), fProcessReset);
  }
