dw_fluffos_v2/
dw_fluffos_v2/fluffos-2.9-ds2.05/
dw_fluffos_v2/fluffos-2.9-ds2.05/ChangeLog.old/
dw_fluffos_v2/fluffos-2.9-ds2.05/Win32/
dw_fluffos_v2/fluffos-2.9-ds2.05/compat/
dw_fluffos_v2/fluffos-2.9-ds2.05/compat/simuls/
dw_fluffos_v2/fluffos-2.9-ds2.05/include/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/clone/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/command/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/data/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/etc/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/include/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/inherit/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/inherit/master/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/log/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/compiler/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/efuns/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/operators/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/u/
dw_fluffos_v2/fluffos-2.9-ds2.05/tmp/
dw_fluffos_v2/fluffos-2.9-ds2.05/windows/
dw_fluffos_v2/lib/
dw_fluffos_v2/lib/binaries/cmds/
dw_fluffos_v2/lib/binaries/cmds/creator/
dw_fluffos_v2/lib/binaries/cmds/living/
dw_fluffos_v2/lib/binaries/cmds/player/
dw_fluffos_v2/lib/binaries/d/admin/obj/
dw_fluffos_v2/lib/binaries/d/liaison/
dw_fluffos_v2/lib/binaries/global/virtual/
dw_fluffos_v2/lib/binaries/global/virtual/setup_compiler/
dw_fluffos_v2/lib/binaries/obj/handlers/autodoc/
dw_fluffos_v2/lib/binaries/obj/handlers/terrain_things/
dw_fluffos_v2/lib/binaries/obj/misc/
dw_fluffos_v2/lib/binaries/obj/misc/buckets/
dw_fluffos_v2/lib/binaries/obj/monster/
dw_fluffos_v2/lib/binaries/obj/reactions/
dw_fluffos_v2/lib/binaries/obj/reagents/
dw_fluffos_v2/lib/binaries/secure/cmds/creator/
dw_fluffos_v2/lib/binaries/secure/master/
dw_fluffos_v2/lib/binaries/std/
dw_fluffos_v2/lib/binaries/std/dom/
dw_fluffos_v2/lib/binaries/std/effects/object/
dw_fluffos_v2/lib/binaries/std/guilds/
dw_fluffos_v2/lib/binaries/std/languages/
dw_fluffos_v2/lib/binaries/std/races/
dw_fluffos_v2/lib/binaries/std/room/
dw_fluffos_v2/lib/binaries/std/room/basic/
dw_fluffos_v2/lib/binaries/std/shops/
dw_fluffos_v2/lib/binaries/std/shops/inherit/
dw_fluffos_v2/lib/binaries/www/
dw_fluffos_v2/lib/cmds/guild-race/
dw_fluffos_v2/lib/cmds/guild-race/crafts/
dw_fluffos_v2/lib/cmds/guild-race/other/
dw_fluffos_v2/lib/cmds/playtester/
dw_fluffos_v2/lib/cmds/playtester/senior/
dw_fluffos_v2/lib/d/admin/
dw_fluffos_v2/lib/d/admin/log/
dw_fluffos_v2/lib/d/admin/mapper/31-10-01/mapmaker/event/
dw_fluffos_v2/lib/d/admin/meetings/
dw_fluffos_v2/lib/d/admin/obj/
dw_fluffos_v2/lib/d/admin/room/we_care/
dw_fluffos_v2/lib/d/admin/save/
dw_fluffos_v2/lib/d/dist/
dw_fluffos_v2/lib/d/dist/mtf/
dw_fluffos_v2/lib/d/dist/pumpkin/
dw_fluffos_v2/lib/d/dist/pumpkin/chars/
dw_fluffos_v2/lib/d/dist/pumpkin/desert/
dw_fluffos_v2/lib/d/dist/pumpkin/gumboot/
dw_fluffos_v2/lib/d/dist/pumpkin/hospital/
dw_fluffos_v2/lib/d/dist/pumpkin/inherit/
dw_fluffos_v2/lib/d/dist/pumpkin/map/
dw_fluffos_v2/lib/d/dist/pumpkin/plain/
dw_fluffos_v2/lib/d/dist/pumpkin/pumpkin/
dw_fluffos_v2/lib/d/dist/pumpkin/save/
dw_fluffos_v2/lib/d/dist/pumpkin/squash/
dw_fluffos_v2/lib/d/dist/pumpkin/terrain/
dw_fluffos_v2/lib/d/dist/pumpkin/woods/
dw_fluffos_v2/lib/d/dist/start/
dw_fluffos_v2/lib/d/learning/TinyTown/buildings/
dw_fluffos_v2/lib/d/learning/TinyTown/map/
dw_fluffos_v2/lib/d/learning/TinyTown/roads/
dw_fluffos_v2/lib/d/learning/add_command/
dw_fluffos_v2/lib/d/learning/arms_and_weps/
dw_fluffos_v2/lib/d/learning/chars/
dw_fluffos_v2/lib/d/learning/cutnpaste/
dw_fluffos_v2/lib/d/learning/examples/npcs/
dw_fluffos_v2/lib/d/learning/examples/player_houses/npcs/
dw_fluffos_v2/lib/d/learning/examples/terrain_map/basic/
dw_fluffos_v2/lib/d/learning/functions/
dw_fluffos_v2/lib/d/learning/handlers/
dw_fluffos_v2/lib/d/learning/help_topics/npcs/
dw_fluffos_v2/lib/d/learning/help_topics/objects/
dw_fluffos_v2/lib/d/learning/help_topics/rcs_demo/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/crowd/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/situations/
dw_fluffos_v2/lib/d/learning/items/
dw_fluffos_v2/lib/d/learning/save/
dw_fluffos_v2/lib/d/liaison/
dw_fluffos_v2/lib/d/liaison/NEWBIE/doc/
dw_fluffos_v2/lib/d/liaison/NEWBIE/save/oldlog/
dw_fluffos_v2/lib/db/
dw_fluffos_v2/lib/doc/
dw_fluffos_v2/lib/doc/creator/
dw_fluffos_v2/lib/doc/creator/autodoc/include/reaction/
dw_fluffos_v2/lib/doc/creator/autodoc/include/ritual_system/
dw_fluffos_v2/lib/doc/creator/autodoc/include/talker/
dw_fluffos_v2/lib/doc/creator/autodoc/include/terrain_map/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/baggage/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/clock/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/clothing/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/cont_save/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/corpse/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/money/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/monster/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/scabbard/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/service_provider/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/state_changer/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/wand/
dw_fluffos_v2/lib/doc/creator/autodoc/std/book_dir/
dw_fluffos_v2/lib/doc/creator/autodoc/std/key/
dw_fluffos_v2/lib/doc/creator/autodoc/std/learning/
dw_fluffos_v2/lib/doc/creator/autodoc/std/map/
dw_fluffos_v2/lib/doc/creator/autodoc/std/race/
dw_fluffos_v2/lib/doc/creator/autodoc/std/weapon_logic/
dw_fluffos_v2/lib/doc/creator/files/
dw_fluffos_v2/lib/doc/creator/policy/
dw_fluffos_v2/lib/doc/creator/room/
dw_fluffos_v2/lib/doc/effects/
dw_fluffos_v2/lib/doc/ideas/
dw_fluffos_v2/lib/doc/known_command/
dw_fluffos_v2/lib/doc/lpc/basic_manual/
dw_fluffos_v2/lib/doc/lpc/intermediate/
dw_fluffos_v2/lib/doc/new/add_command/
dw_fluffos_v2/lib/doc/new/handlers/
dw_fluffos_v2/lib/doc/new/living/
dw_fluffos_v2/lib/doc/new/living/race/
dw_fluffos_v2/lib/doc/new/living/spells/
dw_fluffos_v2/lib/doc/new/player/
dw_fluffos_v2/lib/doc/new/room/guild/
dw_fluffos_v2/lib/doc/new/room/outside/
dw_fluffos_v2/lib/doc/new/room/storeroom/
dw_fluffos_v2/lib/doc/object/
dw_fluffos_v2/lib/doc/playtesters/
dw_fluffos_v2/lib/doc/policy/
dw_fluffos_v2/lib/doc/weapons/
dw_fluffos_v2/lib/global/handlers/
dw_fluffos_v2/lib/global/virtual/setup_compiler/
dw_fluffos_v2/lib/include/
dw_fluffos_v2/lib/include/cmds/
dw_fluffos_v2/lib/include/effects/
dw_fluffos_v2/lib/include/npc/
dw_fluffos_v2/lib/include/shops/
dw_fluffos_v2/lib/net/daemon/chars/
dw_fluffos_v2/lib/net/inherit/
dw_fluffos_v2/lib/net/intermud3/
dw_fluffos_v2/lib/net/intermud3/services/
dw_fluffos_v2/lib/net/obj/
dw_fluffos_v2/lib/net/save/
dw_fluffos_v2/lib/net/smnmp/
dw_fluffos_v2/lib/net/snmp/
dw_fluffos_v2/lib/obj/amulets/
dw_fluffos_v2/lib/obj/b_day/
dw_fluffos_v2/lib/obj/examples/
dw_fluffos_v2/lib/obj/food/alcohol/
dw_fluffos_v2/lib/obj/food/chocolates/
dw_fluffos_v2/lib/obj/food/fruits/
dw_fluffos_v2/lib/obj/food/meat/
dw_fluffos_v2/lib/obj/food/nuts/
dw_fluffos_v2/lib/obj/food/seafood/
dw_fluffos_v2/lib/obj/food/vegetables/
dw_fluffos_v2/lib/obj/fungi/
dw_fluffos_v2/lib/obj/furnitures/artwork/
dw_fluffos_v2/lib/obj/furnitures/bathroom/
dw_fluffos_v2/lib/obj/furnitures/beds/
dw_fluffos_v2/lib/obj/furnitures/cabinets/
dw_fluffos_v2/lib/obj/furnitures/chairs/
dw_fluffos_v2/lib/obj/furnitures/chests/
dw_fluffos_v2/lib/obj/furnitures/clocks/
dw_fluffos_v2/lib/obj/furnitures/crockery/
dw_fluffos_v2/lib/obj/furnitures/cupboards/
dw_fluffos_v2/lib/obj/furnitures/cushions/
dw_fluffos_v2/lib/obj/furnitures/fake_plants/
dw_fluffos_v2/lib/obj/furnitures/lamps/
dw_fluffos_v2/lib/obj/furnitures/mirrors/
dw_fluffos_v2/lib/obj/furnitures/outdoor/
dw_fluffos_v2/lib/obj/furnitures/safes/
dw_fluffos_v2/lib/obj/furnitures/shelves/
dw_fluffos_v2/lib/obj/furnitures/sideboards/
dw_fluffos_v2/lib/obj/furnitures/sofas/
dw_fluffos_v2/lib/obj/furnitures/stoves/
dw_fluffos_v2/lib/obj/furnitures/tables/
dw_fluffos_v2/lib/obj/furnitures/wardrobes/
dw_fluffos_v2/lib/obj/handlers/
dw_fluffos_v2/lib/obj/handlers/autodoc/
dw_fluffos_v2/lib/obj/jewellery/anklets/
dw_fluffos_v2/lib/obj/jewellery/bracelets/
dw_fluffos_v2/lib/obj/jewellery/earrings/
dw_fluffos_v2/lib/obj/jewellery/misc/
dw_fluffos_v2/lib/obj/jewellery/necklaces/
dw_fluffos_v2/lib/obj/jewellery/rings/
dw_fluffos_v2/lib/obj/media/
dw_fluffos_v2/lib/obj/misc/buckets/
dw_fluffos_v2/lib/obj/misc/jars/
dw_fluffos_v2/lib/obj/misc/papers/
dw_fluffos_v2/lib/obj/misc/player_shop/
dw_fluffos_v2/lib/obj/misc/shops/
dw_fluffos_v2/lib/obj/misc/traps/
dw_fluffos_v2/lib/obj/monster/
dw_fluffos_v2/lib/obj/monster/godmother/
dw_fluffos_v2/lib/obj/monster/transport/
dw_fluffos_v2/lib/obj/plants/inherit/
dw_fluffos_v2/lib/obj/potions/
dw_fluffos_v2/lib/open/boards/
dw_fluffos_v2/lib/save/autodoc/
dw_fluffos_v2/lib/save/bank_accounts/
dw_fluffos_v2/lib/save/boards/frog/
dw_fluffos_v2/lib/save/books/bed_catalog/
dw_fluffos_v2/lib/save/creators/
dw_fluffos_v2/lib/save/mail/
dw_fluffos_v2/lib/save/mail/p/
dw_fluffos_v2/lib/save/soul/data/
dw_fluffos_v2/lib/save/tasks/
dw_fluffos_v2/lib/save/vaults/
dw_fluffos_v2/lib/secure/cmds/lord/
dw_fluffos_v2/lib/secure/config/
dw_fluffos_v2/lib/secure/items/
dw_fluffos_v2/lib/secure/player/
dw_fluffos_v2/lib/soul/
dw_fluffos_v2/lib/soul/i/
dw_fluffos_v2/lib/soul/j/
dw_fluffos_v2/lib/soul/k/
dw_fluffos_v2/lib/soul/o/
dw_fluffos_v2/lib/soul/q/
dw_fluffos_v2/lib/soul/to_approve/
dw_fluffos_v2/lib/soul/u/
dw_fluffos_v2/lib/soul/v/
dw_fluffos_v2/lib/soul/wish_list/
dw_fluffos_v2/lib/soul/y/
dw_fluffos_v2/lib/soul/z/
dw_fluffos_v2/lib/std/creator/
dw_fluffos_v2/lib/std/effects/
dw_fluffos_v2/lib/std/effects/attached/
dw_fluffos_v2/lib/std/effects/external/
dw_fluffos_v2/lib/std/effects/fighting/
dw_fluffos_v2/lib/std/effects/other/
dw_fluffos_v2/lib/std/environ/
dw_fluffos_v2/lib/std/guilds/
dw_fluffos_v2/lib/std/hospital/
dw_fluffos_v2/lib/std/house/
dw_fluffos_v2/lib/std/house/onebedhouse/
dw_fluffos_v2/lib/std/house/onebedhut/
dw_fluffos_v2/lib/std/house/tworoomflat/
dw_fluffos_v2/lib/std/languages/
dw_fluffos_v2/lib/std/liquids/
dw_fluffos_v2/lib/std/nationality/
dw_fluffos_v2/lib/std/nationality/accents/
dw_fluffos_v2/lib/std/nationality/accents/national/
dw_fluffos_v2/lib/std/nationality/accents/regional/
dw_fluffos_v2/lib/std/npc/goals/
dw_fluffos_v2/lib/std/npc/goals/basic/
dw_fluffos_v2/lib/std/npc/goals/misc/
dw_fluffos_v2/lib/std/npc/inherit/
dw_fluffos_v2/lib/std/npc/plans/
dw_fluffos_v2/lib/std/npc/plans/basic/
dw_fluffos_v2/lib/std/outsides/
dw_fluffos_v2/lib/std/races/shadows/
dw_fluffos_v2/lib/std/room/basic/topography/
dw_fluffos_v2/lib/std/room/controller/
dw_fluffos_v2/lib/std/room/controller/topography/
dw_fluffos_v2/lib/std/room/furniture/games/
dw_fluffos_v2/lib/std/room/furniture/inherit/
dw_fluffos_v2/lib/std/room/inherit/carriage/
dw_fluffos_v2/lib/std/room/inherit/topography/
dw_fluffos_v2/lib/std/room/punishments/
dw_fluffos_v2/lib/std/room/topography/area/
dw_fluffos_v2/lib/std/room/topography/iroom/
dw_fluffos_v2/lib/std/room/topography/milestone/
dw_fluffos_v2/lib/std/shadows/
dw_fluffos_v2/lib/std/shadows/attached/
dw_fluffos_v2/lib/std/shadows/curses/
dw_fluffos_v2/lib/std/shadows/disease/
dw_fluffos_v2/lib/std/shadows/fighting/
dw_fluffos_v2/lib/std/shadows/room/
dw_fluffos_v2/lib/std/shops/controllers/
dw_fluffos_v2/lib/std/shops/objs/
dw_fluffos_v2/lib/std/shops/player_shop/
dw_fluffos_v2/lib/std/shops/player_shop/office_code/
dw_fluffos_v2/lib/std/socket/
dw_fluffos_v2/lib/www/
dw_fluffos_v2/lib/www/external/autodoc/
dw_fluffos_v2/lib/www/external/java/telnet/Documentation/
dw_fluffos_v2/lib/www/external/java/telnet/Documentation/images/
dw_fluffos_v2/lib/www/external/java/telnet/examples/
dw_fluffos_v2/lib/www/external/java/telnet/tools/
dw_fluffos_v2/lib/www/pics/
dw_fluffos_v2/lib/www/secure/creator/
dw_fluffos_v2/lib/www/secure/editors/
dw_fluffos_v2/lib/www/secure/survey_results/
dw_fluffos_v2/win32/
/**
 * A handler to track player houses.  This handler should only be used for
 * general houses that are available for sale or rent. Don't add club or
 * special (eg. guildmaster) houses here or they'll get sold or rented :)
 *
 * The handler stores information about registered player houses, makes houses
 * vacant if their owners are idle and charges rent on rented houses.
 *
 * @author Ceres
 */

