/* menu.c - deal with a BBS menu file stream
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <unistd.h>
#include "actions.h"
#include "mstring.h"
#include "menu.h"

void conv_text(char *, long);
void conv_html(char *, long);
void conv_html_strip(char *, long, int);
void mtrib_menu_info(menu_t *);


char *mtrib_menu_filename = 0;


/* Return a relative filename which is "file" relative to the current path
 * name.
 *
 * This is kludgy, but then again so is generating a web page from a BBS
 * file.
 */
char *menu_relativify(char *file)
{
	char *foo;
	char *bar;
	int i = 0, j = 0;

	if (!mtrib_menu_filename)
		return (file);

	foo = ldb_filename(mtrib_menu_filename);
	bar = strrchr(foo, '/');
	if (bar)
		bar[1] = 0;

	while (foo[i] == file[i])
		i++;

	ldb_lbuf[0] = 0;

	j = i;
	while (foo[j] != 0) {
		if (foo[j] == '/')
			strcat(ldb_lbuf, "../");
		j++;
	}

	strcat(ldb_lbuf, file + i);

	return (ldb_lbuf);
}


/* Add an HTML link, if appropriate, for "e" in "buf", for guests if "g" is
 * set.
 */
void mtrib_menu_htlink(menuentry_t * e, char g, char *buf)
{
	char tmp[1024];
	char *a;
	int n;

	if (e->key == 0)
		return;
	if ((g) && (e->status & MENU_STATUS_XRATED))
		return;

	a = strchr(buf, '[');
	if (!a)
		return;
	if ((a[1] == 0) || (a[2] == 0) || (a[3] == 0))
		return;
	n = a - buf;
	n += 3;

	sprintf(tmp, "<a href=\"%s.html\">", menu_relativify(e->filename));

	mstrinsert(buf, tmp, &n, 1024);
	n++;
	while ((buf[n] != ']') && (buf[n] > 32))
		n++;
	mstrinsert(buf, "</a>", &n, 1024);
}


/* Output the buffer "buf" in the format given by "out".
 */
void mtrib_menu_output(char *buf, int out)
{
	char *a;

	a = strchr(buf, 10);		    /* turn off attributes at line end */
	if (a)
		strcpy(a, "\035CA\035Ca\035a\n");

	switch (out) {
	case MT_OUTPUT_ANSI:
		mstrtoansi(buf, 1024);
		break;
	case MT_OUTPUT_TEXT:
		conv_text(buf, 1024);
		break;
	case MT_OUTPUT_HTML:
		conv_html(buf, 1024);
		break;
	}

	printf("%s", buf);

	if (out == MT_OUTPUT_ANSI)
		printf("\r");
}


/* Return a string reporting the time elapsed since "file"'s last
 * modification, given by "t".
 */
char *mtrib_menu_time(char *file, unsigned long t)
{
	if (!file)
		return ("                ");
	return (mstrsince(time(0) - t));
}


/* Output the menu entry "e" in format "out", for guests if "g" set, to a
 * screen width of "w", using the 1024-byte buffer "buf" for workspace. The
 * longest menu title is assumed to be "max" printable characters long.
 * "ldbfile" is the LDB file to use, or 0 if none.
 */
