/* help.c -- commands for giving help */

#include "autoconf.h"
#include "copyright.h"
#ifndef	lint
static char RCSid[] = "$Id: help.c,v 1.8 1995/03/21 00:00:29 ambar Exp $";
USE(RCSid);
#endif

#include "interface.h"
#include "help.h"

/* Pointers to this struct is what gets stored in the help_htab's */
  struct help_entry {
      int pos;			/* Position, copied from help_indx */
      char original;		/* 1 for the longest name for a topic.
				   0 for abbreviations */
      char *key;		/* The key this is stored under. */
  };

int 
helpindex_read(htab, filename)
    HASHTAB *htab;
    char *filename;
{
    help_indx entry;
    char *p;
    int count;
    FILE *fp;
    struct help_entry *htab_entry;

/* Let's clean out our hash table, before we throw it away. */

    for (htab_entry = (struct help_entry *) hash_firstentry(htab);
	 htab_entry;
	 htab_entry = (struct help_entry *) hash_nextentry(htab)) {

	free(htab_entry->key);
	free(htab_entry);
    }

    hashflush(htab, 0);

    if ((fp = tf_fopen(filename, O_RDONLY)) == NULL) {
	STARTLOG(LOG_PROBLEMS, "HLP", "RINDX")
	    p = alloc_lbuf("helpindex_read.LOG");
	sprintf(p, "Can't open %s for reading.", filename);
	log_text(p);
	free_lbuf(p);
	ENDLOG
	    return -1;
    }
    count = 0;
    while ((fread((char *) &entry, sizeof(help_indx), 1, fp)) == 1) {

	/* Lowercase the entry and add all leftmost substrings.
	 * Substrings already added will be rejected by hashadd.
	 */
	for (p = entry.topic; *p; p++)
	    *p = ToLower(*p);

	htab_entry = (struct help_entry *) XMALLOC(sizeof(struct help_entry),
						   "helpindex_read.1");

	htab_entry->pos = entry.pos;
	htab_entry->original = 1;	/* First is the longest */
	htab_entry->key = (char *) XMALLOC(strlen(entry.topic) + 1,
					   "helpindex_read.2");
	strcpy(htab_entry->key, entry.topic);
	while (p > entry.topic) {
	    p--;
	    if (!isspace(*p)
		&& (hashadd(entry.topic, (int *) htab_entry, htab) == 0)) {
		count++;
	    } else {		/* It didn't make it into the hash table */
		free(htab_entry->key);
		free(htab_entry);
	    }
	    *p = '\0';
	    htab_entry = (struct help_entry *) XMALLOC(sizeof(struct help_entry),
						       "helpindex_read.3");

	    htab_entry->pos = entry.pos;
	    htab_entry->original = 0;
	    htab_entry->key = strsave(entry.topic);
	}
	free(htab_entry->key);
	free(htab_entry);
    }
    tf_fclose(fp);
    hashreset(htab);
    return count;
}

void 
helpindex_load(player)
    dbref player;
{
    int news, help, whelp;

    news = helpindex_read(&mudstate.news_htab, mudconf.news_indx);
    help = helpindex_read(&mudstate.help_htab, mudconf.help_indx);
    whelp = helpindex_read(&mudstate.wizhelp_htab, mudconf.whelp_indx);
    if ((player != NOTHING) && !Quiet(player))
	notify(player,
	       tprintf("Index entries: News...%d  Help...%d  Wizhelp...%d",
		       news, help, whelp));
}

void 
NDECL(helpindex_init)
{
    hashinit(&mudstate.news_htab, 17);
    hashinit(&mudstate.help_htab, 37);
    hashinit(&mudstate.wizhelp_htab, 37);
    helpindex_load(NOTHING);
}

void 
help_write(player, topic, htab, filename)
    dbref player;
    char *topic, *filename;
    HASHTAB *htab;
{
    FILE *fp;
    char *p, *line;
    int offset;
    struct help_entry *htab_entry;
    char matched;
    char *topic_list, *buffp;

    if (*topic == '\0')
	topic = (char *) "help";
    else
	for (p = topic; *p; p++)
	    *p = ToLower(*p);
    htab_entry = (struct help_entry *) hashfind(topic, htab);
    if (htab_entry)
	offset = htab_entry->pos;
    else {
	matched = 0;
	for (htab_entry = (struct help_entry *) hash_firstentry(htab);
	     htab_entry != NULL;
	     htab_entry = (struct help_entry *) hash_nextentry(htab)) {
	    if (htab_entry->original &&
		quick_wild(topic, htab_entry->key)) {
		if (matched == 0) {
		    matched = 1;
		    topic_list = alloc_lbuf("help_write");
		    buffp = topic_list;
		}
		safe_str(htab_entry->key, topic_list, &buffp);
		safe_str((char *) "  ", topic_list, &buffp);
	    }
	}
	if (matched == 0)
	    notify(player, tprintf("No entry for '%s'.", topic));
	else {
	    notify(player, tprintf("Here are the entries which match '%s':", topic));
	    *buffp = '\0';
	    notify(player, topic_list);
	    free_lbuf(topic_list);
	}
	return;
    }
    if ((fp = tf_fopen(filename, O_RDONLY)) == NULL) {
	notify(player,
	       "Sorry, that function is temporarily unavailable.");
	STARTLOG(LOG_PROBLEMS, "HLP", "OPEN")
	    line = alloc_lbuf("help_write.LOG.open");
	sprintf(line, "Can't open %s for reading.", filename);
	log_text(line);
	free_lbuf(line);
	ENDLOG
	    return;
    }
    if (fseek(fp, offset, 0) < 0L) {
	notify(player,
	       "Sorry, that function is temporarily unavailable.");
	STARTLOG(LOG_PROBLEMS, "HLP", "SEEK")
	    line = alloc_lbuf("help_write.LOG.seek");
	sprintf(line, "Seek error in file %s.", filename);
	log_text(line);
	free_lbuf(line);
	ENDLOG
	    tf_fclose(fp);
	return;
    }
    line = alloc_lbuf("help_write");
    for (;;) {
	if (fgets(line, LBUF_SIZE - 1, fp) == NULL)
	    break;
	if (line[0] == '&')
	    break;
	for (p = line; *p != '\0'; p++)
	    if (*p == '\n')
		*p = '\0';
	notify(player, line);
    }
    free_lbuf(line);
    tf_fclose(fp);
}

/* ---------------------------------------------------------------------------
 * do_help: display information from new-format news and help files
 */

void 
do_help(player, cause, key, message)
    dbref player, cause;
    int key;
    char *message;
{
    char *buf;

    switch (key) {
    case HELP_HELP:
	help_write(player, message, &mudstate.help_htab, mudconf.help_file);
	break;
    case HELP_NEWS:
	help_write(player, message, &mudstate.news_htab, mudconf.news_file);
	break;
    case HELP_WIZHELP:
	help_write(player, message, &mudstate.wizhelp_htab,
		   mudconf.whelp_file);
	break;
    default:
	STARTLOG(LOG_BUGS, "BUG", "HELP")
	    buf = alloc_mbuf("do_help.LOG");
	sprintf(buf, "Unknown help file number: %d", key);
	log_text(buf);
	free_mbuf(buf);
	ENDLOG
    }
}