#include <housing.h>
#include <login_handler.h>
#include <am_time.h>
#include <nomic_system.h>

#define BANK "/obj/handlers/bank_handler"
#define DEFAULT_BANK "Bing's First"
#define DEFAULT_PLACE "Ankh-Morpork"
#define MAIL_HANDLER "/obj/handlers/mailer"

#define SAVE_FILE "/save/player_housing/housing"

/**
 * This class stores all the data about a given house. The class is used
 * within the houses mapping. The key of the mapping is the basename of the
 * house (the filename of the main room) and the value is this class, which
 * explains why this class doesn't have a name or filename field for the house.
 *
 * @field other_rooms a string array of the other rooms in the house.
 * @field owner the name of the current owner. This may also be 'For Sale' or
 * 'Under Offer' while the house is vacant or being auctioned.
 * @field region The region the house is in eg. 'Ankh-Morpork'
 * @field type The type of house. 1 for rented, 0 for owned.
 * @field value The current value of the house. For rented houses this is the
 * monthly rent, for owned houses this is the purchase price.
 *
 */
class housing {
  string *other_rooms;
  string owner;
  string address;
  string region;
  int type;
  int value;
  string bank;
}

void load_file();
string query_housing_area_bank(string area);

private nosave string *_tmp_houses;
private nosave string *_tmp_rentals;

