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/
/**
 *  Creator Project Management System Web Interface
 *  @author Drakkos (god forgive me)
 *  @started 26/08/2001
 *
 */
 
 
#include <http.h>
#include <player_handler.h>
#include <project_management.h>
#include <permissions.h>

string get_project_menu();
varargs string get_add_project(mapping);
string get_web_page (string, string);
string www_project_info (class project);
varargs string get_modify_project (string, string, string);
varargs string get_add_note (mapping, string);
string get_add_task (mapping, string);
string do_add_file (mapping, string); 
string get_modify_task (string, string);
string get_add_file (mapping, string);
string get_modify_note (string, string);
string get_modify_file (string, string, int);
string get_notes_list (string*);
string get_notes_summary (string);
string get_tasks_summary (string);
string get_view_project (string, int);
string get_view_page (string, string, string);
string get_view_note (string, string);
string get_files_summary (string);



string get_id(string str) {
  return implode (map (explode (str, " "), (: capitalize ($1) :)),
    "");   
}

varargs string *explode_to_array (string str, int cap) {
  string *arr;
  arr = explode (replace (str, ({" ", ""})), ",");

  if (!cap) {
    arr = map (arr, (: lower_case ($1) :));
  }
  
  return arr;
}  
  
string* normalise_guilds (string str) {
  string *valid_guilds = ({"wizards", "witches", "priests", "warriors",
    "thieves", "assassins"});  
  string *good = ({ });
  string *start;
  
  start = explode_to_array (str);
  
  foreach (string s in start) {
    if (member_array (s, valid_guilds) == -1) {
      s = s + "s";
    }
    if (member_array (s, valid_guilds) != -1 && 
        member_array (s, good) == -1) {
      good += ({ s });
    }
  }
      
  return good;
}


/**
 *  Take the type of timescale and the number, and multiply them together
 *  to give a time value estimate.
 *  @param number the number of units
 *  @param value the type of units
 *  @returns the number of seconds until the estimated completion date.
 */
 
int get_time_value (string number, string value) {
  int est, time;
  
  est = to_int (number);
  
  switch (value) {
    case "day":
      time = DAY;
    break;
    case "week":
      time = DAY * 7;
    break;
    case "month":
      time = DAY * 30;
    break;
    case "year":
      time = DAY * 365;
    break;
  }
  
  est *= time;

  return est;
}

string* get_twiki_links (class project p) {
  string *ret = ({ });
  string *details;
  string domain, page;
  if (!sizeof (p->twiki)) {
    return ret;
  }
  
  foreach (string t in p->twiki) {
    details = explode (t, ".");
  
    if (sizeof (details) == 2) {
      domain = details[0];
      page = details[1];
    }
    else {
      domain = p->domains[0];
      page = t;
    }

    ret += ({ "<a href=" + TWIKI_BASE + capitalize (domain) + "/" + page + ">"
     + page + "</a>"});
    
  }
  
  return ret;    
}

string* get_domain_links (class project p) {
  string *ret = ({ });
  if (!sizeof (p->domains)) {
    return ret;
  }
  
  foreach (string d in p->domains) {
    ret += ({ "<a href=project.c?misc=Domlist&domain=" + d + ">"
      + capitalize (d) + "</a>" });
  }
  
  if (!sizeof (ret)) {
    ret = ({"Error!"});
  }
  
  
  return ret;    
}

string *get_creator_links (mixed cre) {
  string *creators;
  string *ret = ({ });
  
  if (arrayp (cre)) {
    creators = cre;
  }
  else {
    creators = ({ cre });
  }
  
  creators = sort_array (creators, 1);
  
  foreach (string c in creators) {
    ret += ({ "<a href=project.c?misc=Crelist&creator=" + c + ">"
        + capitalize (c) + "</a>" });
  }
      
  return ret;
  
}


string parse_details (class project *tmp) {
  string ret = "";

  if (!sizeof (tmp)) {
    return "There are no projects in this category.<P>";
  }

  
  ret += "<ol>";
  
  foreach (class project t in tmp) {
    ret += "<li>";
    ret += "<TABLE width=100%>";
    ret += "<TD width=80%>";      
    ret += sprintf ("<B>%s:</b>  %s (%s).<br>%s<br>",
      query_multiple_short (map (t->domains, (: capitalize ($1) :))), t->id, 
      t->name, (sizeof (t->creators) ? 
      "Assigned creators: " + query_multiple_short (get_creator_links 
      (t->creators)) + "." : "<b>Unassigned</b>"));
    if (t->last_touched) {
      ret += "  Last touched: " + ctime (t->last_touched) + " by " + 
      (t->touched_by ? query_multiple_short (get_creator_links 
      (t->touched_by)) : "Nobody");
    }
    else {
      ret += "  This project has not been touched since creation.";
    }
    
    ret += "<TD>";      
               
    ret += "<b>[ </b><a href=project.c?projecttype=Details&pid=" 
      + t->id + ">Details</a> <b>|</b> "
      "<a href=project.c?pid=" + 
      t->id + "&projecttype=Edit>Edit</a> <b>]</b>" 
      "<TR>";
    ret += "</TABLE>";

  }
  
  ret += "</ol>";
    
  return ret;
}

string get_project_list() {
  class project *tmp = PROJECT_HANDLER->data_dump();
  
  return parse_details (tmp);;
  
}


string get_domain_project_list(string domain) {
  class project *tmp = PROJECT_HANDLER->filter_by_query((["domains" : 
    domain]));
  
  return parse_details (tmp);;
  
}

string get_creator_project_list(string creator) {
  class project *tmp = PROJECT_HANDLER->filter_by_query((["creators" : 
    creator]));
  
  return parse_details (tmp);;
  
}

/**
 *  Get the HTML code for the estimated completion data drop down menus.
 *  @returns the HTML code.
 */
 
varargs string get_estimate(int ignore) {
  string ret = "<SELECT NAME=\"number\">";
  
  for (int i = 0; i < 13; i++) {
    ret += "<OPTION VALUE + \"" + i + "\">" + i;
  }
  
  ret += "</SELECT>";    
  
  ret += "<SELECT NAME=\"time\">";
    
  foreach (string stat in ({"day", "week", "month", "year"}))  {   
    ret += "<OPTION value = \"" + stat+ "\">" + stat;
  }  
  
  ret += "</SELECT>";
  
  if (!ignore) {
    ret += "<INPUT type = \"checkbox\" name = \"newest\"> Update?";
  }
  
  return ret;
}

string get_tasks_summary (string id) {
  class task *tmp = PROJECT_HANDLER->project_task_data(id);
  string ret = "";
  

  ret += "<HR>"
    "<B>Tasks: </B>" 
    "<b>[</b> <a href=project.c?pid=" + id + "&tasktype=Add>"
    "Add New Task</a> <b>]</b><p>";
  
  if (sizeof (tmp)) {
    ret += "<ol>";
      
    foreach (class task t in tmp) {
      ret += "<li><TABLE width=100%>";
      ret += "<TD width=70%>";      
      ret += sprintf ("<b>%s (%s) [%d%%] </b><br>%s<br>Added by %s on %s",
        t->id, t->task_name, to_int (t->percent_complete), (sizeof (t->assigned_to) ? 
          "Assigned creators: " + query_multiple_short (
          get_creator_links (t->assigned_to)) :
          "<b>Unassigned</b>"), query_multiple_short (get_creator_links 
            (t->added_by)), 
          ctime (t->date_added));
      ret += "<TD>";
      ret += "<b>[</b> <a href=project.c?tid=" + t->id + 
        "&tasktype=Details&pid=" 
        + id + ">Details</a> | "
        "<a href=project.c?tid=" + t->id + "&tasktype=Edit&pid=" + id +">"
      "Edit</a> <b>]</b>";
      ret += "<TR>";
      ret += "</TABLE>";
  
    }
    
    ret += "</ol>";
  }
    
  return ret;
}  


varargs string get_view_task (string id, string task) {
  string ret = "";
  class task tmp;

  ret += get_view_project (id, 0);
  
  
  tmp  = PROJECT_HANDLER->get_task_file (id, task);
    
  if (!tmp) {
    return "";    
  }
  
  ret += "<HR>"
      "<B>Task " + task+ ":  </B><a href=project.c?tid=" 
      + tmp->id + "&tasktype=Edit&pid=" 
      + id + ">Edit Task</a><P> "
    "<form action=\"project.c\" METHOD=POST "
    "action=\"project.c?\">"
    "<TABLE width=100%>"
    "<TR>"
    "<TH width=30% align = \"left\"> Task ID: </TH>" 
    "<TD>" + tmp->id + "<TD>"  
    "<TR>"
    "<TH align = \"left\"> Task Name: </TH>" 
    "<TD>" + tmp->task_name + "<TD>"  
    "<TR>"
    "<TH align = \"left\"> Added by: </TH>" 
    "<TD>" + query_multiple_short (get_creator_links(tmp->added_by)) + " at " 
      + ctime (tmp->date_added) 
      + "<TD>"  
    "<TR>"
    "<TH align = \"left\"> Comments: </TH>" 
    "<TD>" + (tmp->comments? tmp->comments : "") + "<TD>"  
    "<TR>"
    "<TH align = \"left\"> Project creators (separated by comma): "
    "</TH>" 
    "<TD>";
    if (sizeof (tmp->assigned_to)) {      
      ret += query_multiple_short (get_creator_links 
        (tmp->assigned_to));  
    }
  ret += "<TD><TR>"
    "<TH align = \"left\"> Percent Complete: </TH>" 
    "<TD>" + tmp->percent_complete+ "<TD>"  
    "<TR>"
    "<TH align = \"left\"> Task Aims: </TH>" 
    "<TD>" + tmp->aims + "<TD>";
    if (tmp->completion_date) {
    ret += "<TR><TH align = \"left\"> Estimated completion: </TH>" 
    "<TD>" + ctime (tmp->completion_date) + "<TD>"  
    "<TR>";
  }    
    
  ret += "</TABLE>";

  return ret;
}

varargs string get_view_file (string id, string file, string task) {
  string ret = "";
  class file tmp;
  
  ret += get_files_summary (id);
  
  tmp  = PROJECT_HANDLER->get_file (id, file, task);
    
  if (!tmp) {
    return "";    
  }
  
  ret += "<HR>"
      "<B>Access for " + file + ":  </B><a href=project.c?filetype=Delete&pid=" 
      + id + "&fid="+file + "&task=" + task + ">Delete this File</a><P> "
    "<form action=\"project.c\" METHOD=POST "
    "action=\"project.c?\">"
    "<TABLE width=100%>"
    "<TR>"
    "<TH width=30% align = \"left\"> Filename: </TH>" 
    "<TD>" + tmp->file + "<TD>"  
    "<TR>"
    "<TH align = \"left\"> File Access: </TH>" 
    "</SELECT>"    
    "<SELECT NAME=\"access\">";
    
    foreach (string stat in ({"read", "read+write", "read+write+grant"}))  {   
      ret += "<OPTION value = \"" + stat+ "\">" + stat;
    }  
  
    ret += "</SELECT>"    
    "<TD>"  
    "<TR>"
    "<TH align = \"left\"> Leader Only: </TH>" 
    "<SELECT NAME=\"leader\">";
    
    foreach (string stat in ({"yes", "no"}))  {   
      ret += "<OPTION value = \"" + stat+ "\">" + stat;
    }  
    ret += "</SELECT>"  
    "</TABLE>";

  return ret;
}

