/*
 * This file is part of Jehanne.
 *
 * Copyright (C) 2015 Giacomo Tesio <giacomo@tesio.it>
 *
 * Jehanne is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * Jehanne is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Jehanne.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <u.h>
#include <lib9.h>

#include "console.h"

enum {
	Black		= 0x00,
	Blue		= 0x01,
	Green		= 0x02,
	Cyan		= 0x03,
	Red		= 0x04,
	Magenta		= 0x05,
	Brown		= 0x06,
	Grey		= 0x07,

	Bright 		= 0x08,
	Blinking	= 0x80,

	kbAttr		= (Black<<4)|Grey,	/* (background<<4)|foreground */
	Cursor = (Grey<<4)|Black,
};

enum {
	Width		= 80*2,
	Height		= 25,
};

static int cgapos;
static uint8_t CGA[16384];

static void
cgaputc(uint8_t c)
{
	int i;
	uint8_t *cga, *p;

	cga = CGA;

	cga[cgapos] = ' ';
	cga[cgapos+1] = kbAttr;

	switch(c){
	case '\r':
		break;
	case '\n':
		cgapos = cgapos/Width;
		cgapos = (cgapos+1)*Width;
		break;
	case '\b':
		if(cgapos >= 2)
			cgapos -= 2;
		break;
	default:
		cga[cgapos++] = c;
		cga[cgapos++] = kbAttr;
		break;
	}

	if(cgapos >= (Width*Height)){
		memmove(cga, &cga[Width], Width*(Height-1));
		p = &cga[Width*(Height-1)];
		for(i = 0; i < Width/2; i++){
			*p++ = ' ';
			*p++ = kbAttr;
		}

		cgapos -= Width;
	}

	cga[cgapos] = ' ';
	cga[cgapos+1] = Cursor;
}

static int32_t
cgaflush(int device)
{
	int32_t w;
	Dir *dirp;

	w = 1;	/* 0 must mean eof, thus this is the default */
	if((dirp = dirfstat(device)) != nil){
		if(dirp->length == 0)
			w = pwrite(device, CGA, Width*Height, 0);
		free(dirp);
	} else {
		w = pwrite(device, CGA, Width*Height, 0);
	}
	return w;
}

/* read from conswrites, write to device */
void
writecga(int conswrites, int device)
{
	int32_t pid, r, w, i;
	static uint8_t buf[ScreenBufferSize];

	pid = getpid();

	debug("writecga %d: started\n", pid);
	do
	{
		r = read(conswrites, buf, ScreenBufferSize);
		debug("writecga %d: read(conswrites) returns %d\n", pid, r);
		for(i = 0; i < r; i++)
			cgaputc(buf[i]);
		w = cgaflush(device);
		debug("writecga %d: cgaflush(device) returns %d\n", pid, w);
	}
	while(r > 0 && w > 0);

	close(conswrites);
	debug("writecga %d: close(%d)\n", pid, conswrites);
	close(device);
	debug("writecga %d: close(%d)\n", pid, device);

	debug("writecga %d: shut down (r = %d, w = %d)\n", pid, r, w);
	if(r < 0)
		exits("writecga: read");
	if(w < 0)
		exits("writecga: write");
	exits(nil);
}