private mapping houses;
private int last_paid;
// This is a mapping to setup a link between housing and a specific citizenship
// area.
private mapping _housing_area;
private mapping _area_money;

/** @ignore yes */
void create() {
  houses = ([ ]);
  _housing_area = ([ ]);
  _area_money = ([ ]);
  seteuid("Root");
  load_file();
  if (!_housing_area) {
    _housing_area = ([ ]);
  }
  if (!_area_money) {
    _area_money = ([ ]);
  }
  call_out("check_owners", 900 + random(1800), 0);
  call_out("check_rent", 900 + random(1800));
}

/*
 * Utility functions
 */
/** @ignore yes */
void save_file() {
  unguarded((: cp, SAVE_FILE + ".o", SAVE_FILE + ".o.bak" :));
  unguarded((: save_object, SAVE_FILE :));
}

/** @ignore yes */
void load_file() {
  if (file_size(SAVE_FILE+".o") > 0)
    unguarded((: restore_object, SAVE_FILE :));
}

#ifdef 0
int change() {
  class housing nhouse;
  string house;

  foreach(house in keys(houses)) {
    write(sizeof(houses[house]) + "\n");
    if(sizeof(houses[house]) == 6) {
      nhouse = new(class housing,
                   other_rooms: houses[house]->other_rooms,
                   owner: houses[house]->owner,
                   address: houses[house]->address,
                   region: houses[house]->region,
                   type: houses[house]->type,
                   bank: houses[house]->region
               );
      houses[house] = nhouse;
    }
  }
  save_file();
  return 1;
}
#endif