string get_files_summary (string id) {
  class file *tmp = PROJECT_HANDLER->query_files(id);
  string ret = "";
  string acc_str, cohort;
  
  ret += "<HR>"
    "<B>Files: </B>" 
    "<b>[</b><a href=project.c?pid=" + id + "&filetype=Add>"
    "Add New File Permission</a><b>]</b><P>";
             
  if (sizeof (tmp)) {             
    ret += "<ol>";        
     foreach (class file t in tmp) {
        switch (t->access) {
          case 4:
            acc_str = "read+write+grant";
          break;
          case 2:
            acc_str = "read+write";
          break;
          case 1:
            acc_str = "read";
          break;
        }
        
      if (t->task == "leader") {
        cohort = " the project leader";
      }
      else if (sizeof (t->task)) {
        cohort = " members assigned to task " + t->task;
      }
      else {
        cohort = " project members";
      }
      

      ret += "<li><TABLE width=100%>";
      ret += "<TD width=70%>";      
      ret += sprintf ("<b>%s</b>:  %s access for %s.",
        t->file, acc_str, cohort);
      ret += "<TD>";
      ret += "<b>[ </b>"
        "<a href=project.c?fid=" + t->file + "&filetype=Delete&pid=" + id 
        +"&task=" + t->task + ">"
      "Delete</a> <b>]</b>";
  
      ret += "<TR>";
      ret += "</TABLE>";
    }
    
    ret += "</ol>";

  }
  
  return ret;
}  

string get_notes_summary (string id) {
  class note *tmp = PROJECT_HANDLER->project_note_data(id);
  string ret = "";
  

  ret += "<HR>"
    "<B>Notes: </B>" 
    "<b>[</b><a href=project.c?pid=" + id + "&notetype=Add>"
    "Add New Note</a><b>]</b><P>";
             
  if (sizeof (tmp)) {             
    ret += "<ol>";
    
    foreach (class note t in tmp) {
      ret += "<li><TABLE width=100%>";
      ret += "<TD width=70%>";      
      ret += sprintf ("<b>%s</b><br>  Added by %s %s.",
        t->id, query_multiple_short (get_creator_links (t->added_by)), 
          ctime (t->date_added));
      ret += "<TD>";
      ret += "<b>[</b><a href=project.c?nid=" + t->id + 
        "&notetype=Details&pid=" 
        + id + ">Details</a> | "
        "<a href=project.c?nid=" + t->id + "&notetype=Edit&pid=" + id +">"
      "Edit</a> <b>]</b>";
  
      ret += "<TR>";
      ret += "</TABLE>";
    }
    
    ret += "</ol>";

  }
  
  return ret;
}  
/**
 *  Deal with updaing a project's task and returning the appropriate 
 *  web page.  It will check for consistency of data and the neccessary
 *  updating of the project management PROJECT_HANDLER.  It will only do this 
 *  if the user has valid access to perform the operation.
 *  @param data the task data
 *  @param name the name of the user.
 *  @returns the HTML code for the page
 */
  
protected string do_update_task(mapping data, string name) {
  string *required = ({"taskname"});
  string *creators;  
  class task tmp;
  int valid;
  
  foreach (string r in required) {
    if (undefinedp (data[r])) {
      return get_web_page (get_modify_task(data["projid"], 
      data["tid"]), "The " + r + " field is required.");
    }
  }
  
  data["projid"] = get_id (data["projid"]);
  data ["tid"] = get_id (data["tid"]);
  
  if (PROJECT_HANDLER->valid_operation (name, TASK, data["projid"])) {
      valid = 1;
  }
  
  if (!valid) {
    return get_web_page (get_modify_project(data["projid"]), 
        "You do not have access to perform this operation.");
  }    
   
  tmp = PROJECT_HANDLER->get_task_file (data["projid"], data["tid"]);   
  
  if (!tmp) {
      return get_web_page (get_modify_task(data["projid"], 
        data["tid"]), "Oh no, error!");
  }
  
  if (sizeof (data["assigned"])) {
    creators = filter (explode_to_array (data["assigned"]), 
      (: PLAYER_HANDLER->test_creator ($1) :));
  }
  if (tmp->task_name != data ["taskname"]) {
    tmp->task_name = data["taskname"];
  }
  if (tmp->comments != data ["comments"]) {
    tmp->comments = data["comments"];
  }

  if (tmp->percent_complete != data ["completed"]) {
    tmp->percent_complete = to_int (data["completed"]);
  }
    
  if (tmp->assigned_to != creators) {
    if (sizeof (creators)) {
      tmp->assigned_to = map (creators, (: lower_case ($1) :));
    }
    else {
      tmp->assigned_to = ({ });
    }
    
  }
  
  if (tmp->aims != data["aims"]) {
    tmp->aims = data ["aims"];
  }
  
  if (data ["newest"] == "on") {
    tmp->completion_date = time() + get_time_value (data["number"], 
      data["time"]);
  }
    
  PROJECT_HANDLER->set_task_file (data["projid"], data ["tid"], tmp, name);  
  
  return get_view_page (get_view_task (data["projid"], data["tid"]), 
    data["projid"], "Task modifed");      
}    

/**
 *  Deal with updating a project's note and returning the appropriate 
 *  web page.  It will check for consistency of data and the neccessary
 *  updating of the project management PROJECT_HANDLER.  It will only do this 
 *  if the user has valid access to perform the operation.
 *  @param data the note data
 *  @param name the name of the user.
 *  @returns the HTML code for the page
 */
 
protected string do_update_note(mapping data, string name) {
  string *required = ({"nid"}); 
  class note tmp;
  int valid;
  
  foreach (string r in required) {
    if (undefinedp (data[r])) {
      return get_web_page (get_modify_task(data["projid"], 
      data["nid"]), 
      "The " + r + " field is required.");
    }
  }

  data ["projid"] = get_id (data ["projid"]);
  data ["nid"] = get_id (data["nid"]);


  tmp = PROJECT_HANDLER->get_note_file (data["projid"], data["nid"]);   
  
  if (!tmp) {
      return get_web_page (get_modify_task(data["projid"], 
        data["nid"]), "Oh no, error!");
  }
  
  if (PROJECT_HANDLER->valid_operation (name, NOTE, data["projid"], 
      PROJECT_HANDLER->query_project_domains(data["projid"]))) {
      valid = 1;
  }
  
  if (!valid) {
    return get_web_page (get_modify_project(data["projid"]), 
        "You do not have access to perform this operation.");
  }    

  if (tmp->note != data ["note"]) {
    tmp->note = data["note"];
  }

    
  PROJECT_HANDLER->set_note_file (data["projid"], data ["nid"], tmp, name);    
      
  return get_view_page (get_view_note(data["projid"], data["nid"]), 
    data["projid"], "Note modifed");      
} 

/*
protected string do_update_file(mapping data, string name) {
  string *required = ({"file", "access", "lead"}); 
  class file tmp;
  int valid;
  
  foreach (string r in required) {
    if (undefinedp (data[r])) {
      return get_web_page (get_modify_file(data["projid"], 
      data["fid"], to_int (data["lead"])), 
      "The " + r + " field is required.");
    }
  }

  data ["projid"] = get_id (data ["projid"]);

  tmp = PROJECT_HANDLER->get_file (data["projid"], data["fid"], 
  to_int (data["lead"]));   
  
  if (!tmp) {
      return get_web_page (get_modify_file(data["projid"], 
        data["fid"], to_int (data["lead"])), "Oh no, error!");
  }
  
  if (PROJECT_HANDLER->valid_operation (name, FILE, data["projid"], 
      PROJECT_HANDLER->query_project_domains(data["projid"]))) {
      valid = 1;
  }
  
  if (!valid) {
    return get_web_page (get_modify_project(data["projid"]), 
        "You do not have access to perform this operation.");
  }    

  if (tmp->file != data ["file"]) {
    tmp->file = data["file"];
  }

  if (tmp->access != data ["access"]) {
    tmp->access = data["access"];
  }

  if (tmp->leader_only != data ["lead"]) {
    tmp->leader_only = data["lead"];
  }

    
  PROJECT_HANDLER->set_file (data["projid"], data ["fid"], data["access"],
  data ["leader"]);    
      
  return get_view_page (get_view_note(data["projid"], data["nid"]), 
    data["projid"], "Note modifed");      
} 
*/

/**
 *  Deal with updaing a project and returning the appropriate 
 *  web page.  It will check for consistency of data and the neccessary
 *  updating of the project management PROJECT_HANDLER.  It will only do this is
 *  the user has valid access to perform the operation.
 *  @param data the project data
 *  @param name the name of the user.
 *  @returns the HTML code for the page
 */
 
protected string do_update_project (mapping data, string name) {
  string *required = ({"projid", "name", "domains"});
  string *domains, *creators, *twiki, *sub, *pts;  
  class project tmp;
  int tmp_val, valid;
  
  foreach (string r in required) {
    if (undefinedp (data[r])) {
      return get_web_page (get_modify_project(data["projid"]), 
        "The " + r + " field is required.");
    }
  }

  data ["projid"] = get_id (data["projid"]);

  domains = filter (explode_to_array (data["domains"]), 
    (: find_object ("/d/" + $1 + "/master") :));
   
  if (PROJECT_HANDLER->valid_operation (name, PROJECT, data["projid"], 
      domains)) {
      valid = 1;
  }
  
  pts = explode_to_array (data["playtesters"]);

  tmp = PROJECT_HANDLER->get_project_file (data["projid"]);   

  if (sizeof (pts & tmp->playtesters) != sizeof (tmp->playtesters)) {
    if (PROJECT_HANDLER->valid_operation (name, PROJECT, data["projid"], 
      domains)) {
      valid = 1;
    }
  }
  
     
  if (!valid) {
    return get_web_page (get_modify_project(data["projid"]), 
        "You do not have access to perform this operation.");
  }  
  
  
  if (PROJECT_HANDLER->find_project (data["projid"]) == -1) {
      return get_web_page (get_modify_project(data["projid"]), 
        "The project " + data["projid"] + " does not exist.");
  }
   
  if (!sizeof (domains)) {
      return get_web_page (get_modify_project(data["projid"]), 
        "At least one valid domain required.");
  }

  creators = filter (explode_to_array (data["creators"]), 
    (: PLAYER_HANDLER->test_creator ($1) :));
     
  if (sizeof (data["twiki"])) {
    twiki = explode (replace (data["twiki"], ({" ", ""})), ",");
  }
  

  if (sizeof (data["sub"])) {
    sub = explode (replace (data["sub"], ({" ", ""})), ",");
  }      
  
  if (data["size"]) {
    tmp->size = member_array (data["size"], SIZE);    
  }
  if (data["complexity"]) {
    tmp->complexity = member_array (data["complexity"], COMPLEXITY);    
  }
  if (sizeof (data["guilds"])) {
    tmp->guild_specific = normalise_guilds (data["guilds"]);
      
  }
      
  if (tmp->name != data ["name"]) {
    tmp->name = data["name"];
  }
  if (tmp->pt_notes != data ["ptnotes"]) {
    tmp->pt_notes = data["ptnotes"];
  }
  if (tmp->leader != data ["leader"]) {
    tmp->leader = data["leader"];
  }
  
  if (tmp->description != data ["description"]) {
    tmp->description = data ["description"];
  }  

  if (tmp->percent_complete != data ["completed"]) {
    tmp->percent_complete = to_int (data ["completed"]);
  }  
  
  if (tmp->domains!= domains) {
    tmp->domains = domains;
  }
  
  if (tmp->creators != creators) {
    tmp->creators = map (creators, (: lower_case ($1) :));
  }

//  if (tmp->files != files) {
//    tmp->files = files;
//  }

  if (tmp->twiki != twiki) {
    tmp->twiki = twiki;
  }

  if (tmp->sub_projects != sub) {
    tmp->sub_projects = sub;
  }

  if (data["newest"] == "on") {
    tmp_val = get_time_value (data["number"], data["time"]);
    if (tmp_val > 0) {
      tmp->estimated_completion = (time() + tmp_val);
    }
    else {
      tmp->estimated_completion = 0;
    }    
  }

  if (STATUS[tmp->status] != data["status"] && 
    member_array (data["status"], STATUS) != -1 ) {
    tmp->status = member_array (data["status"], STATUS);
    PROJECT_HANDLER->catch_status_change (tmp->id, tmp->status);
  }

  PROJECT_HANDLER->assign_playtesters (data["projid"], pts, name);   
            
  PROJECT_HANDLER->set_project_file (data["projid"], tmp, name);    
      
  return get_view_page (get_view_project (data["projid"], 1), 
    data["projid"], "Project modifed");      
}  

