/**
 * This is an inheritable for a document manager.  It allows the owner
 * to put a bunch of different documents into the system with a name.
 * They can then be retrieved by others.
 * @author Pinkfish
 * @started Tue Jan 15 13:25:26 PST 2002
 */
#include <move_failures.h>
#include <nroff.h>
#include <room/newspaper.h>
#include <room/document_handler.h>
#define TAG "document__h"
class document {
   string title;
   string fname;
   string added_by;
   int time_added;
   int type;
}
private mapping _documents;
private int _next_doc_id;
string query_save_dir();
void save_me();
int is_open_for(string type, string name);
void add_auto_load_value(mapping map, string tag, string name, mixed value);
mixed query_auto_load_value(mapping map, string tag, string name);
/** @ignore yes */
void create() {
   _documents = ([ ]);
}
/**
 * This method returns the file name of the specified document.
 * @param id the id of the document
 * @return the file name of the document, 0 on failure
 */
string query_document_file_name(string id) {
   if (_documents[id]) {
      return query_save_dir() + "/" + _documents[id]->fname;
   }
   return 0;
} /* query_document_file_name() */
/**
 * This method loads up the specified document from the list of
 * documents.  This returns the data off the disk directly, without any
 * processing.
 * @param id the id of the document
 * @return the document string
 */
string query_document_data(string id) {
   string fname;
   fname = query_document_file_name(id);
   if (fname) {
      return unguarded( (: read_file($(fname)) :) );
   }
   return 0;
} /* query_document_data() */
/**
 * This checks to see if the document exists in the repository.
 * @param id the id to check
 */
int is_document(string id) {
   return _documents[id] != 0;
} /* is_document() */
/**
 * This method will convert the data in the file into a readable format
 * (on the mud).
 * @param id the id of the document
 * @return the document in a readable format
 */
string query_document_readable(string id) {
   string fname;
   string text;
   fname = query_document_file_name(id);
   if (fname) {
      switch (_documents[id]->type) {
      case DOCUMENT_PLAIN :
         text = unguarded( (: read_file($(fname)) :) );
         break;
      case DOCUMENT_HTML :
         text = unguarded( (: NROFF_HAND->cat_file($(fname) + ".nroff", 1) :) );
         if (!text) {
            // Make the html output.
            text = unguarded( (: read_file( $(fname)) :) );
            if (text) {
               text = NEWSPAPER_HANDLER->convert_html(text);
               unguarded( (: write_file($(fname) + ".proc", $(text), 1) :) );
               if (unguarded( (: NROFF_HAND->create_nroff($(fname) + ".proc",
                           $(fname) + ".nroff")
:) )) {
                  text = unguarded( (: NROFF_HAND->cat_file($(fname) +
                                                            ".nroff") :) )
;
               } else {
                  text = "Unable to make nroff file.\n";
               }
            } else {
               text = "Unable to read the file, opps!\n";
            }
         }
         break;
      }
   }
   return text;
} /* query_document_readbale() */
/**
 * This method returns the text of the document in html format.
 * @param id the document id
 * @return the text of the document in html
 */
string query_document_html(string id) {
   string fname;
   string text;
   fname = query_document_file_name(id);
   if (fname) {
      switch (_documents[id]->type) {
      case DOCUMENT_PLAIN :
         text = unguarded( (: read_file($(fname)) :) );
         text = replace(fname, ({ "&", "&", "<", "<", ">", ">",
                                  " ", " ", "\n", "<br>" }) );
         break;
      case DOCUMENT_HTML :
         text = unguarded( (: read_file($(fname)) :) );
         if (!text) {
            // Make the html output.
            text = unguarded( (: read_file( $(fname)) :) );
            if (text) {
               text = NEWSPAPER_HANDLER->convert_html(text);
               unguarded( (: write_file($(fname) + ".proc", $(text), 1) :) );
               if (unguarded( (: NROFF_HAND->create_nroff($(fname) + ".proc",
                           $(fname) + ".nroff")
:) )) {
                  text = unguarded( (: NROFF_HAND->cat_file($(fname) +
                                                            ".nroff") :) )
;
               } else {
                  text = "Unable to make nroff file.\n";
               }
            } else {
               text = "Unable to read the file, opps!\n";
            }
         }
         break;
      }
   }
   return text;
} /* query_document_html() */
/**
 * This method updates the text for the specified document.
 * @param id the document id to update
 * @param text the new text for the document
 */
void update_document_text(string id, string text) {
   string fname;
   fname = query_document_file_name(id);
   if (fname) {
      unguarded( (: write_file($(fname), $(text), 1) :));
   }
} /* update_document_text() */
/** 
 * This method deletes a document from the system.
 * @param id the id of the document to delete
 */
void delete_document(string id) {
   string fname;
   fname = query_document_file_name(id);
   if (fname) {
      unguarded( (: rm($(fname) + ".proc") :));
      unguarded( (: rm($(fname) + ".nroff.o") :));
      unguarded( (: rm($(fname)) :));
      map_delete(_documents, id);
      save_me();
   }
} /* delete_document() */
/**
 * This method adds a document into the repository.
 * @param title the title of the document
 * @param text the text of the document
 * @param person the person that added the document
 * @param type the type of the document
 * @return the new id of the document
 */
