#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#include <sys/time.h>
#endif
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>

#include "merc.h"
#include "interp.h"
#include "tables.h"
#include "olc.h"
#include "lookup.h"
#include "recycle.h"

/*
 * Local functions.
 */ 
bool help_find args ((CHAR_DATA *ch, char *argument));

#define HEDIT( fun )           bool fun(CHAR_DATA *ch, char*argument)
#define EDIT_HELP(ch, help)    ( help = (HELP_DATA *) ch->desc->pEdit )

const struct olc_cmd_type hedit_table[] = {
/*    {    command        function    }, */

    {"keyword", hedit_keyword},
    {"text", hedit_text},
    {"new", hedit_new},
    {"level", hedit_level},
    {"commands", show_commands},
    {"delete", hedit_delete},
    {"list", hedit_list},
    {"show", hedit_show},
    {"?", show_help},

    {NULL, 0}
};


HEDIT (hedit_show)
{
    HELP_DATA *help;
    EDIT_HELP (ch, help);
    char buf[MSL];
        
    ch_printf(ch, "Keyword : [%s]\n\rLevel   : [%d]\n\rText    :\n\r", help->keyword, help->level);
    sprintf(buf, draw_line(ch, "{w-{W-", 0));
    send_to_char(buf, ch);
    ch_printf(ch, "%s-END-\n\r", help->text);
    sprintf(buf, draw_line(ch, "{w-{W-", 0));
    send_to_char(buf, ch);
    return FALSE;
}

HEDIT (hedit_level)
{
    HELP_DATA *help;
    int lev;

    EDIT_HELP (ch, help);

    if (IS_NULLSTR (argument) || !is_number (argument))
    {
        send_to_char ("Syntax: level [-1..MAX_LEVEL]\n\r", ch);
        return FALSE;
    }

    lev = atoi (argument);

    if (lev < -1 || lev > MAX_LEVEL)
    {
        printf_to_char (ch, "HEdit : levels are between -1 and %d inclusive.\n\r",
                        MAX_LEVEL);
        return FALSE;
    }

    help->level = lev;
    send_to_char ("Ok.\n\r", ch);
    return TRUE;
}

HEDIT (hedit_keyword)
{
    HELP_DATA *help;

    EDIT_HELP (ch, help);

    if (IS_NULLSTR (argument))
    {
        send_to_char ("Syntax: keyword [keywords]\n\r", ch);
        return FALSE;
    }

    free_string (help->keyword);
    help->keyword = str_dup (argument);

    send_to_char ("Ok.\n\r", ch);
    return TRUE;
}

HEDIT (hedit_new)
{
    char arg[MIL];
    HELP_DATA *help;
    extern HELP_DATA *help_last;

    if (IS_NULLSTR (argument))
    {
        send_to_char ("Syntax: new [name]\n\r", ch);
        return FALSE;
    }

    argument = one_argument (argument, arg);
    if (help_lookup (arg))
    {
        send_to_char ("HEdit : help exists.\n\r", ch);
        return FALSE;
    }

    help = new_help ();
    help->level = 0;
    help->keyword = str_dup (arg);
    help->text = str_dup ("");

    if (help_last)
        help_last->next = help;

    if (help_first == NULL)
        help_first = help;

    help_last = help;
    help->next = NULL;

    ch->desc->pEdit = (HELP_DATA *) help;
    ch->desc->editor = ED_HELP;

    ch_printf(ch, "\n\rCreated new help file '%s'.\n\r", help->keyword);
    return FALSE;
}

HEDIT (hedit_text)
{
    HELP_DATA *help;

    EDIT_HELP (ch, help);

    if (!IS_NULLSTR (argument))
    {
        send_to_char ("Syntax: text\n\r", ch);
        return FALSE;
    }

    string_append (ch, &help->text);

    return TRUE;
}

void hedit (CHAR_DATA * ch, char *argument)
{
    HELP_DATA *pHelp;
    char arg[MAX_INPUT_LENGTH];
    char command[MAX_INPUT_LENGTH];
    int cmd;
    
    if (ch->pcdata->security < 9)
    {
        send_to_char("Insufficent security to edit helps.\n\r", ch);
        edit_done(ch);
        return;
    }    

    smash_tilde (argument);
    strcpy (arg, argument);
    argument = one_argument (argument, command);

    EDIT_HELP (ch, pHelp);

    if (command[0] == '\0')
    {
        hedit_show (ch, argument);
        return;
    }

    if (!str_cmp (command, "done"))
    {
        edit_done (ch);
        return;
    }

    for (cmd = 0; hedit_table[cmd].name != NULL; cmd++)
    {
        if (!str_prefix (command, hedit_table[cmd].name))
        {
            if ((*hedit_table[cmd].olc_fun) (ch, argument))
                mud.helps_changed = TRUE;
            return;
        }
    }
    
    interpret (ch, arg);
    return;
}

