/*

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

// standard library includes ...

#include <iterator>
#include <stdexcept>
#include <fstream>

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

using namespace std; 

#include "utils.h"
#include "object.h"
#include "regexp.h"
#include "globals.h"
#include "exceptions.h"

// get item from container
ObjectList::const_iterator findItem (const string & what, 
                                     const ObjectList & container,
                                     const string & message)
{

StringMap wildcards;

  ObjectList::const_iterator i = FindObjectRegexp (container, "match", what, wildcards);

   // not found? error
  if (i == container.end ())
    throw msg (message);
  
  // return iterator to it
  return i;
  } // end of findItem

// get item from container
ObjectList::iterator findItem (const string & what, 
                               ObjectList & container,
                               const string & message)
{

StringMap wildcards;

  ObjectList::iterator i = FindObjectRegexp (container, "match", what, wildcards);

   // not found? error
  if (i == container.end ())
    throw msg (message);
  
  // return iterator to it
  return i;
  } // end of findItem

// move item from source container to destination container
void moveItem (ObjectList & source,      // source container
              ObjectList::iterator item, // iterator to item
              ObjectList & destination)  // destination container
  {
  if (&source == &destination)
    return;   // don't move to itself
  destination.push_back (*item);   // add to destination
  source.erase (item);    // erase from source
  } // end of moveItem
  
// flag must be set
void Object::NeedFlag (const string & name, const string & message, const bool lookedUp) const
{
  if (!name.empty () && !getb (name))
    NotPermitted (message, lookedUp);
} // end of NeedFlag


// flag must not be set
void Object::NeedNoFlag (const string & name, const string & message, const bool lookedUp) const
{
  if (!name.empty () && getb (name))
    NotPermitted (message, lookedUp);
} // end of NeedNoFlag

 // functor to help finding a object by using a regexp
struct fFindObjectRegexp : unary_function<const Object &, bool>
{
  const string key_;
  const string target_;
  StringMap & wildcards_;

  // ctor
  fFindObjectRegexp (const string & key,
                     const string & target,
                     StringMap & wildcards)
      : key_ (key), target_ (target), wildcards_ (wildcards) {}
  // check for item with matching field
  bool operator() (const Object & t) const
    {
    Regexp regexp (t.gets (key_), PCRE_CASELESS);
    if (regexp.Execute (target_))  // true if match
      {
      regexp.BuildResultMap (wildcards_);
      return true;
      }
    return false;
    } // end of operator()
};  // end of fFindObjectRegexp

  
// find an iterator to a object in a list of objects, matching key=target
// where key evaluates to a regular expression
// eg, container might be a list of exits
//     key might be "match"  (what field to match)
//     target might be "north"
//     and in a particular exit match="n|north"
ObjectList::const_iterator FindObjectRegexp (const ObjectList & container,
                                       const string & key,
                                       const string & target,
                                       StringMap & wildcards)
{
//  writeList (cout, "test", container);
  return find_if (ISEQ (container), fFindObjectRegexp (key, target, wildcards));
} /* end of FindObjectRegexp */

// non-const version
ObjectList::iterator FindObjectRegexp (ObjectList & container,
                                       const string & key,
                                       const string & target,
                                       StringMap & wildcards)
{
//  writeList (cout, "test", container);
  return find_if (ISEQ (container), fFindObjectRegexp (key, target, wildcards));
} /* end of FindObjectRegexp */

// functor to help finding a object by using a direct match
struct fFindObject : unary_function<const Object &, bool>
{
  const string key_;
  const string target_;
  
  // ctor
  fFindObject (const string & key, 
               const string & target) 
      : key_ (key), target_ (target){} 
  // check for item with matching field
  bool operator() (const Object & t) const
    {
    return ciStringEqual (target_, t.gets (key_));
    } // end of operator()  
};  // end of fFindObject

  
// find an iterator to a object in a list of objects, matching key=target
// where key matches exactly
// eg, a command handler
ObjectList::iterator FindObject (ObjectList & container, 
                                 const string & key, 
                                 const string & target)
{
  return find_if (ISEQ (container), fFindObject (key, target));
} /* end of FindObject */

// functor to help finding a object by using a direct match
struct fFindObjectByNumber : unary_function<const Object &, bool>
{
  const string key_;
  const int target_;
  
  // ctor
  fFindObjectByNumber (const string & key, 
                      const int target) 
      : key_ (key), target_ (target){} 
  // check for item with matching field
  bool operator() (const Object & t) const
    {
    return target_ == t.geti (key_);
    } // end of operator()  
};  // end of fFindObjectByNumber

  
// find an iterator to a object in a list of objects, matching key=target
// where key matches exactly
// -- this version is for numeric keys, such as vnums
ObjectList::iterator FindObject (ObjectList & container, 
                                 const string & key, 
                                 const int target)
{
  return find_if (ISEQ (container), fFindObjectByNumber (key, target));
} /* end of FindObject */

// object short description
const string shortDesc (const Object & object, const string & prefix) 
      { 
      return object.gets (prefix + "short", control ().gets (prefix + "unnamed_object_short")); 
      } // end of shortDesc
      
// long description
const string longDesc (const Object & object, const string & prefix)  
      { 
      return object.gets (prefix + "long", control ().gets (prefix + "unnamed_object_long")); 
      } // end of longDesc

// gives an object, and all its owned objects, a unique ID
void GiveUniqueID (Object & o)
  {
  o.sets ("id", UniqueID ());
  // do all children
  for_each (ISEQ (o.contents_), GiveUniqueID);
  }