/**
 *  Do a query on the data and return the results in a list. 
 *  @param query the query data
 *  @returns the HTML code for the page
 */
 
string web_query (mapping query) {
  class project *tmp;
  string ret = "";
  

  query ["touched"] = get_time_value (query["number"], query["time"]);
  
  tmp = PROJECT_HANDLER->filter_by_query (query);
  
  ret += "<B>" + capitalize (query_num (sizeof(tmp))) + 
  (sizeof (tmp) == 1 ? " project matches " : " projects match ") 
    + "this query: </B><P>";
  ret += parse_details (tmp);
  
  return ret;
}

protected string do_add_project (mapping data, string name) {
  string *required = ({"projid", "name", "domains"});
  string *domains, *creators, *twiki;  
  int valid = 0, size, complexity;

  foreach (string r in required) {
    if (undefinedp (data[r])) {
      return get_web_page (get_add_project(data), 
        "The " + r + " field is required.");
    }
  }
  
  data ["projid"] = get_id (data["projid"]);
  
  if (PROJECT_HANDLER->find_project (data["projid"]) != -1) {
      return get_web_page (get_add_project(data), 
        "The project " + data["projid"] + " already exists.");
  }
    
  domains = filter (explode_to_array (data["domains"]), 
    (: find_object ("/d/" + $1 + "/master") :));
   
  if (!sizeof (domains)) {
      return get_web_page (get_add_project(data), 
        "At least one valid domain required.");
  }
  
  if (PROJECT_HANDLER->valid_operation (name, PROJECT, data["projid"], 
      domains)) {
      valid = 1;
  }
  
  if (!valid) {
    return get_view_page (get_project_list (), 
      data["projid"], "You do not have access to perform this "
      "operation.");
  }

    
  creators = filter (explode_to_array (data["creators"]), 
    (: PLAYER_HANDLER->test_creator ($1) :));
     
  if (sizeof (data["twiki"])) {
    twiki = explode (replace (data["twiki"], ({" ", ""})), ",");
  }
  
  if (data["size"]) {
    size = member_array (data["size"], SIZE);
  }
  if (data["complexity"]) {
    complexity = member_array (data["complexity"], COMPLEXITY);
  }
  
  
  
//  if (sizeof (data["files"])) {
//    files = explode (replace (data["files"], ({" ", ""})), ",");
//  }
      
  
  PROJECT_HANDLER->add_project (data["projid"], data["name"], data["leader"],
    data["description"], domains, creators, name, size, complexity, 
    normalise_guilds (data["guilds"]));

  if (data["newest"] == "on") {
    PROJECT_HANDLER->set_completion_date(data["projid"], time() + 
      get_time_value (data["number"], data["time"]));
  }
    
          
  return get_view_page (get_view_project (data["projid"], 1), data["projid"], 
    "Project added.");      
}  

protected string do_add_note (mapping data, string name) {
  string *required = ({"nid", "note"});
  int valid;
  
  foreach (string r in required) {
    if (undefinedp (data[r])) {
      return get_web_page (get_add_note(data, data["projid"]), 
        "The " + r + " field is required.");
    }
  }
  
  data ["nid"] = get_id (data["nid"]);
  
  if (PROJECT_HANDLER->valid_operation (name, NOTE, data["projid"], 
      PROJECT_HANDLER->query_project_domains(data["projid"]))) {
      valid = 1;
  }
  
  if (!valid) {
    return get_web_page (get_modify_project (data["projid"]), 
        "You do not have access to perform this operation.");
  }

  if (PROJECT_HANDLER->find_project (data["projid"]) == -1) {
      return get_web_page (get_add_note(data, data["projid"]), 
        "The project " + data["projid"] + " does not exist.");
  }

  if (PROJECT_HANDLER->find_note (data["projid"], data["nid"]) != -1) {
      return get_web_page (get_add_note(data, data["projid"]), 
        "The task " + data["nid"] + " already exists.");
  }

  PROJECT_HANDLER->add_note_to_project (data["projid"], data["nid"], 
    data["note"], name);
                  
  return get_view_page (get_view_project (data["projid"], 1), data["projid"], 
    "Note Added.");      
}

protected string do_add_file (mapping data, string name) {
  string *required = ({"fid", "access", "task"});
  int valid, access, k;
  string task;
  object ob;
  
  foreach (string r in required) {
    if (undefinedp (data[r])) {
      return get_web_page (get_add_file(data, data["projid"]), 
        "The " + r + " field is required.");
    }
  }
  
  
  if (PROJECT_HANDLER->valid_operation (name, FILE, data["projid"], 
      PROJECT_HANDLER->query_project_domains(data["projid"]))) {
      valid = 1;
  }
  
  if (!valid) {
    return get_web_page (get_modify_project (data["projid"]), 
        "You do not have access to perform this operation.");
  }

  if (PROJECT_HANDLER->find_project (data["projid"]) == -1) {
      return get_web_page (get_add_note(data, data["projid"]), 
        "The project " + data["projid"] + " does not exist.");
  }
  
  if (data["task"] == "Leader only") {
    task = "leader";
  }
  else if (data["task"] == "All project members") {
    task = "";
  }
  else {
    task = data["task"];
  }
  
  if (sizeof (PROJECT_HANDLER->find_file (data["projid"], data["fid"], task))) {
      return get_web_page (get_add_file(data, data["projid"]), 
        "Permissions for this file and task  already exist.  Please "
        "remove if you wish to change the access rights.");
  }

  switch (data["access"]) {
    case "grant":
      access = GRANT_MASK;
    break;
    case "write":
      access = WRITE_MASK;
    break;
    default:
      access = READ_MASK;
    break;
  }

  ob = find_player (name);
    
  if (access == GRANT_MASK) {
  
    if (!ob) {
      return get_web_page (get_add_file(data, data["projid"]), 
        "You must be online to add grant access to a file.");
    }
  }
  
  k = master()->valid_grant(name, data["fid"], access);
  
  tell_creator ("drakkos", "%d.\n", k);
  if (!k) {
      return get_web_page (get_add_file(data, data["projid"]), 
        "You do not have valid access to add this file to the tracker.");
  }

  PROJECT_HANDLER->add_file (data["projid"], data["fid"], 
    access, name, task);
                  
  return get_view_page (get_view_project (data["projid"], 1), data["projid"], 
    "File Permission Added.");      
}

protected string do_add_task (mapping data, string name) {
  string *required = ({"tid", "taskname"});
  string *creators;
  int i, valid;
  
  foreach (string r in required) {
    if (undefinedp (data[r])) {
      return get_web_page (get_add_task(data, data["projid"]), 
        "The " + r + " field is required.");
    }
  }
  
  data ["tid"] = get_id (data["tid"]);

  if (PROJECT_HANDLER->find_project (data["projid"]) == -1) {
      return get_web_page (get_add_task(data, data["projid"]), 
        "The project " + data["projid"] + " does not exist.");
  }

  if (PROJECT_HANDLER->find_task (data["projid"], data["tid"]) != -1) {
      return get_web_page (get_add_task(data, data["projid"]), 
        "The task " + data["tid"] + " already exists.");
  }
  
  if (PROJECT_HANDLER->valid_operation (name, TASK, data["projid"])) {
      valid = 1;
  }
  
  if (!valid) {
    return get_view_page (get_view_task(data["projid"], 
      data ["tid"]), data["projid"], "You do not have access to "
      "perform this operation.");
  }  

  creators = filter (explode_to_array (data["creators"]), 
    (: PLAYER_HANDLER->test_creator ($1) :));
     
  PROJECT_HANDLER->add_task_to_project (data["projid"], data["tid"], name);
  
  if (sizeof (data["taskname"])) {
    PROJECT_HANDLER->set_task_name (data["projid"], data["tid"],
      data["taskname"]);
  }

  if (sizeof (data["aims"])) {
    PROJECT_HANDLER->set_task_aims (data["projid"], data["tid"],
      data["aims"]);
  }

  if (sizeof (data["comments"])) {
    PROJECT_HANDLER->set_task_comments (data["projid"], data["tid"],
      data["comments"]);
  }
   
  if (sizeof (creators)) {
    foreach (string c in creators) {
      PROJECT_HANDLER->add_task_creator (data["projid"], data["tid"],
        c);
    }      
  }

  i = to_int (data["completed"]);
  
  if (i > 0 && i <= 100) {
    PROJECT_HANDLER->set_task_completion (data["projid"], data["tid"],
      i);
  }
  
  if (sizeof(data["number"]) && data["newest"] == "on") {
   PROJECT_HANDLER->set_task_completion_date (data["projid"], data["tid"],
        time() + get_time_value (data["number"], data["time"]));
  }
  
                
    return get_view_page (get_view_task(data["projid"], 
      data ["tid"]), data["projid"], "Task Added");    
}