/**
 * Add a new house to the handler.
 *
 * @param house the basename of the house
 * @param other_rooms an array of other rooms in the house
 * @param address a string for the address
 * @param region the region (used for house sales)
 * @param type an integer. 1 for owned, 0 for rented.
 * @return 1 for success, 0 for failure
 */
int add_house(string house, string *other_rooms, string address,
              string region, int type) {
  if(!houses)
    houses = ([ ]);

  if(houses[house])
    return 0;

  houses[house] = new(class housing,
                      other_rooms: uniq_array(other_rooms),
                      address: address,
                      region: region,
                      type: type,
                      bank: query_housing_area_bank(region)
                  );
  save_file();
  return 1;
}

/**
 * Modify a houses information.
 *
 * @param house the basename of the house
 * @param other_rooms an array of other rooms in the house
 * @param address a string for the address
 * @param region the region (used for house sales)
 * @param type an integer. 1 for owned, 0 for rented.
 * @return 1 for success, 0 for failure
 */
int modify_house(string house, string *other_rooms, string address,
              string region, int type) {
  if(!houses)
    houses = ([ ]);

  if(!houses[house])
    return 0;

  houses[house] = new(class housing,
                      other_rooms: uniq_array(other_rooms),
                      address: address,
                      region: region,
                      type: type,
                      bank: query_housing_area_bank(region));
  save_file();
  return 1;
}