void do_hedit( CHAR_DATA *ch, char *argument )
{
	HELP_DATA *pHelp;
	char arg1[MIL];
	char argall[MAX_INPUT_LENGTH],argone[MAX_INPUT_LENGTH];
	bool found = FALSE;

	strcpy(arg1,argument);

	/*if(!str_cmp (arg2,"new"))
	{
		if (argument[0] == '\0')
		{
			send_to_char("Syntax: hedit new [topic]\n\r",ch);
			return;
		}
        ch_printf(ch, "Passing argument to hedit_new: %s\n\r", argument);
		if (hedit_new(ch, argument) )
			ch->desc->editor = ED_HELP;
		return;
	}*/
		
	if(argument[0] != '\0')
	{
		argall[0] = '\0';
		while (argument[0] != '\0' )
		{
			argument = one_argument(argument,argone); //argone = new, argument = whatever
			if (argall[0] != '\0')
				strcat(argall," ");
			strcat(argall,argone);
		}
		for ( pHelp = help_first; pHelp != NULL; pHelp = pHelp->next )
		{
			if ( is_name( argall, pHelp->keyword ) )
			{
				ch->desc->pEdit=(void *)pHelp;
				ch->desc->editor= ED_HELP;
				found = TRUE;
                ch_printf(ch, "Now editing help '%s'.", pHelp->keyword);
				return;
			}
		}
	}

	if(!found)
	{
		argument = one_argument(arg1, arg1);

		if(!str_cmp(arg1,"new"))
		{
			if (argument[0] == '\0')
			{
				send_to_char("Syntax: hedit new [topic]\n\r",ch);
				return;
			}
			if (hedit_new(ch, argument) )
				ch->desc->editor = ED_HELP;
			return;
		}
	}

	send_to_char( "HEdit:  There is no default help to edit.\n\r", ch );
	return;
}


HEDIT (hedit_delete)
{
    HELP_DATA *pHelp, *temp;
    DESCRIPTOR_DATA *d;

    EDIT_HELP (ch, pHelp);

    //JH kick everyone off the helpfile, even the deleter
    for (d = descriptor_list; d; d = d->next)
        if (d->editor == ED_HELP && pHelp == (HELP_DATA *) d->pEdit)
            edit_done (d->character);

    if (help_first == pHelp)
        help_first = help_first->next;
    else
    {
        for (temp = help_first; temp; temp = temp->next)
            if (temp->next == pHelp)
                break;

        if (!temp)
        {
            bugf ("hedit_delete : help %s not found in help_first",
                  pHelp->keyword);
            return FALSE;
        }

        temp->next = pHelp->next;
    }

    free_help (pHelp);
    
    send_to_char ("Help file deleted.\n\r", ch);
    return TRUE;
}

HEDIT (hedit_list)
{
    char buf[MIL];
    int cnt = 0;
    HELP_DATA *pHelp;
    BUFFER *buffer;

    EDIT_HELP (ch, pHelp);

    if (!str_cmp (argument, "all"))
    {
        buffer = new_buf ();

        for (pHelp = help_first; pHelp; pHelp = pHelp->next)
        {
            sprintf (buf, "%3d. %-14.14s%s", cnt, pHelp->keyword,
                     cnt % 4 == 3 ? "\n\r" : " ");
            add_buf (buffer, buf);
            cnt++;
        }

        if (cnt % 4)
            add_buf (buffer, "\n\r");

        page_to_char (buf_string (buffer), ch);
        free_buf(buffer);
        return FALSE;
    }


    if (IS_NULLSTR (argument))
    {
        send_to_char ("Syntax: list all\n\r", ch);
        return FALSE;
    }

    return FALSE;
}