string get_view_project (string id, int verbose) {
  string ret = "";
  class project p;

//  verbose = 1;
    
  p = PROJECT_HANDLER->get_project_file (id);
    
  if (!p) {
    return "There is no project with that ID.\n";
  }  
  ret +="<B>Project " + id + ":  </B><b>[</b> <a href=project.c?pid=" + 
    p->id + "&projecttype=Edit>Edit Project</a> | " 
  "<a href=project.c?pid=" + p->id + "&projecttype=Details>"
    "Project Details</a><b> ]</b><P>" 
  "<B>" + PROJECT_HANDLER->query_touched (p->id) + "</B><P>";      

  ret += "<TABLE width=100%>"
  "<TR>"
  "<TH width=30% align = \"left\"> Project ID: </TH>"
  "<TD>" + p->id + "<TD>"
  "<TR>"
  "<TR>"    
  "<TH align = \"left\"> Project Name: </TH>" 
  "<TD>" + p->name + "<TD>"    
  "<TR>"    
  "<TH align = \"left\"> Project Domains: </TH>" 
  "<TD>" + query_multiple_short (get_domain_links(p)) 
    + "<TD>"   
  "<TR>"        
  "<TH align = \"left\"> Project Leader: </TH>" 
  "<TD>" + query_multiple_short (get_creator_links (p->leader)) + "<TD>";
  if (sizeof (p->creators)) {
    ret += "<TR>"    
    "<TH align = \"left\"> Project Creators: </TH>" 
    "<TD>" +  query_multiple_short (get_creator_links (p->creators)) 
      + "<TD>";
  }    
  
  if (verbose) {
    ret += "<TD>"        
    "<TR>"    
    "<TH align = \"left\"> Percent complete: </TH>" 
    "<TD>";  

    if (!p->percent_complete) {           
      ret += PROJECT_HANDLER->query_project_completeness (p->id);
    }
    else {
      ret += "" + p->percent_complete;
    }
    
    ret += "%";
       
    if (sizeof (p->playtesters)) {           
      ret += "<TD>"        
      "<TR>"    
      "<TH align = \"left\"> Assigned Playtesters: </TH>" 
      "<TD>";  
      ret += query_multiple_short (map (p->playtesters, 
        (: capitalize ($1) :)));   
    }   
    if (p->estimated_completion) {           
      ret += "<TD>"        
      "<TR>"    
      "<TH align = \"left\"> Estimated Completion Date: </TH>" 
      "<TD>";  
      ret += ctime (p->estimated_completion);
    }                
    if (p->description) {           
      ret += "<TD>"        
      "<TR>"    
      "<TH align = \"left\"> Description: </TH>" 
      "<TD>";  
      ret += p->description;
    }       

    if (p->size >= 0) {
      ret += "<TD>"        
      "<TR>"    
      "<TH align = \"left\"> Size: </TH>" 
      "<TD>";  
      ret += capitalize (SIZE[p->size]);
    }
    if (p->complexity >= 0) {
      ret += "<TD>"        
      "<TR>"    
      "<TH align = \"left\"> Complexity: </TH>" 
      "<TD>";  
      ret += capitalize (COMPLEXITY [p->complexity]);
    }
    if (sizeof (p->guild_specific)) {           
      ret += "<TD>"        
      "<TR>"    
      "<TH align = \"left\"> Guild Specific: </TH>" 
      "<TD>";  
      ret += query_multiple_short (map (p->guild_specific, 
        (: capitalize ($1) :)));   
    }       
    
    if (p->last_rotation) {
      ret += "<TD>"        
      "<TR>"    
      "<TH align = \"left\"> Last rotation: </TH>" 
      "<TD>";  
      ret += ctime(p->last_rotation);
    }      
      
    if (sizeof (p->pt_notes)) {           
      ret += "<TD>"        
      "<TR>"    
      "<TH align = \"left\"> Notes for Playtesters: </TH>" 
      "<TD>";  
      ret += p->pt_notes;
    }     
    ret += "<TD>"    
    "<TR>"    
    "<TH align = \"left\"> Currently in: </TH>" 
    "<TD>";  
    ret += capitalize (STATUS[p->status]);
    if (p->last_status_change) {           
      ret += "<TD>"        
      "<TR>"    
      "<TH align = \"left\"> Last Status Change: </TH>" 
      "<TD>";  
      ret += ctime (p->last_status_change);
    }    
    ret += "<TD>"
      "<TR>"               
      "<TH align = \"left\"> Added by: </TH>" 
      "<TD>";  
    ret += query_multiple_short (get_creator_links(p->added_by)) + " at " 
      + ctime (p->date_added);            
    if (sizeof (p->sub_projects)) {
      ret += "<TD>"
      "<TR>"    
      "<TH align = \"left\"> Subproject IDs: </TH>" 
      "<TD>";  
      ret += query_multiple_short (map (p->sub_projects, (: "<a href="
        "project.c?projecttype=Details&pid=" + $1 + ">" + $1 + "</a>":)));             
    }    
//    if (sizeof (p->files)) {
//      ret += "<TD>"
//      "<TR>"    
//      "<TH align = \"left\"> Project Files: </TH>" 
//      "<TD>";  
//      ret += query_multiple_short (p->files);        
//    }
    if (sizeof (p->twiki)) {
      ret += "<TD>"
      "<TR>"    
      "<TH align = \"left\"> Project Twiki: </TH>" 
      "<TD>";  
      ret += query_multiple_short (get_twiki_links (p));               
    }
  }

 ret += "</TABLE>";
      
  return ret;        
}

string get_view_page (string page, string id, string title) {
  string ret = "";
  
  ret += page;

  ret += get_tasks_summary (id);
  ret += get_notes_summary (id);  
  ret += get_files_summary (id);  


  return get_web_page (ret, title);
}  
  
string www_task_info (class task p) {
  string ret = "";
  
  if (!p) {
    ret += "There is no task with that ID.\n";
  }
  
  else {
    ret += "<TABLE>"
    "<TR><TH align = \"left\"> Task ID: </TH>"
    "<TD>";
    ret += p->id;
    ret += "<TD>";
    ret += "<B>This task was added by: " + p->added_by + "</B>"
    "<TR>"    
    "<TH align = \"left\"> Task Name: </TH>" 
    "<TD>";  
    ret += p->task_name;
    ret += "<TD>"
    "<TR>";          
    ret += "<B>Added: " + ctime (p->date_added) + " </B>"
    "<TD>"    
    "<TR>"    
    "<TH align = \"left\"> Task creators: </TH>" 
    "<TD>";  
    ret += query_multiple_short (get_creator_links (p->assigned_to));
    ret += "<TD>"
    "<TR>";                   
    if (p->completion_date) {           
      ret += "<B> Estimated Completion Date: " + ctime (p->completion_date) 
        + "</B>"; 
    }                
    ret += "<TD>";        
    if (p->percent_complete) {           
      ret += "<TD>"        
      "<TR>"    
      "<TH align = \"left\"> Currently completed percentage: </TH>" 
      "<TD>";  
      ret += query_num (p->percent_complete);
      ret += "<TD>"
      "<TR>";   
    }   
    ret += "</TABLE>";
  }
  
  return ret;        
}


  
varargs string get_project_menu() {  
  string ret = "";
  string *no_project_list = ({"fluffy", "admin", "decrepit", "am_old"});
  string *domains = (master()->query_domains() - no_project_list);
  
  ret += "<form action=\"project.c\" METHOD=POST "
    "action=\"project.c?\">"
    "<TABLE>"
    "<TR><TH align = \"left\"> Projects: </TH>"
    "<TD>"  
    "<b>[</b> <a href=project.c?projecttype=Add>"
    "Add Project</a> | "    
    "<a href=project.c?projecttype=List>"
    "List Projects</a> | "
    "<a href=project.c?misc=Query> "
    "Query Projects </a> <b>]</b>"
    "<TD>"
    "<TR>"   
    "<TH align = \"left\"> Queries: </TH>"
    "<TD>"
    "<b>[</b> <a href=project.c?misc=Week> "
    "One Week Summary </a> | "
    "<a href=project.c?misc=Playtesting> "
    "Projects in Playtesting</a> <b>]</b>"
    "<TD>"
    "<TR>"
    "<TH align = \"left\"> Domains: </TH>" 
    "<TD> <b>[</b> ";
    
    for (int i = 0; i < sizeof (domains); i++) {      
      ret += "<a href=project.c?misc=Domlist&domain=" + domains[i] + ">"
        + capitalize (domains[i]) + "</a>";
      
      if (i != sizeof (domains) -1) {
        ret += " | ";
      }
      
    }
    
    ret += " <b>]</b></TABLE>"
    "<HR>";

  return ret;
  
}


varargs string get_add_project (mapping tmp) {
  string ret = "";
  
  if (!tmp) {
    tmp = ([ ]);
  }
  ret += "This is the add project page.  Enter the details of the project "
    "you wish to add, and then click 'add' to record them with the system.  "
    "Required fields are Project ID, Project Name and Project Description.  "
    "If you forget to complete any of these fields, you will be prompted "
    "again for details.<p><p>"
    "<hr><p>"
    "<TABLE>";
    
  ret += "<form action=\"project.c\" METHOD=POST "
    "action=\"project.c?\">";

  ret += "<TR>" 
    "<TH align = \"left\"> Project ID: </TH>"
    "<TD><INPUT NAME=\"projid\"";
  
  if (tmp["projid"]) {
    ret += "VALUE = \"" + tmp ["projid"] + "\"";
  }

  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Project Name: </TH>" 
    "<TD><INPUT NAME=\"name\"";

  if (tmp["name"]) {
    ret += "VALUE = \"" + tmp ["name"] + "\"";
  }
  
  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Project Leader: </TH>" 
    "<TD><INPUT NAME=\"leader\"";

  if (tmp["leader"]) {
    ret += "VALUE = \"" + tmp ["leader"] + "\"";
  }
  
  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Project Domains (separated by comma): </TH>" 
    "<TD><INPUT NAME=\"domains\"";
  
  if (sizeof (arrayp (tmp ["domains"]))) {
    ret += "VALUE = \"" + tmp["domains"] + "\"";
  }
  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Estimated Completion: </TH>" 
    "<TD>";
    ret += get_estimate();
    ret += "<TD>"  
    "<TR>"
    "<TH align = \"left\"> Project Creators (separated by comma): </TH>" 
    "<TD><INPUT NAME=\"creators\"";

  if (sizeof (tmp ["creators"])) {
    ret += "VALUE = \"" + tmp["creators"]  + "\"";
  }
  
  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Project Size: </TH><TD>";
       
  ret += "<SELECT NAME=\"size\">";
  
  for (int i = 0; i < sizeof (SIZE); i++) {
    ret += "<OPTION VALUE + \"" + SIZE[i] ;
    if (tmp["size"] == SIZE[i]) {
      ret += "selected ";
    }
  
    ret += "\">" + SIZE[i];
  }
  
  ret += "</SELECT>";

  ret += "<TD>"  
    "<TR>"
    "<TH align = \"left\"> Project Complexity: </TH><TD>";
       
  ret += "<SELECT NAME=\"complexity\">";
  
  for (int i = 0; i < sizeof (COMPLEXITY); i++) {
    ret += "<OPTION VALUE + \"" + COMPLEXITY[i] ;
    if (tmp["complexity"] == COMPLEXITY[i]) {
      ret += "selected ";
    }
  
    ret += "\">" + COMPLEXITY[i];
  }
  
  ret += "</SELECT>";

    ret += "<TD>"  
    "<TR>"
    "<TH align = \"left\"> Guilds (Of the form 'wizards,thieves', separated by comma, or leave blank): </TH>" 
    "<TD><INPUT NAME=\"guilds\"";

  if (sizeof (tmp ["guilds"])) {
    ret += "VALUE = \"" + tmp["guilds"]  + "\"";
  }      
  
//  if (sizeof (tmp["twiki"])) {
//    foreach (string t in twiki) {
//      PROJECT_HANDLER->add_twiki (data["projid"], t);
//    }
//  }
  
  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Subproject IDs (separated by comma): </TH>" 
    "<TD><INPUT NAME=\"sub\"";
//  ret += "><TD>"  
//    "<TR>"
//    "<TH align = \"left\"> Project Files (separated by comma): </TH>" 
//    "<TD><INPUT NAME=\"files\"";

//  if (sizeof (tmp ["files"])) {
//    ret += "VALUE = \"" + tmp["files"] + "\"";
//  }
  
  ret += "<TD>"  
    "<TR>"
    "<TH align = \"left\"> Project Twiki (separated by comma): </TH>" 
    "<TD><INPUT NAME=\"twiki\"";

  if (sizeof (tmp ["twiki"])) {
    ret += "VALUE = \"" + tmp["twiki"] + "\"";
  }
  
  ret += "><TD>"  
    "<TR>"
    "</TABLE>"
    "<B>Project Description:</B><P>" 
    "<TD><TEXTAREA cols=70 rows=6 wrap=\"virtual\""
      "NAME=\"description\">";
  if (tmp["description"]) {
    ret += tmp ["description"];
  }

  ret += "</TEXTAREA><P>";

  ret += "<INPUT TYPE=\"submit\" NAME = \"button\" VALUE=\"Add\">";
  ret += "<INPUT TYPE=\"reset\" VALUE=\"Reset\"><p>";
   
  return ret;
}