string add_document(string title, string text, string person, int type) {
   class document bing;
   string id;
   id = _next_doc_id + "";
   bing = new(class document);
   bing->title = title;
   bing->added_by = person;
   bing->type = type;
   bing->time_added = time();
   bing->fname = id + ".txt";
   _next_doc_id++;
   _documents[id] = bing;
   update_document_text(id, text);
   save_me();
   return id;
} /* add_document() */
/**
 * This command lists all the documents in the current set.
 */
int do_list() {
   string ret;
   class document info;
   string id;
   if (!is_open_for("document_view", this_player()->query_name())) {
      add_failed_mess("You cannot list documents on $I.\n",
                      ({ this_object() }));
      return 0;
   }
   if (!sizeof(_documents)) {
      add_failed_mess("Cannot find any documents to list on $I.\n",
                      ({ this_object() }));
      return 0;
   }
   ret = "";
   foreach (id, info in _documents) {
      ret += "$I$3=" + id + ") " + info->title + " [" + info->added_by +
             "] - " + ctime(info->time_added)[4..9] + " " + 
             ctime(info->time_added)[<4..] + "\n";
   }
   write("$P$Documents$P$" + ret);
   add_succeeded_mess(({ "", "$N lists the documents in $I.\n" }),
                      ({ this_object() }));
   return 1;
} /* do_list() */
/**
 * This method displays one document.
 */
int do_display(string id) {
   string ret;
   class document info;
   if (!is_open_for("document_view", this_player()->query_name())) {
      add_failed_mess("You cannot view documents on $I.\n",
                      ({ this_object() }));
      return 0;
   }
   ret = query_document_readable(id);
   if (!ret) {
      add_failed_mess("Cannot find the document " + id + " on $I.\n",
                      ({ this_object() }));
      return 0;
   }
   info = _documents[id];
   ret = "Document #" + id + " " + info->title + " [" + info->added_by +
             "] - " + ctime(info->time_added)[4..9] + " " + 
             ctime(info->time_added)[<4..] + "\n" + ret;
   write("$P$Document " + id + "$P$" + ret);
   add_succeeded_mess(({ "", "$N reads a document from $I.\n" }),
                      ({ this_object() }));
   return 1;
} /* do_display() */
/**
 * This method adds in a document.
 */
int do_add_document(string title, int type) {
   if (!is_open_for("document_add", this_player()->query_name())) {
      add_failed_mess("You cannot add documents to $I.\n",
                      ({ this_object() }));
      return 0;
   }
   this_player()->do_edit("", "finish_edit", this_object(), 0,
                          ({ title, type }));
   return 1;
} /* do_add_document() */
/** @ignore yes */
void finish_edit(string str, mixed* args) {
   string title;
   int type;
   title = args[0];
   type = args[1];
   if (!str || str == "") {
      write("Abandoning adding the document.\n");
      return ;
   }
   add_document(title, str, this_player()->query_cap_name(), type);
   write("Added the document into the collection.\n");
} /* finish_edit() */
/**
 * This method deletes a document from the repository.,
 */
int do_delete_document(string id) {
   if (!is_open_for("document_delete", this_player()->query_name())) {
      add_failed_mess("You cannot delete documents from $I.\n",
                      ({ this_object() }));
      return 0;
   }
   if (!is_document(id)) {
      add_failed_mess("The document " + id + " does not exist in $I.\n",
                      ({ this_object() }));
      return 0;
   }
   delete_document(id);
   add_succeeded_mess("$N delete$s a document from $I.\n", ({ this_object() }));
   return 1;
} /* do_delete_document() */
/** @ignore yes */
mapping query_dynamic_auto_load(mapping map) {
   if (file_name(this_object()) != "/std/room/furniture/inherit/document_handler" && map) {
      add_auto_load_value(map, TAG, "documents", _documents);
      add_auto_load_value(map, TAG, "doc id", _next_doc_id);
      return map;
   }
} /* query_dynamic_auto_load() */
/** @ignore yes */
void init_dynamic_arg(mapping map) {
   if (file_name(this_object()) != "/std/room/furniture/inherit/document_handler" && map) {
      _documents = query_auto_load_value(map, TAG, "documents");
      if (!_documents) {
         _documents = ([ ]);
      }
      _next_doc_id = query_auto_load_value(map, TAG, "doc id");
   }
} /* init_dynamic_arg() */
/**
 * This is the init to call if this is used inside an object.
 */
void init_object() {
   add_command("list", "documents [from] <direct:object>", (: do_list() :));
   add_command("view", "document <string'id'> [from] <direct:object>",
                (: do_display($4[0]) :));
   add_command("add", "documents {html|plain} called <string:quoted'title'> to <direct:object>",
               (: do_add_document($4[1], ($4[0] == "html"?DOCUMENT_HTML:DOCUMENT_PLAIN)) :));
   add_command("delete", "document <string'id'> [from] <direct:object>",
                (: do_delete_document($4[0]) :));
} /* init_object() */
/**
 * This is the init to call if this is used inside a room.
 */
void init_room() {
   add_command("list", "[documents]", (: do_list() :));
   add_command("view", "[document] <string'id'>",
                (: do_display($4[0]) :));
   add_command("add", "[document] {html|plain} called <string:quoted'title'>",
               (: do_add_document($4[1], ($4[0] == "html"?DOCUMENT_HTML:DOCUMENT_PLAIN)) :));
   add_command("delete", "[document] <string'id'>",
                (: do_delete_document($4[0]) :));
} /* init_room() */