/**
 * Rename a house. This will remove the "main" room and replace it with
 * another.
 * @param house the current basename of the house
 * @param newhouse the new basename.
 */
int rename_house(string house, string newhouse) {
  if(!houses[house])
    return 0;
  if(houses[newhouse])
    return 0;
  houses[newhouse] = houses[house];
  if(member_array(newhouse, houses[newhouse]->other_rooms) != -1)
    houses[newhouse]->other_rooms -= ({ newhouse });
  map_delete(houses, house);
  save_file();
  return 1;
}

/**
 * Remove a house from the list of houses
 *
 * @param house the basename of the house
 * @return 1 for success 0 for failure
 */
int remove_house( string house ) {
  if(!houses[house])
    return 0;
  
  map_delete( houses, house );
  return 1;
}

/**
 * Add secondary rooms to a house.
 *
 * @param house the basename of the house
 * @param an array of basenames for the rooms
 * @return 1 for success 0 for failure
 */
int add_rooms(string house, string *rooms) {
  if(!houses[house])
    return 0;

  houses[house]->other_rooms = uniq_array(houses[house]->other_rooms + rooms);
  save_file();
  return 1;
}

/**
 * Remove secondary rooms from a house.
 *
 * @param house the basename of the house
 * @param an array of basenames for the rooms
 * @return 1 for success 0 for failure
 */
int remove_rooms(string house, string *rooms) {
  if(!houses[house])
    return 0;

  houses[house]->other_rooms -= rooms;
  save_file();
  return 1;
}


/**
 * Set the owner of this house.
 *
 * @param house The basename of the house
 * @param owner The new owner of the house
 * @return 1 for success 0 for failure
 */
int set_owner(string house, string owner) {
  string room;
  
  if(!houses)
    return 0;
  if(!houses[house])
    return 0;
  if(!owner)
    return 0;
  
  // Inform the house and all its rooms that the owner has changed.
  owner = lower_case(owner);
  house->ownership_change(houses[house]->owner, owner);
  foreach(room in houses[house]->other_rooms)
    room->ownership_change(houses[house]->owner, owner);
  
  log_file("HOUSING", "%s Owner for %s set to %s from %s.\n",
           ctime(time())[4..15], house, owner, houses[house]->owner);
  houses[house]->owner = owner;
  save_file();
  return 1;
}

/**
 * Set the region of this house.
 *
 * @param house The basename of the house
 * @param region The new region of the house
 * @return 1 for success 0 for failure
 */
int set_region(string house, string region) {
  if(!houses) {
    return 0;
  }
  if(!houses[house]) {
    return 0;
  }
  if(!stringp(region)) {
    return 0;
  }
  
  // Inform the house and all its rooms that the owner has changed.
  houses[house]->region = region;
  save_file();
  log_file("HOUSING", "%s Region for %s set to %s\n",
           ctime(time())[4..15], house, region);
  return 1;
}

/**
 * Set the address of this house.
 *
 * @param house The basename of the house
 * @param address The new address of the house
 * @return 1 for success 0 for failure
 */
int set_address(string house, string address) {
  if(!houses) {
    return 0;
  }
  if(!houses[house]) {
    return 0;
  }
  if(!stringp(address)) {
    return 0;
  }
  
  // Inform the house and all its rooms that the owner has changed.
  houses[house]->address = address;
  save_file();
  log_file("HOUSING", "%s Address for %s set to %s\n",
           ctime(time())[4..15], house, address);
  return 1;
}

/**
 * Find out the current owner of this house.
 *
 * @param house The basename of the house
 * @return the owners name.
 */
string query_owner(string house) {
  string tmp;
  
  if(!houses)
    return 0;
  if(houses[house])
    return replace(houses[house]->owner, " (In Arrears)", "");

  foreach(tmp in keys(houses))
    if(member_array(house, houses[tmp]->other_rooms) != -1)
      return replace(houses[tmp]->owner, " (In Arrears)", "");
}

/**
 * Check if a given house is registered.
 *
 * @param house The basename of the house
 * @return 1 if its registered, 0 otherwise.
 */
int query_house(string house) {
  if(!houses)
    return 0;
  if(!houses[house])
    return 0;
  return 1;
}

/**
 * Set the bank account to be used for rent on this house.
 *
 * @param house The basename of the house
 * @param owner The new bank to use
 * @return 1 for success 0 for failure
 */
int set_bank(string house, string bank) {
  if(!houses)
    return 0;
  if(!houses[house])
    return 0;
  if(!bank)
    return 0;
  if(((class housing)houses[house])->type != RENT)
    return 0;
  houses[house]->bank = bank;
  save_file();
  return 1;
}

/**
 * Return which bank account rent will be removed from for a house.
 *
 * @param house The basename of the house
 * @return the bank name.
 */