varargs string get_add_task (mapping tmp, string project) {
  string ret = "";
  
  if (!tmp) {
    tmp = ([ ]);
  }
  ret += "This is the add task page.  Enter the details of the task "
    "you wish to add, and then click 'add' to record them with the system.  "
    "Required fields are task ID, and task Name. you will be prompted "
    "again for details.<p><p>"
    "<hr><p>"
    "<TABLE>";

      
  ret += "<form action=\"project.c\" METHOD=POST "
    "action=\"project.c?\">";

 ret += "<TR>" 
    "<TH align = \"left\"> Project ID: </TH>"
    "<TD><INPUT NAME=\"projid\"";
  
  if (project) {
    ret += "VALUE = \"" + project + "\"";
  }
  ret += "<TD>"
    "<TR>" 
    "<TH align = \"left\"> Task ID: </TH>"
    "<TD><INPUT NAME=\"tid\"";
  
  if (tmp["tid"]) {
    ret += "VALUE = \"" + tmp ["tid"] + "\"";
  }

  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Task Name: </TH>" 
    "<TD><INPUT NAME=\"taskname\"";

  if (tmp["taskname"]) {
    ret += "VALUE = \"" + tmp ["taskname"] + "\"";
  }
  
  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Comments: </TH>" 
    "<TD><INPUT NAME=\"comments\"";

  if (tmp["comments"]) {
    ret += "VALUE = \"" + tmp ["comments"] + "\"";
  }
  
  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Task Creators (separated by comma): </TH>" 
    "<TD><INPUT NAME=\"creators\"";

  if (sizeof (tmp ["creators"])) {
    ret += "VALUE = \"" + tmp["creators"]  + "\"";
  }
  
  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Percent Completed: </TH>" 
    "<TD><INPUT NAME=\"completed\"";

  if (tmp["completed"]) {
    ret += "VALUE = \"" + tmp ["completed"] + "\"";
  }
  
  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Estimated completion: </TH>" 
    "<TD>" + get_estimate();    
  ret += "<TD>"  
    "<TR>"
    "</TABLE>"
  "<B>Task aims:</B><P>" 
    "<TD><TEXTAREA rows=6 cols=70 wrap=\"virtual\""
      "NAME=\"aims\">";
  if (tmp["aims"]) {
    ret += tmp ["aims"];
  }
  ret += "</TEXTAREA><P>"  
    "<INPUT TYPE=\"submit\" NAME = \"button\" VALUE=\"Add Task\">"
    "<INPUT TYPE=\"reset\" VALUE=\"Reset\"><p>";
   
  return ret;
}


varargs string get_add_note (mapping tmp, string project) {
  string ret = "";
  
  if (!tmp) {
    tmp = ([ ]);
  }
  ret += "This is the add note page.  Enter the details of the note "
    "you wish to add, and then click 'add' to record them with the system.  "
    "Required fields are note ID, and the note itself. you will be prompted "
    "again for details.<p><p>"
    "<hr><p>"
    "<TABLE>";
    
  ret += "<form action=\"project.c\" METHOD=POST "
    "action=\"project.c?\">";

  ret += "<TR>" 
    "<TH align = \"left\"> Project ID: </TH>"
    "<TD><INPUT NAME=\"projid\"";
  
  if (project) {
    ret += "VALUE = \"" + project + "\"";
  }

  ret += "><TD>"  
    "<TR>" 
    "<TH align = \"left\"> Note ID: </TH>"
    "<TD><INPUT NAME=\"nid\"";
  
  if (tmp["nid"]) {
    ret += "VALUE = \"" + tmp ["nid"] + "\"";
  }

  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Note: </TH>" 
    "<TD><TEXTAREA NAME=\"note\" rows=6 cols=70"
    " wrap=virtual>" + (tmp["note"] ? tmp ["note"] : 
    "") + "</TEXTAREA>"  
    "<TD>"
    "</TABLE>"
    "<INPUT TYPE=\"submit\" NAME = \"button\" VALUE=\"Add Note\">"
    "<INPUT TYPE=\"reset\" VALUE=\"Reset\"><p>";
   
  return ret;
}

varargs string get_add_file (mapping tmp, string project) {
  string ret = "";
  string *tasks = ({ });
  class project proj;
  
  proj = PROJECT_HANDLER->get_project_file (project);
  
  foreach (class task t in proj->tasks) {
    tasks += ({ t->id });    
  }
  
  
  if (!tmp) {
    tmp = ([ ]);
  }
   ret+= "<TABLE>"
    "<form action=\"project.c\" METHOD=POST "
    "action=\"project.c?\">"
    "<TR>" 
    "<TH align = \"left\"> Project ID: </TH>"
    "<TD><INPUT NAME=\"projid\"";
  
  if (project) {
    ret += "VALUE = \"" + project + "\"";
  }

  ret += "><TD>"  
    "<TR>" 
    "<TH align = \"left\"> Filename: </TH>"
    "<TD><INPUT NAME=\"fid\"";
  
  if (tmp["fid"]) {
    ret += "VALUE = \"" + tmp ["fid"] + "\"";
  }

  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Access: </TH>" 
    "<TD>"
    "<SELECT NAME=\"access\">";
    
    foreach (string a in ({"read", "read+write", "read+write+grant"}))  {   
      ret += "<OPTION  \"" + a + "\">"+ a;
    }
    
  ret += "</SELECT>"   
    "<TD>"  
    "<TR>" 
    "<TH align = \"left\"> Access Rights: </TH>"
    "<TD>"
    "<SELECT NAME=\"task\">";
    
    foreach (string a in ({"All project members", "Leader only"}) +
      tasks)  {   
      ret += "<OPTION  \"" + a + "\"" + (tmp["task"] == a ? 
      "selected" : "") + ">"+ a;
    }
    
  ret += "</SELECT>"   
     "</TABLE>"
    "<INPUT TYPE=\"submit\" NAME = \"button\" VALUE=\"Add File\">"
    "<INPUT TYPE=\"reset\" VALUE=\"Reset\"><p>";

  return ret;
}

varargs string get_modify_project (string id, string swit, string id_two, 
  int lead) {
  string ret = ""; 
  
  class project tmp = PROJECT_HANDLER->get_project_file (id);
  
  
  if (!tmp) {
    return "";    
  }
  
  
  ret += "<form action=\"project.c\" METHOD=POST "
    "action=\"project.c?\">"
    "<B>Project " + id + ": </B><b>[</b><a href=project.c?pid=" 
    + id + "&projecttype=Delete>"
    "Delete This Project</a> | "
    "<a href=project.c?pid=" 
    + id + "&projecttype=Details>"
    "Project Details</a> <b>]</b>"
    "<P><B>" + PROJECT_HANDLER->query_touched (tmp->id) + "</B></P>"
    "<HR><TABLE><TR>" 
    "<TH align = \"left\"> Project ID: </TH>"
    "<TD><INPUT NAME=\"projid\""
    "VALUE = \"" + tmp->id + "\""  
    "><TD>"
    "<TR>"
    "<TH align = \"left\"> Project Name: </TH>" 
    "<TD><INPUT NAME=\"name\""
    "VALUE = \"" + tmp->name + "\""    
    "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Project Leader: </TH>" 
    "<TD><INPUT NAME=\"leader\""
    "VALUE = \"" + tmp->leader + "\""  
    "><TD>"  
    "<B> This project was added by " + tmp->added_by +"</B>"     
    "<TR>"
    "<TH align = \"left\"> Project Domains (separated by comma): </TH>" 
    "<TD><INPUT NAME=\"domains\""
    "VALUE = \"" + implode (tmp->domains, ",") + "\""
    "><TD>"  
    "<B> Added: " + ctime (tmp->date_added) +"</B>"     
    "<TD>"
    "<TR>"
    "<TH align = \"left\"> Project Creators (separated by comma): </TH>" 
    "<TD><INPUT NAME=\"creators\""
    "VALUE = \"" + implode (tmp->creators, ",") 
    + "\"><TD>"
    "<TR>"
    "<TH align = \"left\"> Project Playtesters (separated by comma): </TH>" 
    "<TD><INPUT NAME=\"playtesters\"";
    if (tmp->playtesters) {
      ret += "VALUE = \"" + implode (tmp->playtesters, ",");
    }
    ret += "\">";

    ret += "<TD>"  
    "<TR>"
    "<TH align = \"left\"> Project Size: </TH><TD>";
       
    ret += "<SELECT NAME=\"size\">";
  
    for (int i = 0; i < sizeof (SIZE); i++) {
      ret += "<OPTION VALUE + \"" + SIZE[i] ;
      if (tmp->size  == i) {     
        ret += " selected ";
      }
  
      ret += "\">" + SIZE[i];
  }

    ret += "</SELECT>";     
    ret += "<TD>"  
    "<TR>"
    "<TH align = \"left\"> Project Complexity: </TH><TD>";
       
    ret += "<SELECT NAME=\"complexity\">";
  
    for (int i = 0; i < sizeof (COMPLEXITY); i++) {
      ret += "<OPTION VALUE + \"" + COMPLEXITY[i] ;
      if (tmp->complexity  == i) {
        ret += " selected ";
      }
  
      ret += "\">" + COMPLEXITY[i];
  }
  
  ret += "</SELECT>"    
    "<TD>"
    "<TR>"
    "<TH align = \"left\"> Guilds (Of the form 'wizards,thieves', separated by comma, "
      "or leave blank): </TH>" 
    "<TD><INPUT NAME=\"guilds\"";
    if (tmp->guild_specific) {
      ret += "VALUE = \"" + implode (tmp->guild_specific, ",");
    }
    ret += "\">";    
    ret += "<TD><TR>"
    "<TH align = \"left\"> Percent complete: </TH>" 
    "<TD><INPUT NAME=\"completed\"";
    if (tmp->percent_complete) {
      ret += "VALUE = \"" + tmp->percent_complete;
    }
    ret += "\"><TD><TR>";     
    if (tmp->estimated_completion) {
      ret += "<B> Estimated Completion: " + ctime 
        (tmp->estimated_completion) + "</B>";
    } 
   
    
    ret += "<TR>"
    "<TH align = \"left\"> Subproject IDs (separated by comma): </TH>" 
    "<TD><INPUT NAME=\"sub\"";    
    if (sizeof (tmp->sub_projects)) {
        ret += "VALUE = \"" + implode (tmp->sub_projects, ",") + "\"";
    }
  
    ret += "><TD>"   
    "<TR>"
    "<TH align = \"left\"> Project Twiki (separated by comma): </TH>" 
    "<TD><INPUT NAME=\"twiki\"";    
    if (sizeof (tmp->twiki)) {
        ret += "VALUE = \"" + implode (tmp->twiki, ",") + "\"";
    }
      
  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Update Estimate: </TH>" 
    "<TD>";
    ret += get_estimate();
    ret += "<TD>"  
    "<TR>"
    "<TH align = \"left\"> Project Status: </TH>" 
    "<TD><SELECT NAME=\"status\">";
    
    foreach (string stat in STATUS)  {   
      ret += "<OPTION  \"" + stat+ "\"";
    
      if (stat == STATUS[tmp->status]) {
        ret += " selected "; 
      }
      
      ret += ">" + stat;
    }      
  ret += "</SELECT>"
    "</TABLE>"
    
    "<B>Project Description:</B><P>"
    "<TEXTAREA NAME=\"description\" rows=6 cols=70 "
    "wrap=\"virtual\">" + tmp->description+ "</TEXTAREA><P>"    
    "<B>Notes for Playtesters:</B><P>"
    "<TEXTAREA NAME=\"ptnotes\" rows=6 cols=70 "
    "wrap=\"virtual\">" + tmp->pt_notes + "</TEXTAREA><P>"
    "<INPUT TYPE=\"submit\" NAME = \"button\" VALUE=\"Update\">"
    "<INPUT TYPE=\"reset\" VALUE=\"Reset\">";    

    
  if (swit) {
    switch (swit) {
      case "task":
        ret += get_modify_task(id, id_two);
      break;
      case "note":
        ret += get_modify_note(id, id_two);
      break;
      case "file":
        ret += get_modify_file (id, id_two, lead);
    }
    
  }
    
  ret += get_tasks_summary (id);
  ret += get_notes_summary (id);
  ret += get_files_summary (id);

  
  return ret;
  
}

