// MorgenGrauen MUDlib
//
// container/items.c -- creating extra items in room
//
// $Id: items.c 8811 2014-05-09 17:30:37Z Zesstra $

// extra items handling
//
//	AddItem(string filename, int refresh)
//	  Clones an item and puts it into the room. <refresh> may be
//	  on of the following:
//	  REFRESH_NONE: No refresh done until reboot.
//	  REFRESH_DESTRUCT: Refresh on reset if item was destructed.
//	  REFRESH_REMOVE: Refresh on reset if item was removed from room.
//	  REFRESH_ALWAYS: Create a new clone on every reset.
//
// The commands are implemented as properties P_ITEMS as mapping. They are 
// stored locally (_set_xx) as mapping to speed up the routines 
// in this module.
// 
// Format of key and data in the P_ITEMS mapping:
//
// ([ key1 : refresh1; obp1; arr1, ..., keyn : refreshn; obpn; arrn ])

#include <sys_debug.h>
#pragma strict_types
#pragma save_types
#pragma range_check
#pragma no_clone
#pragma pedantic

#define NEED_PROTOTYPES
#include <thing/properties.h>
#include <rooms.h>
#include <container.h>
#undef NEED_PROTOTYPES
#include <defines.h>
#include <config.h>
#include <properties.h>
#include <moving.h>
#include <daemon.h>

protected void create()
{ 
  Set(P_ITEMS,({}));
  Set(P_ITEMS,SECURED,F_MODE_AS);
  
  OBJECTD->QueryObject();  // querying general objects
}

protected void create_super()
{
  set_next_reset(-1);
}

/* Kram zum Aufraeumen von multiplen gleichen Items im Container. */
private object removeable_ob(object ob)
{
  if(!query_once_interactive(ob) && !living(ob))
  {
    return ob;
  }

  return 0;
}