string query_bank(string house) {
  if(!houses)
    return 0;
  if(!houses[house])
    return 0;
  return houses[house]->bank;
}

/**
 * Get a list of the houses rooms.
 *
 * @param house The basename of the house
 * @return a list of rooms.
 */
string *query_rooms(string house) {
  string *tmp;
  
  if(!houses)
    return 0;
  if(!houses[house])
    return 0;

  if(sizeof(houses[house]->other_rooms)) {
    tmp = houses[house]->other_rooms;
    tmp += ({ house });
  } else
    tmp = ({ house });
  
  return tmp;
}

/**
 * Find out the address of a house.
 *
 * @param house The basename of the house
 * @return the address.
 */
string query_address(string house) {
  if(!houses)
    return 0;
  if(!houses[house])
    return 0;

  return houses[house]->address;
}

/**
 * Find out the region a house is in for sale/rental purposes.
 *
 * @param house The basename of the house
 * @return the region.
 */
string query_region(string house) {
  if(!houses)
    return 0;
  if(!houses[house])
    return 0;

  return houses[house]->region;
}
/**
 * Set the type of a house. ie. Whether it's rented or owned.
 * (1 for rented, 0 for owned).
 *
 * @param house The basename of the house
 * @return the type.
 */
int set_type(string house, int type) {
  if(!houses)
    return 0;
  if(!houses[house])
    return 0;
  if(type < 0 || type > 1)
    return 0;

  ((class housing)houses[house])->type = type;
  save_file();

  return 1;
}

/**
 * Find out the type of a house. ie. Whether it's rented or owned.
 *
 * @param house The basename of the house
 * @return the type.
 */
int query_type(string house) {
  if(!houses)
    return -1;
  if(!houses[house])
    return -1;

  return ((class housing)houses[house])->type;
}

/**
 * Find out the current value of a house.
 *
 * @param house The basename of the house
 * @return the value.
 */
int query_value(string house) {
  if(!houses)
    return 0;
  if(!houses[house])
    return 0;

  return houses[house]->value;
}

/**
 * Function to get a list of houses that are vacant in a given region.
 * This function is used by the auction system or other sales mechanism.
 *
 * @param region Region to list houses in
 * @return a list of houses.
 */
string *query_vacant(string region) {
  string house, *sale_list;

  sale_list = ({ });
  foreach(house in keys(houses)) {
    if(stringp(houses[house]->owner)) {
      if (lower_case(houses[house]->owner) == "for sale" &&
          houses[house]->region == region) {
        sale_list += ({ house });
      }
    } else {
      debug_printf("Bad owner for house %O\n", house);
    }
  }

  return sale_list;
}

/**
 * Mark a house as being For Sale this puts it in the list of possible
 * houses to go into the vacant list.
 *
 * @param house the basename of the house
 * @return 1 for success 0 for failure
 */
int set_for_sale(string house) {
  if(!houses || !houses[house])
    return 0;

  log_file("HOUSING", "%s %s set to For Sale from %s\n",
           ctime(time())[4..15], house, houses[house]->owner);
  
  houses[house]->owner = "For Sale";
  houses[house]->bank = DEFAULT_BANK;
  save_file();
  return 1;
}

/**
 * Mark a house as being Under Offer (to prevent anyone else trying to sell
 * it too.
 *
 * @param house the basename of the house
 * @return 1 for success 0 for failure
 */
int set_under_offer(string house) {
  if(!houses || !houses[house])
    return 0;

  log_file("HOUSING", "%s %s set to Under Offer from %s\n",
           ctime(time())[4..15], house, houses[house]->owner);
  
  houses[house]->owner = "Under Offer";
  houses[house]->value = 0; // So the old rent isn't visible anymore.
  save_file();
  return 1;
}

/**
 * Mark a house as being in arrears.  This is the step just prior to being
 * repossessed.
 *
 * @param house the basename of the house
 * @return 1 for success 0 for failure
 */
int set_in_arrears(string house) {
  if(!houses || !houses[house])
    return 0;

  log_file("HOUSING", "%s %s set to In Arrears from %s\n",
           ctime(time())[4..15], house, houses[house]->owner);
  
  houses[house]->owner = houses[house]->owner + " (In Arrears)";
  save_file();
  return 1;
}

/**
 * Set the value of a particular house.
 *
 * @param house the basename of the house
 * @param value the value in monetary units.
 * @return 1 for success 0 for failure
 */
int set_value(string house, int value) {
  if(!houses || !houses[house])
    return 0;

  houses[house]->value = value;
  save_file();
  return 1;
}
/**
 * @ignore yes
 * This function is called by the refresh handler when a player refreshes
 * or deletes.
 */
int player_refreshed(mixed name, int refresh_type) {
  class housing house;
  string hname;
  
  if(objectp(name))
    name = name->query_name();

  foreach(hname, house in houses)
    if(house->owner == name) {
      log_file("HOUSING", "%s %s refreshed or deleted.\n", ctime(time())[4..15],
               house->owner);
      set_for_sale(hname);
    }
  
  return 1;
}

/**
 * This method sets a mapping between a housing area and the citizenship
 * required to hold a house there.
 * @param area the housing area to link
 * @param citizenship the citizenship the housing area needs
 */
void set_housing_area_citizenship(string area, string citizenship) {
   _housing_area[area] = citizenship;
   save_file();
}

/**
 * This method removes the mapping between a housing area and it's citizenship
 * requirements.
 * @param area the housing area to remove the link from
 */