varargs string get_modify_task (string id, string task) {
  string ret = "";  
  class task tmp;

  tmp  = PROJECT_HANDLER->get_task_file (id, task);
  
  ret += get_view_project (id, 0);
  
  ret += "<HR><TABLE>";  
  
  if (!tmp) {
    return "";    
  }
  
  ret += 
    "<form action=\"project.c\" METHOD=POST "
    "action=\"project.c?\">"
    "<B>Task " + id + ": </B><b>[</b><a href=project.c?pid=" + id 
    + "&tasktype=Delete&tid=" + task + ">"
    "Delete This Task</a> <b>]</b> <p>"    
    "<TABLE>"
    "<TH align = \"left\"> Project ID: </TH>" 
    "<TD><INPUT NAME=\"projid\""
    "VALUE = \"" + id + "\""    
    "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Task ID: </TH>" 
    "<TD><INPUT NAME=\"tid\""
    "VALUE = \"" + tmp->id + "\""    
    "><TD>"  
    "<B>This task was added by " + tmp->added_by + "</B>"
    "<TR>"
    "<TH align = \"left\"> Task Name: </TH>" 
    "<TD><INPUT NAME=\"taskname\""
    "VALUE = \"" + tmp->task_name + "\""    
    "><TD>"  
    "<B>Added: " + ctime (tmp->date_added) + " </B>"
    "<TR>"
    "<TH align = \"left\"> Comments: </TH>" 
    "<TD><INPUT NAME=\"comments\""
    "VALUE = \"" + tmp->comments+ "\""  
    "><TD>";  
    if (tmp->completion_date) {
    ret += "<B>Estimated Completion: " + ctime (tmp->completion_date) 
      + "</B>";
    }
    ret += "<TR><TH align = \"left\"> Project creators (separated by "
    "comma): "
    "</TH>" 
    "<TD>"
    "<INPUT NAME=\"assigned\"";
    if (sizeof (tmp->assigned_to)) {      
      ret += "VALUE = \"" + implode (tmp->assigned_to, ",") + "\"";  
    }
    ret += "><TD><TR>"
      "<TH align = \"left\"> Percent Complete: </TH>" 
      "<TD><INPUT NAME=\"completed\""
      "VALUE = \"" + tmp->percent_complete+ "\""  
      "><TD>"  
      "<TR>"
      "<TH align = \"left\"> Estimated Completion date: </TH>"
      "<TD>";
    ret += get_estimate();
    ret += "<TD>"  
      "<TR>"
      "</TABLE>"
      "<B>Task Aims:</B><P>"
      "<TEXTAREA NAME=\"aims\" rows=6 cols=70 "
      "wrap=\"virtual\">" + tmp->aims+ "</TEXTAREA><P>"  
      "<INPUT TYPE=\"submit\" NAME = \"button\" VALUE=\"Update Task\">"
      "<INPUT TYPE=\"reset\" VALUE=\"Reset\"><p>";  
  return ret;
}


varargs string get_modify_file (string id, string file, string task) {
  string ret = "";  
  class file tmp;

  
  tmp  = PROJECT_HANDLER->get_file (id, file, task);
  
  ret += get_view_project (id, 0);
  
  ret += "<HR><TABLE>";  
  
  if (!tmp) {
    return "";    
  }
  ret += 
    "<form action=\"project.c\" METHOD=POST "
    "action=\"project.c?\">"
    "<B>File " + file + ": </B><b>[</b> <a href=project.c?pid=" + id 
    + "&filetype=Delete&fid=" + file+ "&task=" + task+ ">"
    "Delete This Permission</a> <b>]</b><p>"    
    "<TABLE width=100%>"
    "<TR>"
    "<TH align = \"left\"> Project ID: </TH>" 
    "<TD width=50%><INPUT NAME=\"projid\""
    "VALUE = \"" + id + "\""    
    "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Filename: </TH>" 
    "<TD width=50%><INPUT NAME=\"file\""
    "VALUE = \"" + file + "\""    
    "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Access: </TH>" 
    "<TD>"
    "<SELECT NAME=\"access\">";
    
    foreach (string a in ({"read", "write", "grant"}))  {   
      ret += "<OPTION  \"" + a + "\">"+ a;
    }
    
    ret += "</SELECT>"   
    "<TD>"  
    "<TR>"
    "<TH align = \"left\"> Leader Only: </TH>" 
    "<TD>"
    "<SELECT NAME=\"lead\">";
    
    foreach (string a in ({"yes", "no"}))  {   
      ret += "<OPTION  \"" + a + "\">" + a;
    }
    ret += "</SELECT>"
      "</TABLE>"
    "<INPUT TYPE=\"submit\" NAME = \"button\" VALUE=\"Update File\">"
    "<INPUT TYPE=\"reset\" VALUE=\"Reset\"><p>";

  return ret;
}

varargs string get_modify_note (string id, string note) {
  string ret = "";  
  class note tmp;

  
  tmp  = PROJECT_HANDLER->get_note_file (id, note);
  
  ret += get_view_project (id, 0);
  
  ret += "<HR><TABLE>";  
  
  if (!tmp) {
    return "";    
  }
  ret += 
    "<form action=\"project.c\" METHOD=POST "
    "action=\"project.c?\">"
    "<B>Note " + note + ": </B><b>[</b> <a href=project.c?pid=" + id 
    + "&notetype=Delete&nid=" + note + ">"
    "Delete This Note</a> <b>]</b><p>"    
    "<TABLE width=100%>"
    "<TR>"
    "<TH align = \"left\"> Project ID: </TH>" 
    "<TD width=50%><INPUT NAME=\"projid\""
    "VALUE = \"" + id + "\""    
    "><TD>"
    "<B>This note was added by " + tmp->added_by + "</B><BR>"
    "<TR>"    
    "<TH align = \"left\"> Note ID: </TH>" 
    "<TD><INPUT NAME=\"nid\""
    "VALUE = \"" + tmp->id + "\""    
    "><TD>"
    "<B>Added: " + ctime (tmp->date_added) + "</B>"      
    "</TABLE>"
    "<TEXTAREA NAME=\"note\" ROWS=6 COLS=70 "
    " wrap=virtual>" + tmp->note + "</TEXTAREA><P>"    
    "<INPUT TYPE=\"submit\" NAME = \"button\" VALUE=\"Update Note\">"
    "<INPUT TYPE=\"reset\" VALUE=\"Reset\"><p>";
  
  return ret;
}

varargs string get_view_note (string id, string note) {
  string ret = "";  
  class note tmp;

  ret += get_view_project (id, 0);  
  
  tmp  = PROJECT_HANDLER->get_note_file (id, note);
  
  
  if (!tmp) {
    return "";    
  }
    
  ret += "<HR>"
      "<B>Note " + note + ": </b><a href=project.c?nid=" + tmp->id + 
      "&notetype=Edit&pid=" 
      + id + ">Edit Note</a><P> "
    "<TABLE width=100%>"
    "<TR>"
    "<TH width=30% align = \"left\"> Note ID: </TH>" 
    "<TD>" + tmp->id + "<TD>"  
    "<TR>"
    "<TH align = \"left\"> Added by: </TH>" 
    "<TD>" + capitalize (tmp->added_by) + " at " + ctime (tmp->date_added) 
      + "<TD>"  
    "<TR>"
    "<TH valign = \"top\" align = \"left\"> Note: </TH>" 
    "<TD>" + replace (tmp->note, ({"\n\n", "<p>", "\n", "<br>"})) + "<TD>"  
    "<TR>"


    "</TABLE>";

  return ret;
}

varargs string get_query_project (mapping tmp) {
  string ret = "<TABLE>";
  
  if (!tmp) {
    tmp = ([ ]);
  }
  
  ret += "<form action=\"project.c\" METHOD=POST "
    "action=\"project.c?\">";

  ret += "<TR>" 
    "<TH align = \"left\"> Project Domains (separated by comma): </TH>"
    "<TD><INPUT NAME=\"domains\"";
  
  if (tmp["domains"]) {
    ret += "VALUE = \"" + tmp ["creators"] + "\"";
  }

  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Project Creators (separated by comma): </TH>" 
    "<TD><INPUT NAME=\"creators\"";

  if (tmp["creators"]) {
    ret += "VALUE = \"" + tmp ["creators"] + "\"";
  }
  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Project Playtesters (separated by comma): </TH>" 
    "<TD><INPUT NAME=\"playtesters\"";

  if (tmp["playtesters"]) {
    ret += "VALUE = \"" + tmp ["playtesters"] + "\"";
  }  

  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Minimum completeness: </TH>" 
    "<TD><INPUT NAME=\"completeness\"";

  if (tmp["completeness"]) {
    ret += "VALUE = \"" + tmp ["completeness"] + "\"";
  }
    
  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Project Leader: </TH>" 
    "<TD><INPUT NAME=\"leader\"";

  if (tmp["leader"]) {
    ret += "VALUE = \"" + tmp ["leader"] + "\"";
  }
  
  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Project Status: </TH>" 
    "<TD><SELECT NAME=\"status\">";
    
    foreach (string stat in STATUS)  {   
      ret += "<OPTION  \"" + stat+ "\">" + stat;
    }

  ret += "<OPTION  \"all\" selected> all"  
    "</SELECT>"
    "<TR><TH align = \"left\"> Last touched: </TH>" 
    "<TD>" + get_estimate(1) + "<TD><TR>";

  if (tmp["leader"]) {
    ret += "VALUE = \"" + tmp ["leader"] + "\"";
  }

  ret +="</TABLE>"
    "<INPUT TYPE=\"submit\" NAME = \"button\" VALUE=\"Query\">"
    "<INPUT TYPE=\"reset\" VALUE=\"Reset\"><p>";

  return ret;
}

varargs string get_query_task (mapping tmp) {
  string ret = "<TABLE>";
  
  if (!tmp) {
    tmp = ([ ]);
  }
  
  ret += "<form action=\"project.c\" METHOD=POST "
    "action=\"project.c?\">";

  ret += "<TR>" 
    "<TH align = \"left\"> Task Creators (separated by comma): </TH>"
    "<TD><INPUT NAME=\"creators\"";
  
  if (tmp["creators"]) {
    ret += "VALUE = \"" + tmp ["creators"] + "\"";
  }

  ret += "><TD>"  
    "<TR>"
    "<TH align = \"left\"> Percent Completed: </TH>" 
    "<TD><INPUT NAME=\"completed\"";

  if (tmp["completed"]) {
    ret += "VALUE = \"" + tmp ["completed"] + "\"";
  }
  
  ret += "><TD>"  
    "<TR>"
    "</TABLE>"
    "<INPUT TYPE=\"submit\" NAME = \"button\" VALUE=\"Query\">"
    "<INPUT TYPE=\"reset\" VALUE=\"Reset\"><p>";

  return ret;
}



void create() {
  seteuid (geteuid());
}

  
string get_header(string title) {
  string ret = "";
  
  ret += "<html><head><title> Project Management 0.7a</title>";
  ret += "<meta http-equiv=\"Content-Type\" content=\"text/html; "
    "charset=iso-8859-1\"><meta http-equiv=\"Cache-Control\" "
     "content=\"expires=-1\"/></head><body bgcolor=\"#ffffff\" "
    "text=\"#000030\" link=\"#4a529c\" vlink=\"#b57339\">"
    "<table width=\"75%\" border=\"0\"><tr VALIGN=TOP>";
  ret += "<td><font face=\"arial,helvetica\"><img align=left "
    "src = \"http://discworld.imaginary.com/external//pics/dw4.gif\">"
    "</font></td>"
    "<td><font face=\"arial,helvetica\">" 
    "<h2>Project Management 0.7a</h2>";
  ret += "</font>"
    "<p><font face=\"arial,helvetica\"><h2>" + title + "</h2>"
    "</p>"
    "<a href=project.c?misc=instructions>Instructions</a>"
    "<br>"
    "<a href=../../secure>Back to the secure pages</a>"
    "</td></tr></table>";
  ret += get_project_menu();
  
  return ret;
}

/**
 *  This function requests the standard footer for the Discworld
 *  web-pages.
 *  @return string  The HTML code for the footer.
 *
 */
 
string get_footer() {
    return "/www/footer"->www_function("footer", ([ ])) +"</body></html>";
}