protected varargs void remove_multiple(int limit, mixed fun)
{
  object *inh = all_inventory(ME)-({0});

  inh=filter(inh,#'removeable_ob);
  foreach(mixed item : QueryProp(P_ITEMS))
  {
    inh-=({item[0]});
  }

  if(!stringp(fun) && !closurep(fun))
  {
    fun="description_id";
  }
  inh=unique_array(inh,fun,0);
  foreach(mixed arr : inh)
  {
    if(sizeof(arr)<=limit)
    {
      continue;
    }
    catch(call_other(arr[limit ..], "remove"); publish);
  }
}


/* Item handling */
public varargs object AddItem(mixed filename, int refresh, mixed props) 
{
  string file;
  object ob;
  int i;

  if(pointerp(filename))
  {
    for(i=sizeof(filename);i--;)
    {
      filename[i] = (string)master()->_get_path( filename[i], "?" );
    }
      
    file=filename[random(sizeof(filename))];
  }
  else 
  {
    file=filename=(string)master()->_get_path(filename,"?");
  }
  
  if(props==1)
  {
    catch(ob=load_object(file); publish);
  }
  else
  {
    catch(ob=clone_object(file); publish);
  }
  
  if(objectp(ob))
  {
    ob->move(ME,M_NOCHECK|M_NO_ATTACK);
    // mit Absicht keine Pruefung aufs Move, wenns nicht geht, solls 2s
    // spaeter auf der Ebene buggen, weil praktisch niemand im create() das
    // Ergebnis vom AddItem() prueft.
  }

  // In P_ITEMS vermerken, es sei denn, REFRESH_NONE ist gegeben, in dem
  // Fall ist die Speicherung voellig unnoetig.
  // TODO: Pruefen, ob das wirklich problemlos geht. Bis dahin werden auch
  // TODO::REFRESH_NONE-Items vermerkt. (s. clean_up() in /std/room.c)
  //if (!(refresh&REFRESH_NONE)) {
    SetProp(P_ITEMS,QueryProp(P_ITEMS)+
      ({ 
        ({
          ob,        // RITEM_OBJECT
          filename,  // RITEM_FILE
          refresh    // RITEM_REFRESH
        })+
        ((mappingp(props) || props==1) ? ({props}) : ({}))
      }));
  //}

  if(ob && mappingp(props)) 
    walk_mapping(props,symbol_function("SetProp",ob));
  
  return ob;
}


private void ri_rem_ob(object ob)
{
  object *inv;

  if(objectp(ob) && environment(ob)==this_object())
  {
    inv=deep_inventory(ob);

    foreach(object o : inv)
    {
      o->remove(1);
      if(objectp(o))
      {
        destruct(o);
      }
    }

    ob->remove(1);

    if(ob)
    {
      destruct(ob);
    }
  }
}

private int ri_filter(<int|<string|string*>|object|mapping>* ritem, 
  string|string* file)
{
  object ob;
  
  ob=ritem[RITEM_OBJECT];
  
  if(stringp(file) && ritem[RITEM_FILE]==file)
  {
    ri_rem_ob(ob);
    return 0;
  }
  else if(pointerp(ritem[RITEM_FILE]) && pointerp(file) &&
          sizeof(file & ritem[RITEM_FILE])==sizeof(ritem[RITEM_FILE]))
  {
    ri_rem_ob(ob);
    return 0;
  }

  return 1;
}


public void RemoveItem(string|string* filename)
{
  < <int|<string|string*>|object>* >* items=QueryProp(P_ITEMS);

  if(!pointerp(items) || !sizeof(items))
  {
    return;
  }

  if(pointerp(filename))
  {
    foreach(string fn: &filename)
    {
      fn=master()->_get_path(fn,"?");
    }
  }
  else
  {
    filename=master()->_get_path( filename,"?");
  }
  
  SetProp(P_ITEMS,filter(items, #'ri_filter/*'*/,filename));
}

private mixed _do_refresh(mixed item)
{
  string file;
  object ob;

  if(!pointerp(item) || item[RITEM_REFRESH]==REFRESH_NONE)
  {
    return item;
  }

  if(pointerp(item[RITEM_FILE])) 
  {
    file=item[RITEM_FILE][random(sizeof(item[RITEM_FILE]))];
  }
  else
  {
    file=item[RITEM_FILE];
  }

  switch(item[RITEM_REFRESH])
  {
    case REFRESH_MOVE_HOME:
      if(objectp(item[RITEM_OBJECT]) &&
        environment(item[RITEM_OBJECT])!=ME)
      {
        item[RITEM_OBJECT]->move(ME,M_GO|M_NO_ATTACK);
        break;
      }
      
    // fall through
    case REFRESH_DESTRUCT:
      if(objectp(item[RITEM_OBJECT])) 
        break; // else FALL THROUGH
      
    case REFRESH_REMOVE:
      if(objectp(item[RITEM_OBJECT]) &&
        environment(item[RITEM_OBJECT])==ME)
        break; // else FALL THROUGH
      
    default:
      if(sizeof(item)>RITEM_PROPS && item[RITEM_PROPS]==1)
      {
        ob=load_object(file);
      }
      else
      {
        ob=clone_object(file);
      }

      ob->move(ME,M_NOCHECK|M_NO_ATTACK);
      break;
  }
  
  if(ob)
  {
    item[RITEM_OBJECT]=ob;
      
    if(sizeof(item)>RITEM_PROPS && mappingp(item[RITEM_PROPS]))
      walk_mapping(item[RITEM_PROPS],symbol_function("SetProp",ob));
  }
  
  return item;
}


// reset handling: check how the items should be refreshed.
void reset() 
{
  mixed *items;

  if(!pointerp(items=QueryProp(P_ITEMS)))
  {
    SetProp(P_ITEMS,({}));
    return;
  }
  
  SetProp(P_ITEMS,map(items,#'_do_refresh)-({0}));
}