void remove_housing_area_citizenship(string area) {
   map_delete(_housing_area, area);
   save_file();
}

/**
 * This method returns the current mappings between the housing area and the
 * required citizenship.
 * @param area the area to check
 * @return the citizenship required, 0 if none
 */
string query_housing_area_citizenship(string area) {
   return _housing_area[area];
}

/**
 * This method returns all of the current mappings between the housing
 * area and the citizenship.  This shouuld not be used for anything
 * except debugging.
 * @return all the housing area stuff
 */
mapping query_all_housing_area_citizenships() {
   return copy(_housing_area);
}

void set_housing_area_money( string area, string bank, string place ) {

    if( !_area_money[area] ) {
        _area_money[area] = ([ ]);
    }
    if( bank ) {
        _area_money[area]["bank"] = bank;
    }
    if( place ) {
        _area_money[area]["place"] = place;
    }
    save_file();
    
} /* set_housing_area_money() */

/**
 * This method returns the current mappings between the housing area and the
 * initial bank to use.
 * @param area the area to check
 * @return the initial bank used, DEFAULT_BANK if none set
 */
string query_housing_area_bank(string area) {
    if( _area_money[area] && _area_money[area]["bank"] ) {
        return _area_money[area]["bank"];
    }
    else {
        return DEFAULT_BANK;
    }
} /* query_housing_area_bank() */

/**
 * This method returns the current mappings between the housing area and the
 * money area ("Ankh-Morpork", "Counterweight Continent", etc) to use.
 * @param area the area to check
 * @return the money area used, DEFAULT_PLACE if none set
 */
string query_housing_area_place(string area) {
    if( _area_money[area] && _area_money[area]["place"] ) {
        return _area_money[area]["place"];
    }
    else {
        return DEFAULT_PLACE;
    }
} /* query_housing_area_place() */



/** @ignore yes
 * This function goes through the houses and checks that the owners
 * are still active.
 */
void check_owners(int i) {
  class housing tmp;
  
  if(!_tmp_houses)
    _tmp_houses = keys(houses);

  if(i == sizeof(_tmp_houses))
    return;

  tmp = houses[_tmp_houses[i]];

  if(!tmp->owner ||
     lower_case(tmp->owner) == "for sale" ||
     lower_case(tmp->owner) == "under offer" ||
     strsrch(lower_case(tmp->owner), "(in arrears)") != -1) {
    call_out("check_owners", 1, ++i);
    return;
  }
 
  if(!PLAYER_HANDLER->test_user(lower_case(tmp->owner))) {
    log_file("HOUSING", "%s %s doesn't exist.\n", ctime(time())[4..15],
             tmp->owner);
    set_for_sale(_tmp_houses[i]);
  } else if(!PLAYER_HANDLER->test_creator(tmp->owner)) {
    switch(tmp->type) {
    case SALE:
      if(PLAYER_HANDLER->test_last(tmp->owner) < time() - OWNER_TIMEOUT) {
        log_file("HOUSING", "%s %s is idle last login %s ago [%s].\n",
                 ctime(time())[4..15], tmp->owner,
                 ctime_elapsed(time() - PLAYER_HANDLER->test_last(tmp->owner)),
                 _tmp_houses[i]);
        set_for_sale(_tmp_houses[i]);
      }
      break;
    case RENT:
      if(PLAYER_HANDLER->test_last(tmp->owner) < time() - RENTER_TIMEOUT) {
        log_file("HOUSING", "%s %s is idle last login %s [%s].\n",
                 ctime(time())[4..15], tmp->owner,
                 ctime_elapsed(time() - PLAYER_HANDLER->test_last(tmp->owner)),
                 _tmp_houses[i]);
        set_for_sale(_tmp_houses[i]);
      }
      if (_housing_area[tmp->region] &&
          !NOMIC_HANDLER->is_citizen_of(_housing_area[tmp->region],
                                        tmp->owner)) {
        log_file("HOUSING", "Property %s has an owner %s, who is not "
                 "a citizen of %s [rent %d].\n", _tmp_rentals[i],
                 tmp->owner, _housing_area[tmp->region], tmp->value);
        MAIL_HANDLER->do_mail_message(tmp->owner,
                                      "Housing Rental Office",
                                      "Reposession", "",
                                      "Due to not being a citizen of " +
                                      _housing_area[tmp->region] +
                                      " when your rent was due, your property "
                                      "at " +tmp->address + " has been "
                                      "reposessed and put up for sale.\n\n"
                                      "The rental office.\n");
        set_for_sale(_tmp_rentals[i]);
      }
      break;
    }
  }
  call_out("check_owners", 1, ++i);
}

/** @ignore yes
 *
 * Charge people rent if appropriate.
 */
void check_rent() {
  int *now, daysleft;

  now = AM_TIME_HANDLER->query_am_time_array(time());

  // Check we haven't charged rent this month and charge it.
  if(now[AM_TIME_MONTH] != last_paid) {
    log_file("HOUSING", "Processing rent for " +
             AM_TIME_HANDLER->query_month(now[AM_TIME_MONTH]) + "\n");
    call_out("charge_rent", 0);
    last_paid = now[AM_TIME_MONTH];
    save_file();
  }

  daysleft = AM_TIME_HANDLER->query_days_per_month()[now[AM_TIME_MONTH]-1] -
    now[AM_TIME_DAY_OF_MONTH];
  call_out("check_rent", (daysleft * AM_SECONDS_PER_DAY) + 1);
}


