#include <stdio.h>
#include <stdlib.h>
#include "g_visu.h"
#include "v_view.h"
#include "v_extern.h"
#include MUT_H

extern int V_colors[];
extern Display *display;
extern Window T_window;
extern float scale;

void T_clearScreen();

typedef struct text_line
{
	char *line;
	int size;
} lines;

static lines *text;      /* text head pointer              */
static int top_line;     /* line where to print from       */
static int last_line;    /* last counted line              */
static int lpp;          /* lines per page                 */
static int cpp;          /* colums per page                */
static int text_pos;     /* text pos in the trace window   */

static FILE *allStream;  /* stream associated all traces   */
static FILE *outStream;  /* stream associated to stdout    */
static FILE *errStream;  /* stream associated to stderr    */
static char allFile[40]; /* stream name for traces         */
static char outFile[40]; /* stream name for new stdout     */
static char errFile[40]; /* stream name for new stderr     */

T_std()
{
	/* catches the std streams in order to get them in tracefile */
	(void)sprintf(allFile, "all_%d",getpid());
	(void)sprintf(outFile, "out_%d",getpid());
	(void)sprintf(errFile, "err_%d",getpid());
/*
	(void)sprintf(allFile, "/usr/tmp/all_%d",getpid());
	(void)sprintf(outFile, "/usr/tmp/out_%d",getpid());
	(void)sprintf(errFile, "/usr/tmp/err_%d",getpid());
*/
	allStream = fopen(allFile, "w+");
	outStream = freopen(outFile, "w+", stdout);
	errStream = freopen(errFile, "w+", stderr);
	if (outStream == NULL || errStream == NULL) {
		(void)fprintf(stderr, "Cannot open trace window for standard output\n");
		EXIT(1);
	}
	T_print("\n\n");
/*
	unlink(allFile);
	unlink(outFile);
	unlink(errFile);
*/
}

T_initText()
{
	T_std();
	(void)fseek(allStream, 0L, 0);
	top_line = last_line = text_pos = 0;
	T_print("\n");
}

T_print(str)
char *str;
{
	(void)fseek(allStream, 0L, 2);
	(void)fputs(str, allStream);
	(void)fflush(allStream);
	merge_io();
	rewind(allStream);
	/* hoops :
	   a little malloc intensive. I guess there is better way to do that. */
	last_line = T_readLine();
	T_clearScreen();
	top_line = ((last_line - lpp) < 0) ? top_line : last_line - lpp; 
	T_writeLine(top_line, top_line + lpp);
	XFlush(display);
}

T_readLine()
{
register int len, n = 1;
static int nl;
char *p, line[100];

	T_free(nl);
	nl = 0;
	text = (lines *)allouer(BUFSIZ * sizeof (lines));
	while (fgets(line, 100, allStream)) {
		len = strlen(line) + 1;
		if ((p = mbkalloc(len)) == NULL)
			exit(-1);
		line[--len] = '\0';
		(void)strcpy(p, line);
		text[nl].size = --len;
		text[nl++].line = p;
		if (nl > (n * BUFSIZ))
			text = (lines *)mbkrealloc(text, ++n * BUFSIZ * sizeof (lines));
	}
	return nl - 1;
}

void T_writeLine(first, last)
int first, last;
{
register int i;

	if (last > last_line)
		last = last_line;
	if (first > last)
		return;
	if (last <= 0) 
	 return;
	for (i = first; i <= last; i++) {
		XDrawImageString(display, T_window, C_gcText,
								2, text_pos, text[i].line, text[i].size);
		text_pos += 12;
	}
}

void T_refresh()
{
	T_clearScreen();
	T_writeLine(top_line, top_line + lpp);
}

void T_pageUp()
{
	T_clearScreen();
	if (top_line > lpp)
		top_line -= lpp;
	else
		top_line = 0;
	T_writeLine(top_line, top_line + lpp);
}

void T_pageDn()
{
	T_clearScreen();
	if (top_line + lpp < last_line)
		top_line += lpp;
	else
		top_line = last_line;
	if (top_line < 0)
		top_line = 0;
	T_writeLine(top_line, top_line + lpp);
}

void T_lineUp()
{
	T_clearScreen();
	if (top_line > 1)
		top_line --;
	else
		top_line = 0;
	T_writeLine(top_line, top_line + lpp);
}

void T_lineDn()
{
register int old;

	T_clearScreen();
	old = top_line;
	if (top_line + 1 < last_line)
		top_line ++;
	else
		top_line = last_line;
	if (top_line < 0)
		top_line = old;
	T_writeLine(top_line, top_line + lpp);
}

void T_clearScreen()
{
int dx, dy;
int forget_me;
Window w;

	text_pos = 16 + 16 + 12;
	XGetGeometry(display, T_window, &w, &forget_me, &forget_me,
			&dx, &dy, &forget_me, &forget_me);
	lpp = (long)((long)(dy - text_pos) / 12) - 1;
	cpp = (long)((long)(dx - 10) / 6) - 1;
	XFillRectangle(display, T_window, C_gcBgnd, 0, text_pos - 12, dx, dy);
}

void T_free(n)
int n;
{
register int i;

	if (!text)
		return;
	for (i = 0; i < n; i++)
		mbkfree((void *)text[i].line);
	mbkfree((void *)text);
	(void)fclose(allStream);
	text = NULL;
}

T_execute(cmd)
char *cmd;
{
char buffer[200];
int s;

	(void)sprintf(buffer, "%s", cmd); /* childs inherit the freopen ! */
	s = system(buffer);
	merge_io();
	return s;
}

static merge_io()
{
int c;

	(void)fseek(allStream, 0L, 2);
	(void)fseek(errStream, 0L, 0); /* rewind error associated stream */
	while ((c = fgetc(errStream)) != EOF)
		(void)putc(c, allStream);
	(void)fseek(outStream, 0L, 0); /* and rewind standard associated stream */
	while ((c = fgetc(outStream)) != EOF)
		(void)putc(c, allStream);
	
	(void)fclose(outStream); /* cleans up the contents */
	(void)fclose(errStream); /* of the two files       */
	outStream = freopen(outFile, "w+", stdout);
	errStream = freopen(errFile, "w+", stderr);
/*
	unlink(outFile);
	unlink(errFile);
*/
}