string get_web_page (string text, string title) {
  return get_header (title) + text + get_footer();
}


string get_instructions(string category) {
  string ret = "";
  

  ret += "<h2>Index Of Help</h2>"
    "<a href=project.c?misc=instructions&cat=access>Access "
        "Rights</a><br>" 
    "<a href=project.c?misc=instructions&cat=addnote>Adding a note</a><br>"        
    "<a href=project.c?misc=instructions&cat=addproject>Adding a project"
      "</a><br>"
    "<a href=project.c?misc=instructions&cat=addtask>Adding a task</a><br>"
    "<a href=project.c?misc=instructions&cat=domainstuff>Master object "
      "modifications</a><br>"
    "<a href=project.c?misc=instructions&cat=modnote>Modifying a note"
      "</a><br>"      
    "<a href=project.c?misc=instructions&cat=modproject>Modifying a "
      "project</a><br>"      
    "<a href=project.c?misc=instructions&cat=modtask>Modifying a "
      "task</a><br>"      
    "<a href=project.c?misc=instructions&cat=queryprojects>Querying the "
      "database</a><p>";
        
  switch (category){ 
    case "access":
      ret += "<h2>Access Rights</h2>"
      "The access rights for the system are as default:<p>"
      "<ol>"
      "<li>Highlords have full write to all data within the system."
      "<li>Everyone can read everything in the system."
      "<li>The lord and deputy of the playtesters domain can modify "
        "playtester assignments in any domain."
      "<li>Domain lords can assign playtesters to projects within their "
        "domains."
      "<li>Domain lords and deputies can add, delete and edit all projects, "
        "notes and tasks within their domain."       
      "<li>Project leaders can delete and modify the projects they are "
        "leading, and can add, delete and edit tasks and notes for the "
        "projects they are actively coding for."
      "<li>Project creators can add, delete and modify tasks and notes "
        "for the projects they are assigned to."
      "</ol>"
      "Domain lords can override 4, 5, 6 and 7 by modifying their master "
      "objects to over-ride the defaults.  See 'master object "
      "modifications' for more details.<p>";
    break;
    case "domainstuff":
      ret += "<h2>Domain stuff</h2>"
        "You can use the features of the project tracker within your "
        "own domain.  The simplest way to make use of it is to use "
        "the $project$ string in your creator's projects.  This will "
        "be expanded to their list of projects are returned from the "
        "tracker.<p>"
        "You can also over-ride the default functionality of the "
        "security restrictions by defining a function in your "
        "domain object called project_callback:<p>"
        "<pre>"
        "int project_callback (string name, string action, string project) {"
        "<br>  if (name == LORD) {"
        "<br>     return 1;"
        "<br>  }"
        "<br>  return 0;"
        "<br>}"
        "<br></pre>"
        "<p>This is an extreme example, of course, and restricts it so "
        "only the lord of the domain is allowed to modify any aspect "
        "of any project within the domain.<p>"
        "<b>Name</b> is the name of the creator making a change to the "
        "database.<br>"
        "<b>Action</b> is the action being performed, one of 'project', "
        "'task', 'note' or 'playtesting'<br>"
        "<b>Project</b> is the project being modified.<p>"
        "The function should return 1 if the action is allowed, 0 if it "
        "is not, and -1 if the defaults should be used.<p>";              
    break;
    case "addproject":
      ret += "<h2>Adding a Project</h2>"
      "First, click on 'add a project'.  This will bring up a form "
      "containing the information you need to enter into the system. "
      "Enter each of these pieces of information in turn as required.  "
      "You will need to enter at least a project ID, a project name, "
      "and at least one domain for the project.<p>"
      "<b>Project ID</b>:  This is the unique code for the project that "
      "identifies it in the database.  If you put mutliple words in "
      "this field, it will concatonate them into 'twiki notation'... "
      "so 'project tracker' becomes ProjectTracker.<p>"
      "<b>Project Name</b>: This is a descriptive name for the project.  "
      "This differs from the project ID in that the project ID is used "
      "internally within the tracker, whereas the name is used "
      "externally, for example in domain finger info and the list of "
      "projects in playtesting.<p>"
      "<b>Project Leader</b>: The leader for the project.  Project leaders "
      "have full access over the project in the tracker, and can update the "
      "project file, and add tasks and notes as required.  See " 
      "<a href=project.c?misc=instructions&cat=access>Access Rights</a> "
      "for more information on how access rights work.<p>"
      "<b>Project Domains</b>: The domains the project belongs to.  You "
      "must be a HL or the lord of at least one of the domains to add "
      "a project to the tracker.<p>"
      "<b>Estimated Completion</b>: The rough estimate of how long it "
      "will take to complete the project.  If you wish to have this "
      "estimate recorded with the system, check the 'update' checkbox.  "
      "If you do not, it will ignore any estimate you place into the "
      "system.<p>"
      "<b>Project Creators</b>: The creator assigned to the project.  "
      "These do not actually have to be members of the domain to "
      "be assigned, but if they are not they will not have their "
      "project displaying in their finger info.<p>"
      "<b>Subproject IDs</b>: The larger projects that form part of "
      "the main project.  While these stand as projects in themselves, "
      "their state of completion reflects on that of the main project.  "
      "The percentage of a project's completion will be modified by "
      "how complete any sub projects are.<p>"
      "<b>Project Files</b>: Any relevant files related to the project.<p>"
      "<b>Project Twiki</b>: Any relevant twiki pages for the project.  "
      "If you simply enter a twiki name (such as ProjectTracker) it will "
      "assume the twiki page may be found on the project's first domain.  "
      "So if you have a project belonging to Forn and Main, it will "
      "assume you mean Forn.ProjectTracker.  If you wish to direct the "
      "link to a particular twiki page, you will need to give the web, then "
      "the page... so Main.ProjectTracker.<p>"
      "<b>Description</b>: The description of what the project actually "
      "involves.<p>"
      "Once you've entered all the information you have, click 'add' to "
      "add the project to the database.  If you have left anything out "
      "or do not have authority to add projects, you will find yourself "
      "back at the add project page.<p>";
    break;
    case "addtask":
      ret += "<h2>Adding a Task</h2>"
      "First, click on the 'add new task' link in the project details.  "
      "page.  This will bring up a form "
      "containing the information you need to enter into the system. "
      "Enter each of these pieces of information in turn as required.  "
      "You will need to enter at least a project ID, a task ID, "
      "and a task ID.<p>"
      "<b>Project ID</b>:  This is the project that the task "
      "belongs to.<p>"      
      "<b>Task ID</b>:  This is the unique code for the task that "
      "identifies it in the database.  If you put mutliple words in "
      "this field, it will concatonate them into 'twiki notation'... "
      "so 'project tracker' becomes ProjectTracker.<p>"
      "<b>Task Name</b>: This is a descriptive name for the task."
      "<b>Comments</b>: Any points of note about this task, such as "
      "'everyone who ever worked on this project has died in a "
      "freak accident involving baby dolphins'.<p>"
      "<b>Task Creators</b>: The creators assigned to the task.  "
      "These do not actually have to be members of the project to "
      "be assigned.<p>"
      "<b>Percent complete</b>: How much of the task has been "
      "completed.<p>"
      "<b>Estimated completion</b>: The rough estimate of how long it "
      "will take to complete the project.  If you wish to have this "
      "estimate recorded with the system, check the 'update' checkbox.  "
      "If you do not, it will ignore any estimate you place into the "
      "system.<p>"
      "<b>Task aims</b>: What is the task concerned with.<p>"
      "Once you've entered all the information you have, click 'add' to "
      "add the task to the the project.  If you have left anything out "
      "or do not have authority to add tasks, you will find yourself "
      "back at the add tasks page.<p>";
    break;
    case "addnote":
      ret += "<h2>Adding a Note</h2>"
      "First, click on the 'add new note' link in the project details.  "
      "page.  This will bring up a form "
      "containing the information you need to enter into the system. "
      "Enter each of these pieces of information in turn as required.  "
      "You will need to enter at least a project ID, a note ID, "
      "and a note.<p>"
      "<b>Project ID</b>:  This is the project that the task "
      "belongs to.<p>"      
      "<b>Note ID</b>:  This is the unique code for the note that "
      "identifies it in the database.  If you put mutliple words in "
      "this field, it will concatonate them into 'twiki notation'... "
      "so 'project tracker' becomes ProjectTracker.<p>"
      "<b>Note</b>: The note itself.<p>";
    break;    
    case "modnote":
      ret += "<h2>Modifying a Note</h2>"
      "First, click on the 'edit note' for the note in the project "
      "details.  page.  This will bring up a form "
      "containing the information you need to enter into the system. "
      "Enter each of these pieces of information in turn as required.  "
      "You will need to enter at least a project ID, a note ID, "
      "and a note.<p>"
      "<b>Project ID</b>:  This is the project that the task "
      "belongs to.<p>"      
      "<b>Note ID</b>:  This is the unique code for the note that "
      "identifies it in the database.  If you put mutliple words in "
      "this field, it will concatonate them into 'twiki notation'... "
      "so 'project tracker' becomes ProjectTracker.<p>"
      "<b>Note</b>: The note itself.<p>";
    break;        
    case "modtask":
      ret += "<h2>Modifying a Task</h2>"
      "First, click on the 'edit' link for the task in the project "
      "details.  page.  This will bring up a form "
      "containing the information you need to enter into the system. "
      "Enter each of these pieces of information in turn as required.  "
      "You will need to enter at least a project ID, a task ID, "
      "and a task ID.<p>"
      "<b>Project ID</b>:  This is the project that the task "
      "belongs to.<p>"      
      "<b>Task ID</b>:  This is the unique code for the task that "
      "identifies it in the database.  If you put mutliple words in "
      "this field, it will concatonate them into 'twiki notation'... "
      "so 'project tracker' becomes ProjectTracker.<p>"
      "<b>Task Name</b>: This is a descriptive name for the task."
      "<b>Comments</b>: Any points of note about this task, such as "
      "'everyone who ever worked on this project has died in a "
      "freak accident involving baby dolphins'.<p>"
      "<b>Task Creators</b>: The creators assigned to the task.  "
      "These do not actually have to be members of the project to "
      "be assigned.<p>"
      "<b>Percent complete</b>: How much of the task has been "
      "completed.<p>"
      "<b>Estimated completion</b>: The rough estimate of how long it "
      "will take to complete the project.  If you wish to have this "
      "estimate recorded with the system, check the 'update' checkbox.  "
      "If you do not, it will ignore any estimate you place into the "
      "system.<p>"
      "<b>Task aims</b>: What is the task concerned with.<p>"
      "Once you've entered all the information you have, click 'add' to "
      "add the task to the the project.  If you have left anything out "
      "or do not have authority to add tasks, you will find yourself "
      "back at the add tasks page.<p>";
    break;    
    case "modproject":
      ret += "<h2>Modifying a Project</h2>"
      "First, click on the 'edit' link for the project.  This will bring up "
      "a form containing the information you need to enter into the system. "
      "Enter each of these pieces of information in turn as required.  "
      "You will need to enter at least a project ID, a task ID, "
      "and a task ID.<p>"
      "<b>Project ID</b>:  This is the unique code for the project that "
      "identifies it in the database.  If you put mutliple words in "
      "this field, it will concatonate them into 'twiki notation'... "
      "so 'project tracker' becomes ProjectTracker.<p>"
      "<b>Project Name</b>: This is a descriptive name for the project.  "
      "This differs from the project ID in that the project ID is used "
      "internally within the tracker, whereas the name is used "
      "externally, for example in domain finger info and the list of "
      "projects in playtesting.<p>"
      "<b>Project Leader</b>: The leader for the project.  Project leaders "
      "have full access over the project in the tracker, and can update the "
      "project file, and add tasks and notes as required.  See " 
      "<a href=project.c?misc=instructions&cat=access>Access Rights</a> "
      "for more information on how access rights work.<p>"
      "<b>Project Domains</b>: The domains the project belongs to.  You "
      "must be a HL or the lord of at least one of the domains to add "
      "a project to the tracker.<p>"
      "<b>Project Creators</b>: The creator assigned to the project.  "
      "These do not actually have to be members of the domain to "
      "be assigned, but if they are not they will not have their "
      "project displaying in their finger info.<p>"
      "<b>Project Playtesters</b>: The playtesters who are assigned "
      "to this project.  The lord of the domain and the lord or "
      "deputies of the playtesting domain can modify this field.<p>"
      "<b>Project Completeness</b>: How complete the project is.  If "
      "you set a value for this, it will over-ride the automatic "
      "calculation used.  If you leave this blank, the project "
      "completeness will be calculated by adding together the completess "
      "of all tasks and subprojects.  For projects that do not have either, "
      "the value will need to be updated manually.<p>"
      "<b>Subproject IDs</b>: The larger projects that form part of "
      "the main project.  While these stand as projects in themselves, "
      "their state of completion reflects on that of the main project.  "
      "The percentage of a project's completion will be modified by "
      "how complete any sub projects are.<p>"
      "<b>Project Files</b>: Any relevant files related to the project.<p>"
      "<b>Project Twiki</b>: Any relevant twiki pages for the project.  "
      "If you simply enter a twiki name (such as ProjectTracker) it will "
      "assume the twiki page may be found on the project's first domain.  "
      "So if you have a project belonging to Forn and Main, it will "
      "assume you mean Forn.ProjectTracker.  If you wish to direct the "
      "link to a particular twiki page, you will need to give the web, then "
      "the page... so Main.ProjectTracker.<p>"
      "<b>Update estimate</b>: The rough estimate of how long it "
      "will take to complete the project.  If you wish to have this "
      "estimate recorded with the system, check the 'update' checkbox.  "
      "If you do not, it will ignore any estimate you place into the "
      "system.<p>"
      "<b>Project status</b>: The status of the project.  Heap refers "
      "to a project that is still conceptual.  Development is a project "
      "that is actively being coded.  Playtesting is a project that has "
      "been approved for playtesting and is undergoing revisions.  "
      "Play is a project that has been put into the game.  Limbo is "
      "for projects that fall somewhere between these stages... mainly "
      "projects that are no longer conceptual, but are not under active "
      "development.<p>"
      "<b>Description</b>: The description of what the project actually "
      "involves.<p>"
      "Once you've entered all the information you have, click 'update' to "
      "modify the project in the database.  If you have left anything out "
      "or do not have authority to add projects, you will find yourself "
      "back at the modify project page.<p>";
    break;    
    case "queryprojects":
      ret += "<h2>Querying projects</h2>"
      "First, click on the 'query projects' link.  This will bring up "
      "a form containing the information you need to enter into the system. "
      "Enter each of these pieces of information in turn as required.  If "
      "you do not enter anything, you will simply get the list of all "
      "projects in the system (the same one you get by clicking "
      "'list projects').<p>"
      "<b>Project Domains</b>: The domains the project belongs to. This is "
      "an AND search... if you enter two domains here, it will look for "
      "projects that belong to domain A and domain B.<p>"
      "<b>Project creators</b>: The creators assigned to the project. "
      "This is an AND search... if you enter two creators here, it will "
      "look for projects that are assigned to creator A and creator B.<p>"
      "<b>Project playtesters</b>: The playtesters assigned to the project. "
      "This is an AND search... if you enter two PTs here, it will "
      "look for projects that are assigned to PT A and PT B.<p>"
      "<b>Minimum completeness</b>: Match projects only that have at "
      "least this level of completeness.  So if you want only projects "
      "that are at least half completed, you would search for 50.<p>"
      "<b>Project leader</b>: Search for the projects that this creator "
      "is a leader of.<p>"
      "<b>Project status</b>: Search for projects that have a specific "
      "status.  'all' will match all projects, regardless of status.<p>"
      "<b>Last touched</b>: Return only projects that have been touched "
      "in the specified amount of time.<p>"
      "These queries are cumulative, so if you enter 'drakkos' in the "
      "creator box, and 'forn' in the domain box, you will get all the "
      "projects in the forn domain that have drakkos as a creator, and "
      "so forth.<p>";   
    break;        
    default:
      ret += "This is the creator project management system for "
      "the Discworld MUD.<p>  "
      "The interface is hopefully fairly intuitive.  The top row of links "
      "are project options.  You can add a project if you have the authority "
      "to do so, list all the projects in the database, or list projects "
      "according to whatever information you are looking for.<p>"
      "The next row of links are the domains covered by the project tracker.  "
      "Click on a domain to get the project list for that domain only.<p>"
      "When you see a project you are interested in, click on 'details' for "
      "the project details and a list of any tasks/notes assosciated with "
      "that project.  Click on edit if you wish to alter the details for that "
      "project.  If you wish to delete a project, you must first click on "
      "edit and then the delete link from there.  That may seem awkwardly "
      "obscure, but it's intentional in that you have to follow a process to "
      "delete an entry from the database, rather than being able to do it "
      "with a misplaced click.<p>"  
      "<h2>Thx bye!</h2>"
      "The system as, at the moment, still undergoing adjustments and "
      "modifications.  If you have any feedback on the interface or requests "
      "for further functionality, mail Drakkos with your suggestions.<p>"
      "Thx bye, flyheads!<p>";      
  }
  
    
  return ret;
}

