/* editscan.c - scan through entries in a file
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "mstring.h"
#include "terminal.h"
#include "viewfile.h"

extern int menuview_abort;


/* Find the next allowable entry, starting at "p" and adding "d" each time.
 * If "f" is nonzero then an allowable entry is one from user "u", otherwise
 * it is any entry (or any entry with a valid username if "u" is nonzero).
 *
 * Returns the line number of the datestamp of the entry, or -1 if none
 * found.
 */
long rf__se_find(rf_data_t data, long p, int f, char *u, int d)
{
	char *a;
	char *b;

	while (1) {
		p += d;

		if (p < 0)
			return (-1);
		if (p >= data->num_lines)
			return (-1);

		if (data->line_pos[p].type == MFILE_LINE_DATESTAMP) {
			if ((!f) && (!u))
				return (p);
			if ((p + 1) >= data->num_lines)
				continue;
			if (data->line_pos[p + 1].type != MFILE_LINE_FROM)
				continue;
			rf_read_line(data, p + 1);
			a = strrchr(data->linebuf, '(');
			if (!a)
				continue;
			*a = 0;
			a++;
			b = strchr(a, ':');
			if (b)
				*b = 0;
			b = strchr(a, ')');
			if (b)
				*b = 0;
			if ((!f) && (u)) {
				if (data->flags & MENU_STATUS_ANONYMOUS)
					continue;
				if (strchr(a, '*') == 0)
					return (p);
			}
			if (strcmp(a, u) != 0)
				continue;
			return (p);
		}
	}
}


/* Display index information about the currently selected entry at "pos",
 * suffixing with string "s".
 */
void rf__se_disp(rf_data_t data, long pos, char *s)
{
	struct tm *t;
	char buf[64];
	time_t n;
	char *a;
	char *b;
	char *u;
	int left;

	u = (data->flags & MENU_STATUS_ANONYMOUS) ? "*Anon*" : "*Unknown*";

	if ((!(data->flags & MENU_STATUS_ANONYMOUS))
	    && ((pos + 1) < data->num_lines)
	    && (data->line_pos[pos + 1].type == MFILE_LINE_FROM)) {
		data->linebuf[0] = 0;
		rf_read_line(data, pos + 1);
		a = strrchr(data->linebuf, '(');
		if (a) {
			*a = 0;
			a++;
			u = a;
			b = strchr(a, ':');
			if (b)
				*b = 0;
			b = strchr(a, ')');
			if (b)
				*b = 0;
			u[8] = 0;
		}
	}

	n = data->line_pos[pos].datestamp;

	if (n == 0) {
		strcpy(buf, "*Unknown*");
	} else {
		t = localtime(&n);
		strftime(buf, sizeof(buf), "%b %d %H:%M", t);
	}

	sprintf(data->tmp,
		"\035B%-12s\035b \035CG\035B(%s)\035b\035CA \"\035U", buf,
		u);

	left = t_cols - mstrlen(data->tmp) - mstrlen(s) - 14;

	data->linebuf[0] = 0;

	pos++;
	if (data->line_pos[pos].type != MFILE_LINE_DATESTAMP) {
		pos++;
		while ((pos < data->num_lines)
		       && ((data->line_pos[pos].type == MFILE_LINE_BLANK)
			   || (data->line_pos[pos].type == MFILE_LINE_TO)))
			pos++;
		rf_read_line(data, pos);
		mstripattr(data->linebuf);
	}

	if (strncmp(data->linebuf, "Subject:", 8) == 0) {
		a = data->linebuf + 9;
		while (*a == ' ')
			a++;
	} else
		a = data->linebuf;

	if ((left >= 0) && (left < strlen(a)))
		a[left] = 0;

	strcat(data->tmp, a);
	strcat(data->tmp, "\035u\"  [\035B-\035b]/[\035B+\035b]  ");
	strcat(data->tmp, s);

	rf_wipe_footer(data);
	t_goto(0, t_rows - 1);
	t_write(data->tmp);
}


/* Starting at line "*pos", allow the user to select an entry from those in
 * the file. String "s" is shown at the end of the footer line.
 *
 * If "f" is non-zero, only entries from user "u" can be selected. If "f" is
 * zero but "u" is not, only entries with a valid username can be selected.
 *
 * Returns 'Q' on exit or error, or any of the characters in the string "k"
 * if any of them were pressed. "*pos" is updated to contain the line number
 * of the datestamp line of the entry selected.
 *
 * Uses data->linebuf and data->tmp for workspace.
 */
int rf_scan_entries(rf_data_t data, long *pos, char *s, char *k, int f,
		    char *u)
{
	struct stat sb;
	int i, c;
	long p;

	if ((!pos) || (!k) || ((f) && (!u)))
		return ('Q');
	if (!s)
		s = "";

	rf_wipe_footer(data);

	p = rf__se_find(data, *pos, f, u, -1);
	if (p < 0)
		p = rf__se_find(data, *pos, f, u, 1);

	if (p < 0) {
		rf_wipe_footer(data);
		t_goto(0, t_rows - 1);
		t_centre("\035R *** No suitable entries found *** \035r");
		sleep(1);
		return ('Q');
	}

	*pos = p;
	rf_redraw = 1;

	do {

		sb.st_mtime = 0;
		fstat(data->fd, &sb);
		data->last_modified = sb.st_mtime;	/* get last-modified time */

		if (data->last_modified > data->last_scanned) {	/* file modified */
			close(data->fd);
			free(data->line_pos);

			data->fd =
			    open(data->ldb_entry->realname, O_RDONLY);

			data->line_pos = 0;
			rf_get_line_positions(data);	/* rescan line positions */
			if (*pos >= data->num_lines)
				*pos = data->num_lines - 1;
			if (*pos < 0)
				*pos = 0;
			if (data->num_lines < 1)
				return ('Q');
		}

		if (rf_redraw) {
			rf__se_disp(data, *pos, s);
			rf_redraw = 0;
		}

		c = toupper(t_getchar(1));

		if (menuview_abort)
			c = 'Q';

		switch (c) {
		case 12:
			rf_redraw = 1;
			break;
		case 0:
			break;
		case '-':
			p = rf__se_find(data, *pos, f, u, -1);
			if (p >= 0) {
				*pos = p;
				rf_redraw = 1;
			}
			break;
		case '+':
			p = rf__se_find(data, *pos, f, u, 1);
			if (p >= 0) {
				*pos = p;
				rf_redraw = 1;
			}
			break;
		default:
			for (i = 0; i < strlen(k); i++) {
				if (c == k[i])
					return (c);
			}
			break;
		}
	} while (c != 'Q');

	return ('Q');
}

/* EOF */
