#include <unistd.h>
#include <fcntl.h>
#include <morebuf.h>

extern int sc_height, sc_width;

//int any_display = 0;

static int tty = -1;
static int got_term = 0;

static int getchr()
{
    if (tty < 0) {
        // Try /dev/tty.
	// If that doesn't work, use file descriptor 2,
	// which in Unix is usually attached to the screen,
	// but also usually lets you read from the keyboard.
        tty = open("/dev/tty", 0);
        if (tty < 0)
	    tty = 2;
    }
    unsigned char ch;
    read(tty, &ch, 1);
    return ch;
}


extern "C" {
void raw_mode(int);
void get_term();
void clear_eol();
void lower_left();
void so_enter();
void so_exit();
}

static streambuf* putchr_sb;
extern "C" void putchr(int ch)
{
    putchr_sb->sputc(ch);
}


morebuf::morebuf(streambuf *b, void* jb)
{
    col = 0;
    base = b;
    jbuf = jb;
}

int morebuf::overflow(int c)
{
    if (!got_term) {
	get_term();
	got_term = 1;
	reset_lines();
    }
    if (c == EOF)
	return base->overflow(EOF);
    base->sputc(c);
    if (c == '\b')
	col--;
    else if (c == '\n') {
	col = 0; avail_lines--;
    }
    else if (c == '\t')
	col = (col + 8) & ~7;
    else col++;
    if (col >= sc_width)
	col = 0, avail_lines--;
    set_column(col);
    if (avail_lines <= 0) {
	putchr_sb = base;
	char More[] = " More: ";
	so_enter();
	base->sputn(More, 7);
	so_exit();
	base->overflow(EOF);
	raw_mode(1);
	int ch = getchr();
	raw_mode(0);
	lower_left(); clear_eol();
	switch (ch) {
	  case '\n':
	    avail_lines = 1;
	    break;
	  case ' ':
	    avail_lines = sc_height-1;
	    break;
	  case 'q': case 'Q':
	    if (jbuf)
		longjmp(jbuf, 1);
	    break;
	}
    }
    return c;
}

void morebuf::reset_lines()
{
    avail_lines = sc_height - 1;  /* Need 1 line for " More " */
    col = 0;
    set_column(0);
}