/*
    Syntax(s):
                help <letter>       - list help files that start with <letter>
                help 2.<keyword>    - find second occurance of <keyword>
                help <keyword>      - find first occurance of <keyword>, put the rest
                                      into 'related helps'.
               
                This help system either entirely lifted from Ryan Jennings'
                1stMUD or coded based on 1stMUD's do_help.

                1stMUD:
                http://sourceforge.net/projects/firstmud/
                
*/
void do_help (CHAR_DATA * ch, char *argument)
{
	HELP_DATA *pHelp;
	bool found = FALSE;
	bool list = FALSE;
	char argall[MIL], argone[MIL], argall2[MIL];
	char nohelp[MIL];
	char *ptr;
	BUFFER *buffer;
	BUFFER *related;
	int counter = 0, number, count = 0;
	char buf[MSL];

	if (argument[0] == '\0')
		argument = "summary";

	argall[0] = '\0';

    //ch_printf(ch, "argument: %s\n\r", argument);
    if (!str_prefix("find", argument))
    {
        argument = one_argument(argument, argone);
        //ch_printf(ch, "argument: %s argone: %s\n\r", argument, argone);
        help_find(ch, argument);
        return;
    }

	while (argument[0] != '\0')
	{
		argument = one_argument(argument, argone);
		if (argall[0] != '\0')
			strcat(argall, " ");
		strcat(argall, argone);
	}

	buffer = new_buf();
	related = new_buf();
	/* allows for help 2.keyword */
	number = number_argument(argall, argall2);
	strcpy(nohelp, argall2);

	for (pHelp = help_first; pHelp != NULL; pHelp = pHelp->next)
	{
		if (pHelp->level > get_trust(ch))
			continue;

		if (!is_name(argall2, pHelp->keyword))
			continue;

		if (list || (strlen(argall2) == 1))
		{
			counter++;

			sprintf(buf, "%3d) %s\n\r", counter, pHelp->keyword);
			add_buf(buffer, buf);
			list = TRUE;
			found = TRUE;
			continue;
		}

		if (found)
		{
			sprintf(buf, "%s, ", pHelp->keyword);
			add_buf(related, buf);
			continue;
		}

		if (++count == number)
		{
			add_buf(buffer, draw_line(ch, "{w-{W-", 0));
			sprintf(buf, "Help keywords: %s\n\r", pHelp->keyword);
			add_buf(buffer, buf);
			add_buf(buffer, draw_line(ch, "{w-{W-", 0));
			if (pHelp->text[0] == '.')
				add_buf(buffer, pHelp->text + 1);
			else
				add_buf(buffer, pHelp->text);
			add_buf(buffer, draw_line(ch, "{w-{W-", 0));
			found = TRUE;
		}
		else
		{
			sprintf(buf, "%s, ", pHelp->keyword);
			add_buf(related, buf);
		}
	}

	if (list)
	{
		char *text; //removed the 'const' qualifier because I don't want to rewrite free_string
		char buf[MIL];

		text = str_dup(buf_string(buffer));
		clear_buf(buffer);
		sprintf(buf, "Help files that start with the letter '%s'.\n\r",
				argall2);
		add_buf(buffer, buf);
		add_buf(buffer, draw_line(ch, "{w-{W-", 0));
		add_buf(buffer, text);
		add_buf(buffer, draw_line(ch, "{w-{W-", 0));
		sprintf(buf, "%d total help files.\n\r", counter);
		add_buf(buffer, buf);
		free_string(text);
	}
	else if (!found)
	{
	    ptr = nohelp; //changed JH 3/11/2004 11:43PM
		if (!str_prefix(ptr, "find"))
		    one_argument(ptr, argone);
		
		ch_printf(ch, "No help found for %s.  Trying a search...\n\r\n\r", ptr);
        if (!help_find(ch, ptr))
        {
    		sprintf(log_buf, "Missing Help: %s", ptr);
    		wiznet(log_buf, ch, NULL, 0, 0, 0);
		}
    	free_buf(buffer);
    	free_buf(related);
		return;
	}
	else if (related->string != NULL && related->string[0] != '\0')
	{
		related->string[strlen(related->string) - 2] = '.';
		related->string[strlen(related->string) - 1] = '\0';
		/*
		sprintf(buf, "See Also : %s\n\r%s\n\r", buf_string(related),
				draw_line(ch, "{w-{W-", 0));*/
		//JH changed above because I felt like it 6/17/2004 12:21AM
		sprintf(buf, "See Also: %s\n\r", buf_string(related));
		add_buf(buffer, buf);
	}

	page_to_char(buf_string(buffer), ch);
	free_buf(buffer);
	free_buf(related);
    return;
}

