#include "global.hh"

#include <stdio.h>
#include <stdarg.h>
#include <time.h>

#include "log.hh"
#include "main.hh"
#include "events.hh"
#include "menus.hh"
#include "windows.hh"

LogWin log_window;
SWindow *log_swindow;

int
ConfigParser::parse_log_style ()
{
	skip (".");

	/**/ if (match ("geometry")) geom (log_window.x, log_window.y, log_window.wd, log_window.ht);
	else if (match ("hitext")) log_window.hitext_color.parse ();
	else if (match ("text")) log_window.text_color.parse ();
	else if (match ("back")) log_window.back_color.parse ();
	else if (match ("font")) log_window.font.parse ();
	else
		error ("bad LogStyle command: ");
}

StringNode::StringNode (const char *ics)
{
	cs=ics;
	s=NULL;
}

StringNode::StringNode (char *is)
{
	s=is;
	cs=NULL;
}

StringNode::~StringNode ()
{
	if (s) delete s;
}

LogWin::LogWin ()
{
	first=NULL; last=NULL; stopped=0; dbg_ln=0; lines = 0;

	// default config
	hitext_color = white;
	text_color = grey;
	back_color = black;
	wd = 200; ht = 100; x = y = 0;
}

int
LogWin::init ()
{
	back_color.init ();
	
	XSetWindowAttributes at;
	at.event_mask = KeyPressMask | KeyReleaseMask
		| StructureNotifyMask | EnterWindowMask | LeaveWindowMask | ExposureMask;
	at.background_pixel = back_color.pixel;
	vm = CWEventMask | CWBackPixel;
	
	w = XCreateWindow
		(dpy, root_window, x, y, wd, ht, 0, CopyFromParent, InputOutput, CopyFromParent, vm, &at);
	
	XTextProperty name;
	char *log_name = (char *) "SWM Log";
	XStringListToTextProperty (&log_name, 1, &name);
	XSetWMName (dpy, w, &name);
	XSetWMIconName (dpy, w, &name);
	XFree ((char *) name.value);

	XLowerWindow (dpy, w);
	XMapWindow (dpy, w);

	// create gc
	font.init ();
	hitext_color.init ();
	text_color.init ();

#ifdef FONTS_XFT
	xft_draw=XftDrawCreate (dpy, w, root_visual, root_colormap);
#elif defined FONTS_XCORE
	gcm = GCForeground | GCFunction | GCFont 
	gcv.foreground = text_color.pixel;
	gcv.function = GXor;
	gcv.font = font.font->fid;
	gc = XCreateGC (dpy, root_window, gcm, &gcv);
	XSync (dpy, 0);
#endif

	lines_max = ht / font.ht;

	// print start message
	time_t ct;
	time (&ct);
	char date[100];
	strftime (date, 100, "%F", localtime (&ct));
	pr ("-- SWM started %s", date);
}

int
LogWin::handle_ConfigureNotify ()
{
#define cn event->x.xconfigure
	x = cn.x;
	y = cn.y;
	wd = cn.width;
	ht = cn.height;
	lines_max = ht / font.ht;
	while (lines > lines_max) rmfirst ();
#undef cn
}

int
LogWin::draw () // handle_Expose
{
	XClearWindow (dpy, w);

#ifdef FONTS_XCORE
	gcm = GCForeground;
	gcv.foreground = text_color.pixel;
	XChangeGC (dpy, gc, gcm, &gcv);
#endif

	StringNode *t;
	int n;
	for (n = 0, t = first; t; t = t->next, n++) {
		int xoff = font.ht/4;
		int yoff = font.ht*n;
#ifdef FONTS_XFT
		XftDrawStringUtf8 (xft_draw, (t==last ? &hitext_color.xftcolor : &text_color.xftcolor),
			font.font, xoff, font.y+yoff, (XftChar8*) t->s, strlen(t->s));
#elif defined FONTS_XCORE
		if (t == last) {
			gcm = GCForeground;
			gcv.foreground = hitext_color.pixel;
			XChangeGC (dpy, gc, gcm, &gcv);
		};

		XDrawString (dpy, w, gc, xoff, font.y + yoff, t->s, strlen (t->s));
#endif
	}
}

int
LogWin::add (StringNode *t)
{
	// add to end of list
	lines++;
	t->next = NULL;
	if (!last)
	{
		first = last = t;
	}
	else {
		last->next = t;
		last = t;
	}
	
	if (lines>lines_max) rmfirst ();
	draw ();
}

int
LogWin::rmfirst ()
{
	if (first) {
		lines--;

		StringNode *t;
		t = first;
		first = first->next;
		delete t;
		// called from pr as log_windowin::add (new something), so this is OK

		if (!first) last = NULL;
	}
}


int
LogWin::dbg (const char *tpl, ...)
{
	if (stopped) return 0;

	time_t ct;
	time (&ct);
	char date[100];
	strftime (date, 100, " %H-%M-%S", localtime (&ct));

	char *s;
	va_list ap;
	
	va_start (ap, tpl);
	int r=vasprintf (&s, tpl, ap);
	va_end (ap);

	dbg_ln++;
	if (r>0) {
		char *ds;
		if (asprintf (&ds, "%s %d) %s", date, dbg_ln, s)) {
			delete s;
			add (new StringNode(ds));
		}
		else {
			add (new StringNode(s));
		}
	}
	else {
		add (new StringNode(date));
	}
}

int
LogWin::pr (const char *tpl, ...)
{
	if (stopped) return 0;

	char *s;
	va_list ap;
	
	va_start (ap, tpl);
	int r=vasprintf (&s, tpl, ap);
	va_end (ap);

	if (r>0) add (new StringNode(s));
}

int	LogWin::stop () { stopped=1; }
int	LogWin::cont () { stopped=0; }

int
LogWin::clear ()
{
	StringNode *t;
	while (first) {
		t = first;
		first = first->next;
		delete t;
	};
	last=NULL;
	lines=0;
	dbg_ln=0;
	draw();
}

int
LogWin::done ()
{
	XftDrawDestroy (xft_draw);
	XDestroyWindow (dpy, w);
}

LogWin::~LogWin ()
{
	StringNode *t;
	while (first) {
		t = first;
		first = first->next;
		delete t;
	}
}
