#include <string.h>
#include <SDL/SDL.h>

#define WIN_X 800
#define WIN_Y 600

char getone()
{
	unsigned char c;
	static char ring[2048];
	static int prod = 0, cons = 0;
	int oldcons;
	
	if (prod == cons)
	{
		int r;
		/* Try to read some. */
		while ((r = read(0, &(ring[prod]), 2048-prod)) == 0)
			usleep(250000);
		prod = (prod + r) % 2048;
	}
	oldcons = cons;
	cons = (cons + 1) % 2048;
	return ring[oldcons];
}

char *readline()
{
	static char s[2048];
	int i = 0;
	
	while (i < 2048)
	{
		s[i] = getone();
		if (s[i] == '\r' || s[i] == '\n')
		{
			s[i] = '\0';
			return s;
		}
		i++;
	}
	s[2047] = 0;
	return s;
}

struct vars {
	char *vname, *var, *sub;
	int val;
};

int *findvar(char *var, char *sub, struct vars *vars, int n)
{
	int i;
	for (i=0; i<n; i++)
		if (!strcmp(vars[i].var, var) && ((!sub && !vars[i].sub) || !strcmp(vars[i].sub, sub)))
			return &vars[i].val;
	printf("Unknown var: %s %s\n", var, sub);
	abort();
}

void main()
{
	char *s;
	struct vars vars[512];
	int nvars = 0;
	int readingdata = 0;
	SDL_Surface *screen;
	
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		printf("SDL init failed: %s\n", SDL_GetError());
		return 1;
	}
	atexit(SDL_Quit);
	screen = SDL_SetVideoMode(WIN_X, WIN_Y, 24, SDL_SWSURFACE);
	if (!screen)
	{
		printf("Video init failed: %s\n", SDL_GetError());
	}
	
	while ((s = readline()))
	{
		if (s[0] == '$')
		{
			if (!strcmp(s, "$dumpvars"))
			{
				readingdata = 1;
				printf("Var dump begin on %d vars\n", nvars);
			} else if (!strncmp(s, "$var", 4)) {
				char *t;
				char *vname, *var, *sub;\
				t = strtok(s, " ");
				t = strtok(NULL, " ");
				t = strtok(NULL, " ");
				t = strtok(NULL, " ");
				vname = t;
				t = strtok(NULL, " ");
				var = t;
				t = strtok(NULL, " ");
				if (strcmp(t, "$end"))
					sub = t;
				else
					sub = NULL;
				printf("Found: %s -> %s %s\n", vname, var, sub);
				
				vars[nvars].vname = strdup(vname);
				vars[nvars].var = strdup(var);
				vars[nvars].sub = sub ? strdup(sub) : NULL;
				vars[nvars].val = 0;
				nvars++;
			}
		} else if (s[0] == '#' || !s[0])
			;
		else if (readingdata)
		{
			int val = (s[0] == '1');
			int i;
			int oldclk = *findvar("gclk", NULL, vars, nvars);
			static int pixn = 0;
			for (i=0; i<nvars; i++)
			{
				if (!strcmp(vars[i].vname, s+1))
				{
					vars[i].val = val;
					break;
				}
			}
			if (i == nvars)
				printf("Unknown: %s\n", s);
			if (*findvar("gclk", NULL, vars, nvars) != oldclk && oldclk == 1 && ((pixn++) % 2))
			{
				static int x = 0, y = 0;
				static int lasths;
				unsigned char *pixp;
				static int *r2 = NULL, *r1 = NULL, *r0 = NULL, *g2 = NULL, *g1 = NULL, *g0 = NULL, *b1 = NULL, *b0 = NULL, *vs = NULL, *hs = NULL;
				r2 = r2 ? r2 : findvar("red", "[2]", vars, nvars);
				r1 = r1 ? r1 : findvar("red", "[1]", vars, nvars);
				r0 = r0 ? r0 : findvar("red", "[0]", vars, nvars);
				g2 = g2 ? g2 : findvar("green", "[2]", vars, nvars);
				g1 = g1 ? g1 : findvar("green", "[1]", vars, nvars);
				g0 = g0 ? g0 : findvar("green", "[0]", vars, nvars);
				b1 = b1 ? b1 : findvar("blue", "[1]", vars, nvars);
				b0 = b0 ? b0 : findvar("blue", "[0]", vars, nvars);
				vs = vs ? vs : findvar("vs", NULL, vars, nvars);
				hs = hs ? hs : findvar("hs", NULL, vars, nvars);
				
				
				int r = *r2 << 7 | *r1 << 6 | *r0 << 5;
				int g = *g2 << 7 | *g1 << 6 | *g0 << 5;
				int b = *b1 << 7 | *b0 << 6;
				if (*vs)
					y = 0;
				else {
					if (*hs)
					{
						x = 0;
						if (!lasths)
						{
							y++;
							SDL_Flip(screen);
						}
					} else
						x++;
				}
				lasths = *hs;
				SDL_LockSurface(screen);
				pixp = screen->pixels + ((WIN_X * y + x) * 3);
				pixp[0] = b; pixp[1] = g; pixp[2] = r;
				SDL_UnlockSurface(screen);
				if ((x % 5) == 4)
					SDL_UpdateRect(screen, x/5*5, y, 5, 1);
			}
		}
	}
}