bool help_find (CHAR_DATA *ch, char *argument)
{
	bool Found = FALSE;
	HELP_DATA *pHelp;
    char buf[MSL];
    //int len, linelen = 0;
    int col = 0;
    BUFFER *buffer;
	
	if (!argument || argument[0] == '\0' || strlen(argument) < 2)
	{
	    send_to_char("Help find requires at least a 2 letter argument.\n\r", ch);
	    return FALSE;
	}	
	
    buffer = new_buf();
    sprintf(buf, "Helpfiles with '%s' contained within:\n\r", argument);
    add_buf(buffer, buf);
    add_buf(buffer, draw_line(ch,"{w-{W-", 0));
	for (pHelp = help_first; pHelp != NULL; pHelp = pHelp->next)
	{
		if (pHelp->level > get_trust(ch))
			continue;
		if (stristr(pHelp->text, argument) != NULL)
		{
		    Found = TRUE;
		    if (col++ > 2)
		    {
    		    add_buf(buffer, "\n\r");
    		    col = 0;
    		}    		
	        sprintf(buf, "%-16.16s   ", pHelp->keyword);
		    add_buf(buffer, buf);
		    continue;
		}
	}
	
	if (!Found)
        add_buf(buffer, "None.\n\r");
    else
        add_buf(buffer, "\n\r");
    
    page_to_char(buf_string(buffer), ch);
    free_buf(buffer);    
    
    return Found;
}


void do_hlookup (CHAR_DATA * ch, char *argument)
{
	HELP_DATA *pHelp;
    int cmd, wrap = 0;
    BUFFER *buf;
    char bufx[MIL];
    bool Found = FALSE;
    buf = new_buf();

    for (cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++)
    {
        //Prevent ' and . and / shitola, also prevent false postives ('reboo' vs 'reboot')
        if ((strlen(cmd_table[cmd].name) < 2) || !cmd_table[cmd].show)
            continue;

        Found = FALSE;

        for (pHelp = help_first; pHelp != NULL; pHelp = pHelp->next)
        {
            if (is_exact_name (cmd_table[cmd].name, pHelp->keyword))
            {
                Found = TRUE;
                break;
            }
        }

        if (!Found)
        {
            add_buf(buf, "{Y*");
            sprintf(bufx, "{C%-12s", cmd_table[cmd].name);
            add_buf(buf, bufx);

            if (++wrap % 6 == 0)
                add_buf(buf, "\n\r");
        }

    }

    add_buf(buf, "\n\r");
    send_to_char("Missing helpfiles for the following commands:\n\r", ch);
    send_to_char(draw_line(ch, "{g-{G-", 0), ch);
    page_to_char(buf_string(buf), ch);
    free_buf(buf);
    return;
}

void do_oldhelp (CHAR_DATA * ch, char *argument)
{
    HELP_DATA *pHelp;
    BUFFER *output;
    bool found = FALSE;
    char argall[MAX_INPUT_LENGTH], argone[MAX_INPUT_LENGTH];
    int level;

    output = new_buf ();

    if (argument[0] == '\0')
        argument = "summary";

    /* this parts handles help a b so that it returns help 'a b' */
    argall[0] = '\0';
    while (argument[0] != '\0')
    {
        argument = one_argument (argument, argone);
        if (argall[0] != '\0')
            strcat (argall, " ");
        strcat (argall, argone);
    }

    for (pHelp = help_first; pHelp != NULL; pHelp = pHelp->next)
    {
        level = (pHelp->level < 0) ? -1 * pHelp->level - 1 : pHelp->level;

        if (level > get_trust (ch))
            continue;

        if (is_name (argall, pHelp->keyword))
        {
            /* add seperator if found */
            if (found)
                add_buf (output,
                         "\n\r============================================================\n\r\n\r");
            if (pHelp->level >= 0 && str_cmp (argall, "imotd"))
            {
                add_buf (output, pHelp->keyword);
                add_buf (output, "\n\r");
            }

            /*
             * Strip leading '.' to allow initial blanks.
             */
            if (pHelp->text[0] == '.')
                add_buf (output, pHelp->text + 1);
            else
                add_buf (output, pHelp->text);
            found = TRUE;
            /* small hack :) */
            if (ch->desc != NULL && ch->desc->connected != CON_PLAYING
                && ch->desc->connected != CON_GEN_GROUPS)
                break;
        }
    }

    if (!found)
	{
        send_to_char ("No help on that word.\n\r", ch);
		/*
		 * Let's log unmet help requests so studious IMP's can improve their help files ;-)
		 * But to avoid idiots, we will check the length of the help request, and trim to
		 * a reasonable length (set it by redefining MAX_CMD_LEN in merc.h).  -- JR
		 */
		if (strlen(argall) > MAX_CMD_LEN)
		{
			argall[MAX_CMD_LEN - 1] = '\0';
			writelogf ("Excessive command length: %s requested %s.", ch, argall);
			send_to_char ("That was rude!\n\r", ch);
		}
		/* OHELPS_FILE is the "orphaned helps" files. Defined in merc.h -- JR */
		else
		{
			append_file (ch, OHELPS_FILE, argall);
		}
	}
    else
        page_to_char (buf_string (output), ch);

    free_buf (output);
}