string www_request (string name, mapping args, class http_request request) {
  
  mapping data = request->body->data;
  class project *tmp;
  string ret = "";
  int i;

  if (request->user != "drakkos") {
    tell_creator ("drakkos", "%s: %d.\n", request->user, sizeof (data));
  }
    
  switch (args["tasktype"]) {
    case "Details":
      ret = get_view_page (get_view_task (args["pid"], args["tid"]),
        args["pid"], "Task Details");
    break;   
    case "Delete":
      if (PROJECT_HANDLER->valid_operation (request->user, TASK, 
        args["pid"])) {      
        PROJECT_HANDLER->delete_task(args["pid"], args["tid"], request->user);
        ret = get_view_page(get_view_project(args["pid"], 1), args["pid"], 
          "Task deleted.");
      }
      else {
        ret = get_web_page ("", "You do not have the authority to "
          "perform this operation.");
       }      
    break; 
    case "Add":
      ret = get_web_page (get_add_task(data, args["pid"]), "Adding a task");
    break;     
    case "Edit":
      ret = get_web_page (get_modify_task(args["pid"], args["tid"]), 
        "Editting a task");    
    break;          
  }    

  switch (args["notetype"]) {
    case "Details":
      ret = get_view_page (get_view_note (args["pid"], args["nid"]), 
        args["pid"], "Note Details");
    break;   
    case "Delete":
      if (PROJECT_HANDLER->valid_operation (request->user, NOTE, 
        args["pid"])) {      
        PROJECT_HANDLER->delete_note(args["pid"], args["nid"], request->user);
        ret = get_view_page(get_view_project(args["pid"], 1), args["pid"],
          "Note deleted.");
      }
      else {
        ret = get_web_page (get_modify_project (args["pid"]), "You do not "
          "have the authority to perform this operation.");
       }      
    break; 
    case "Add":
      ret = get_web_page (get_add_note(data, args["pid"]), "Adding a note");
    break;     
    case "Edit":
      ret = get_web_page (get_modify_note(args["pid"], args["nid"]), 
        "Editting a note");    
    break;           
  }  

  switch (args["filetype"]) {
    case "Add":
      ret = get_web_page (get_add_file(data, args["pid"]), "Adding File "
        "Permission");
    break;     
    case "Delete":
      if (PROJECT_HANDLER->valid_operation (request->user, FILE, 
        args["fid"])) {    
        tell_creator ("drakkos", "%O.\n", args);
        i = PROJECT_HANDLER->remove_file(args["pid"], args["fid"], 
          args["task"],
          request->user);
        tell_creator ("drakkos", "%d.\n", i);
        ret = get_view_page(get_view_project(args["pid"], 1), args["pid"], 
          "File Permissions deleted.");
      }
      else {
        ret = get_web_page ("", "You do not have the authority to "
          "perform this operation.");
       }        
    break;
  }  
    
  switch (args["projecttype"]) {
    case "Delete":
      if (PROJECT_HANDLER->valid_operation (request->user, PROJECT, 
        args["pid"])) {      
        PROJECT_HANDLER->delete_project (args["pid"], request->user);
        ret = get_web_page (get_project_list(), "Project deleted.");
      }
      else {
        ret = get_web_page (get_modify_project (args["pid"]), "You do not "
          "have the authority to perform this operation.");
       }       
    break;  
    case "Add":
      ret = get_web_page (get_add_project(), "Adding a project");
    break;    
    case "List":
      ret = get_web_page (get_project_list(), "Project List");
    break;        
    case "Details":
      ret = get_view_page (get_view_project(args["pid"], 1), args["pid"], 
        "Project Details");
    break;    
    case "Edit":
      ret = get_web_page (get_modify_project(args["pid"]), 
        "Editting a project");
    break;
    case "File":
      ret = get_web_page (get_files_summary (args["pid"]), 
        "File Permission Details");
    break;    
      
  }
  
  switch (args["misc"]) {    
    case "Query":
      ret = get_web_page (get_query_project(), "Query Projects");
    break;  
    case "Domlist":
      ret = get_web_page (get_domain_project_list(args["domain"]), "Projects "
        "in the " + args["domain"] + " domain");
    break;
    case "goto":
      ret = get_web_page (get_modify_project(data["Goto"]), "Project "
        "Details");
    break;
    case "Crelist":
      ret = get_web_page (get_creator_project_list (args["creator"]), 
          "Projects for " + capitalize (args["creator"]));
      break;
    case "instructions":
      ret = get_web_page (get_instructions (args["cat"]), 
          "Project Manager instructions");
    break;
    case "Week":
      tmp = PROJECT_HANDLER->filter_by_query((["touched" : 
      (7 * 24 * 60 * 60)]));
  
      if (!sizeof (tmp)) {
        ret = get_web_page ("There are no projects that have been touched "
          "within the past week.", "Projects Updated This Week");
      }
      else {
        ret = get_web_page (parse_details (tmp), "Projects Updated This Week");    
      }
    break;     
    case "Playtesting":
      tmp = PROJECT_HANDLER->filter_by_query((["status" : 
        "playtesting"]));
  
      if (!sizeof (tmp)) {
        ret = get_web_page ("There are no projects in playtesting.", 
          "Projects In Playtesting");
      }
      else {
        ret = get_web_page (parse_details (tmp), "Projects In Playtesting");    
      }
    break;       
  }
                
  switch (data["button"]) {
    case "Add":
      ret = do_add_project (data, request->user);
    break;
    case "Add Task":
      ret = do_add_task (data, request->user);
    break;
    case "Add Note":
      ret = do_add_note (data, request->user);
    break;
    case "Add File":
      ret = do_add_file (data, request->user);
    break;
    case "Query":
      ret = get_web_page (web_query (data), "Query Completed");
    break;
    case "Update":
      ret = do_update_project (data, request->user);
    break;
    case "Update Task":
      ret = do_update_task (data, request->user);
    break;
    case "Update Note":
      ret = do_update_note (data, request->user);
    break;            
  }    
  
  if (!sizeof (ret)) {
  tmp = PROJECT_HANDLER->filter_by_query((["touched" : 
   (7 * 24 * 60 * 60)]));
  
  ret = get_web_page (parse_details (tmp), "Projects Updated This Week");

  
  }    

//  ret = "<h1>Come back later, Drakkos is breaking stuff.</h1>";
   
  return ret;
}