/** @ignore yes
 *
 * This function goes through the houses and checks that the owners
 * are still active.
 */
void charge_rent(int i) {
  class housing tmp;
  string owner;
  
  if(!_tmp_rentals)
    _tmp_rentals = keys(houses);
  
  if(i >= sizeof(_tmp_rentals))
    return;
  
  tmp = houses[_tmp_rentals[i]];
  // Find the next rental house in the list that has an owner
  while(i < sizeof(_tmp_rentals) &&
        (tmp->type != RENT || !tmp->owner ||
         lower_case(tmp->owner) == "for sale" ||
         lower_case(tmp->owner) == "under offer")) {
    
    if(++i < sizeof(_tmp_rentals))
      tmp = houses[_tmp_rentals[i]];
  }
  
  if(i >= sizeof(_tmp_rentals)) {
    return;
  }

  call_out("charge_rent", 1, (i+1));

  // Sanity check in case they have no bank
  if(!tmp->bank) {
    set_bank( _tmp_rentals[i], query_housing_area_bank( tmp->region ) );
    log_file("HOUSING", "Property %s had no bank, setting it to %s.\n", 
             _tmp_rentals[i], tmp->bank);  
  }
  
  if(!tmp->value) {
    log_file("HOUSING", "Property %s has a rent of zero.\n",
             _tmp_rentals[i]);
  } else if(strsrch(tmp->owner, "(In Arrears)") != -1) {
    // This owner is in arrears on their payments.
    owner = replace(tmp->owner, " (In Arrears)", "");
    if(BANK->query_account(owner, tmp->bank) < tmp->value * 3) {
      // They don't have the requisite 3 months rent so the property
      // is repossessed.
      log_file("HOUSING", "%s %s failed to pay %d (%d) for %s [%s] "
               "property repossessed.\n",
               ctime(time())[4..15], owner, tmp->value * 3, 
               BANK->query_account(owner, tmp->bank), _tmp_rentals[i],
               tmp->bank);
      MAIL_HANDLER->do_mail_message(owner,
                                    "Housing Rental Office",
                                    "Reposession", "",
                                    "Due to insufficient funds in your "
                                    "account at " + tmp->bank + " bank your "
                                    "property\n"
                                    "at " +tmp->address + " has been "
                                    "reposessed.\n\n"
                                    "The rental office.\n");
      // Take what we can to cover outstanding rent.
      BANK->adjust_account(owner, tmp->bank,
                           -(BANK->query_account(owner, tmp->bank)));
      set_for_sale(_tmp_rentals[i]);
    } else {
      // Have them pay last months rent, a months late fee and this 
      // month's rent and then return the house to normal ownership.
      BANK->adjust_account(owner, tmp->bank, - (tmp->value * 3));
      log_file("HOUSING", "%s %s paid arrears of %d for %s [%s]\n",
               ctime(time())[4..15], tmp->owner, tmp->value * 3, 
               BANK->query_account(owner, tmp->bank), _tmp_rentals[i],
               tmp->bank);
      set_owner(_tmp_rentals[i], owner);
    }
  } else if(BANK->query_account(tmp->owner, tmp->bank) < tmp->value) {
    log_file("HOUSING", "%s %s failed to pay %d (%d) for %s [%s] "
             "property set in arrears.\n", ctime(time())[4..15], tmp->owner,
             tmp->value, BANK->query_account(tmp->owner, tmp->bank),
             _tmp_rentals[i], tmp->bank);
    MAIL_HANDLER->do_mail_message(tmp->owner,
                                  "Housing Rental Office",
                                  "In Arrears", "",
                                  "Due to insufficient funds in your account "
                                  "at " + tmp->bank + " bank your property\n"
                                  "at " +tmp->address + " is now in arrears."
                                  "\n\n"
                                  "Next month you will be charged three times "
                                  "the normal rent (this months rent, a one "
                                  "month late fee and next months rent).\n\n"
                                  "Failure to pay will result in repossession "
                                  "of your property.\n\n"
                                  "The rental office.\n");
    set_in_arrears(_tmp_rentals[i]);
  } else {
    BANK->adjust_account(tmp->owner, tmp->bank, -tmp->value);
    log_file("HOUSING", "%s %d rental paid by %s for %s\n",
             ctime(time())[4..15], tmp->value, tmp->owner, _tmp_rentals[i]);
  }
  
  if(tmp->owner != "For Sale" &&
     BANK->query_account(tmp->owner, tmp->bank) < (tmp->value * 3)) {
    
    MAIL_HANDLER->do_mail_message(tmp->owner,
                                  "Housing Rental Office",
                                  "Shortage of funds", "",
                                  "Your bank account currently has funds for "
                                  "less than three months rent.\n\n"
                                  "The rental office.\n");
  }
  
  debug_printf("Doing callout %d.", (i+1));
}

/** @ignore yes
 * Get a list of all the houses that exist. This is just a debug function.
 * @return a mapping of all the houses.
 */
mapping query_houses() {
  return copy(houses);
}

/** @ignore yes */
mixed stats() {
  return ({
    ({ "total houses", sizeof(keys(houses)) }),
      ({ "paid for" , AM_TIME_HANDLER->query_month(last_paid) }),
      });
}