/* $Id$ */
#include "bbs.h"

/*
 * more.c
 * a mini pager in 130 lines of code, or stub of the huge pager pmore.
 * Author: Hung-Te Lin (piaip), April 2008.
 *
 * Copyright (c) 2008 Hung-Te Lin <piaip@csie.ntu.edu.tw>
 * All rights reserved.
 * Distributed under BSD license (GPL compatible).
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 */

#ifdef USE_PMORE
/* use new pager: piaip's more. */
int more(const char *fpath, int promptend)
{
    int r = pmore(fpath, promptend);

    switch(r)
    {

	case RET_DOSYSOPEDIT:
	    r = FULLUPDATE;

	    if (!HasUserPerm(PERM_SYSOP) ||
		    strcmp(fpath, "etc/ve.hlp") == 0)
		break;

#ifdef BN_SECURITY
	    if (strcmp(currboard, BN_SECURITY) == 0)
		break;
#endif // BN_SECURITY

	    log_filef("log/security", LOG_CREAT,
		    "%u %s %d %s admin edit file=%s\n", 
		    (int)now, Cdate(&now), getpid(), cuser.userid, fpath);

	    veditfile(fpath);
	    break;

	case RET_SELECTBRD:
	    r = FULLUPDATE;
	    if (HasUserPerm(PERM_BASIC))
	    {
		if (currstat == READING)
		    return Select();
	    }
	    break;

	case RET_COPY2TMP:
	    r = FULLUPDATE;
	    if (HasUserPerm(PERM_BASIC))
	    {
		char buf[PATHLEN];
		getdata(b_lines - 1, 0, "��o�g�峹���J��Ȧs�ɡH[y/N] ",
			buf, 4, LCECHO);
		if (buf[0] != 'y')
		    break;
		setuserfile(buf, ask_tmpbuf(b_lines - 1));
		Copy(fpath, buf);
	    }
	    break;

	case RET_DOCHESSREPLAY:
	    r = FULLUPDATE;
	    if (HasUserPerm(PERM_BASIC))
	    {
		ChessReplayGame(fpath);
	    }
	    break;

#if defined(USE_BBSLUA) && !defined(DISABLE_BBSLUA_IN_PAGER)
	case RET_DOBBSLUA:
	    r = FULLUPDATE;
	    if (HasUserPerm(PERM_BASIC))
	    {
		bbslua(fpath);
	    } else {
		vmsg("��p�A���b���L�v������ BBS-Lua �{���C");
	    }
	    break;
#endif
    }

    return r;
}

#else  // !USE_PMORE

// minimore: a mini pager in exactly 130 lines
#define PAGER_MAXLINES (2048)
int more(const char *fpath, int promptend)
{
    FILE *fp = fopen(fpath, "rt");
    int  lineno = 0, lines = 0, oldlineno = -1;
    int  i = 0, abort = 0, showall = 0, colorize = 0;
    int  lpos[PAGER_MAXLINES] = {0}; // line position
    char buf [ANSILINELEN];

    if (!fp) return -1; 
    clear();

    if (promptend == NA) {	    // quick print one page
	for (i = 0; i < t_lines-1; i++)
	    if (!fgets(buf, sizeof(buf), fp)) 
		break; 
	    else 
		outs(buf);
	fclose(fp); 
	return 0;
    }
    // YEA mode: pre-read
    while (lines < PAGER_MAXLINES-1 && 
	   fgets(buf, sizeof(buf), fp) != NULL)
	lpos[++lines] = ftell(fp);
    rewind(fp);

    while (!abort) 
    {
	if (oldlineno != lineno)    // seek and print
	{ 
	    clear(); 
	    showall = 0; 
	    oldlineno = lineno;
	    fseek(fp, lpos[lineno], SEEK_SET);

	    for (i = 0, buf[0] = 0; i < t_lines-1; i++, buf[0] = 0) 
	    {
		if (!showall) 
		{
		    fgets(buf, sizeof(buf), fp);
		    if (lineno + i == 0 && 
			(strncmp(buf, STR_AUTHOR1, strlen(STR_AUTHOR1))==0 ||
			 strncmp(buf, STR_AUTHOR2, strlen(STR_AUTHOR2))==0))
			colorize = 1;
		}

		if (!buf[0]) 
		{
		    outs("\n");
		    showall = 1;
		} else {
		    // dirty code to render heeader
		    if (colorize && lineno+i < 4 && *buf && 
			    *buf != '\n' && strchr(buf, ':'))
		    {
			char *q1 = strchr(buf, ':');
			int    l = t_columns - 2 - strlen(buf);
			char *q2 = strstr(buf, STR_POST1);

			chomp(buf); 
			if (q2 == NULL) q2 = strstr(buf, STR_POST2);
			if (q2)	    { *(q2-1) = 0; q2 = strchr(q2, ':'); }
			else q2 = q1;

			*q1++ = 0;	*q2++ = 0; 
			if (q1 == q2)	 q2 = NULL;

			outs(ANSI_COLOR(34;47) " ");
			outs(buf); outs(" " ANSI_REVERSE); 
			outs(q1);  prints("%*s", l, ""); q1 += strlen(q1);

			if (q2) {
			    outs(ANSI_COLOR(0;34;47) " ");  outs(q1+1);
			    outs(" " ANSI_REVERSE);	    outs(q2);
			}
			outs(ANSI_RESET"\n");
		    } else 
			outs(buf);
		}
	    }
	    if (lineno + i >= lines) 
		showall = 1;

	    // print prompt bar
	    snprintf(buf, sizeof(buf),
		    "  �s�� P.%d  ", 1 + (lineno / (t_lines-2)));
	    vs_footer(buf, 
	    " (����[PgUp][PgDn][Home][End])����\t(��/q)����");
	}
	// process key
	switch(vkey()) {
	    case KEY_UP: case 'k': case Ctrl('P'):
		if (lineno == 0) abort = READ_PREV;
		lineno--;		    
		break;

	    case KEY_PGUP: case Ctrl('B'):
		if (lineno == 0) abort = READ_PREV;
		lineno -= t_lines-2;	    
		break;

	    case KEY_PGDN: case Ctrl('F'): case ' ':
	    case KEY_RIGHT:
		if (showall) abort = READ_NEXT;
		lineno += t_lines-2;	    
		break;

	    case KEY_DOWN: case 'j': case Ctrl('N'):
		if (showall) abort = READ_NEXT;
		lineno++;		    
		break;
	    case KEY_HOME: case Ctrl('A'):
		lineno = 0;		    
		break;
	    case KEY_END: case Ctrl('E'):
		lineno = lines - (t_lines-1); 
		break;
	    case KEY_LEFT: case 'q':
		abort = FULLUPDATE;		    
		break;

	    case 'b':
		abort = READ_PREV;
		break;
	    case 'f':
		abort = READ_NEXT;
		break;
	}
	if (lineno + (t_lines-1) >= lines)
	    lineno = lines-(t_lines-1);
	if (lineno < 0)
	    lineno = 0;
    }
    fclose(fp);
    return abort > 0 ? abort : 0;
}

#endif // !USE_PMORE