void mtrib_menu_entry(menuentry_t * e, char *ldbfile, int out, char g,
		      int w, int max, char *buf)
{
	struct stat sb;
	char a[2];
	int i, l;
	int showtime;
	char *t;

	if (e->key == 0) {		    /* centred or repeated text */
		switch (e->type) {
		case MENU_ENTRY_TEXT:	    /* centred text */
			l = (w - mstrlen(e->title)) / 2;
			for (i = 0; i < l; i++)
				buf[i] = ' ';
			buf[i] = 0;
			strcat(buf, e->title);
			strcat(buf, "\n");
			mtrib_menu_output(buf, out);
			break;
		case MENU_ENTRY_LINE:	    /* repeated text */
			buf[0] = 0;
			if ((e->title) && (strlen(e->title) > 1)) {
				while (strlen(buf) < w)
					strcat(buf, e->title);
				buf[w] = 0;
			}
			strcat(buf, "\n");
			mtrib_menu_output(buf, out);
			break;
		default:
			break;
		}
		return;
	}

	showtime = (e->type == MENU_ENTRY_ANIMATION)
	    || (e->type == MENU_ENTRY_BINARY)
	    || (e->type == MENU_ENTRY_COMMENTFILE)
	    || (e->type == MENU_ENTRY_FORMATTED)
	    || (e->type == MENU_ENTRY_READONLY)
	    || (e->type == MENU_ENTRY_UNFORMATTED)
	    || (e->type == MENU_ENTRY_VTANSI);

	if (e->status & MENU_STATUS_NOTIME)
		showtime = 0;

	if (g && (e->status & MENU_STATUS_ADD))
		e->status -= MENU_STATUS_ADD;
	if (g && (e->status & MENU_STATUS_EDIT))
		e->status -= MENU_STATUS_EDIT;
	if (g && (e->status & MENU_STATUS_DELETE))
		e->status -= MENU_STATUS_DELETE;

	switch (e->type) {
	case MENU_ENTRY_ANIMATION:
		t = "Anim";
		break;
	case MENU_ENTRY_BINARY:
		t = " Bin";
		break;
	case MENU_ENTRY_COMMENTFILE:
	case MENU_ENTRY_FORMATTED:
	case MENU_ENTRY_READONLY:
	case MENU_ENTRY_UNFORMATTED:
	case MENU_ENTRY_VTANSI:
		if (e->status & MENU_STATUS_EDIT)
			t = "Edit";
		else if (e->status & MENU_STATUS_ADD)
			t = " Add";
		else
			t = "    ";
		break;
	case MENU_ENTRY_LISTED:
	case MENU_ENTRY_MENU:
		t = "Menu";
		break;
	case MENU_ENTRY_SPOOLED:
	case MENU_ENTRY_EXECUTABLE:
		t = " Run";
		break;
	case MENU_ENTRY_TELNET:
		t = "    ";
		break;
	default:
		t = "    ";
		break;
	}

	l = w / 2;
	if (max > l)
		l = w - max;
	l -= 30;

	for (i = 0; i < l; i++)
		buf[i] = ' ';
	buf[i] = 0;

	sb.st_mtime = 0;
	i = stat(e->filename, &sb);

	if ((showtime) && (i == 0)) {
		strcat(buf, mtrib_menu_time(e->filename, sb.st_mtime));
	} else {
		strcat(buf, "                ");
	}

	strcat(buf, " ");
	strcat(buf, t);
	strcat(buf, " ");

	if (e->status & MENU_STATUS_XRATED)
		strcat(buf, "\035CR\035FX\035f\035CA");
	else
		strcat(buf, " ");

	i = menu_status(e, ldbfile, sb.st_mtime);
	if (i & MENU_ITEM_SKIP2)
		strcat(buf, "=");
	else if (i & MENU_ITEM_SKIP1)
		strcat(buf, "-");
	else
		strcat(buf, " ");

	strcat(buf, "[\035B");
	a[0] = e->key;
	a[1] = 0;
	strcat(buf, a);
	strcat(buf, "\035b] ");

	if ((e->type == MENU_ENTRY_LISTED) || (e->type == MENU_ENTRY_MENU)) {
		strcat(buf, "= ");
	} else if (i & MENU_ITEM_NOLDB)
		strcat(buf, "\035CY*\035CA ");
	else if (i & MENU_ITEM_MODIFIED)
		strcat(buf, "\035CR+\035CA ");
	else
		strcat(buf, "- ");

	strncat(buf, e->title, 1000 - strlen(buf));
	if (mstrlen(buf) > w) {
		i = mstrindex(buf, w);
		strcpy(buf + i, "\035R>\035r");
	}

	if (out == MT_OUTPUT_HTML) {
		conv_html_strip(buf, 1024, 0);
		mtrib_menu_htlink(e, g, buf);
	}

	strcat(buf, "\n");
	mtrib_menu_output(buf, out);
}


/* Process input stream "fptr" to output type "out", formatting to an output
 * width of "width" characters. "file" is the filename of the input stream,
 * and "ldbfile" is the LDB file to use (0 if none is to be used).
 *
 * Returns nonzero on error, and the error is not reported.
 */
int mtrib_menu(FILE * fptr, char *file, char *ldbfile, int out, char guest,
	       int width)
{
	menu_t *menu;
	char buf[1024];
	FILE *iptr;
	int i, l, max;
	char *a;

	if (guest) {
		putenv("MCONV_USER=guest");
		putenv("MVIEW_USER=guest");
	}

	mtrib_menu_filename = file;

	menu = menu_load(fptr, file);	    /* load menu into memory */
	if (!menu)
		return (1);

	if (menu->num_entries < 1) {	    /* no menu to display */
		menu_free(menu);
		return (0);
	}

	if (out == MT_OUTPUT_INFO) {	    /* menu information output */
		mtrib_menu_info(menu);
		menu_free(menu);
		return (0);
	}

	if (menu->title) {		    /* output menu title */
		iptr = fopen(menu->title, "r");
		if (!iptr) {
			printf("failed to open menu title file '%s'\n",
			       menu->title);
			menu_free(menu);
			return (1);
		}
		l = 0;
		while ((!feof(iptr)) && (l < 8)) {
			buf[0] = 0;
			fgets(buf, 1024, iptr);
			if (buf[0] == '#')
				continue;   /* skip if starts with # */
			mstripbs(buf);
			a = strchr(buf, '\n');
			if (a)
				*a = 0;
			if (out == MT_OUTPUT_HTML)
				conv_html_strip(buf, 1024, 0);
			if ((menu->title_type == MENU_TITLE_CENTRE)
			    && (mstrlen(buf) > 0)) {
				for (i = 0;
				     i < ((width - mstrlen(buf)) / 2); i++)
					printf(" ");
			}
			strcat(buf, "\n");
			mtrib_menu_output(buf, out);
			l++;
		}
	}

	strcpy(buf, "\035CB");
	for (i = 0; (i < width) && (strlen(buf) < (sizeof(buf) - 16)); i++)
		buf[i + 3] = '~';

	buf[i + 3] = 0;

	if (!menu->title) {		    /* add owner to ~~~~ line if no title */
		strcpy(buf + width - 1 - strlen(menu->owner), " ");
		strcat(buf, menu->owner);
		strcat(buf, " ~~");
	}

	strcat(buf, "\035CA\n");
	mtrib_menu_output(buf, out);

	max = 0;
	for (i = 0; i < menu->num_entries; i++) {
		if ((menu->menu[i].key != 0) && (menu->menu[i].title)) {
			l = mstrlen(menu->menu[i].title);
			if (l > max)
				max = l;
		}
	}

	for (i = 0; i < menu->num_entries; i++) {
		mtrib_menu_entry(&(menu->menu[i]), ldbfile, out, guest,
				 width, max, buf);
	}

	menu_free(menu);

	return (0);
}

/* EOF */
