#include "BadWM.h"
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <X11/cursorfont.h>
#include <stdio.h>

Display		*dpy;
int 		num_screens;
ScreenInfo	*screens;
ScreenInfo	*current_screen;
Client		*current = NULL;
Window		initialising = None;
XFontStruct	*font;
Client		*head_client;
Atom		xa_wm_state;
Atom		xa_wm_change_state;
Atom		xa_wm_protos;
Atom		xa_wm_delete;
Atom		xa_wm_cmapwins;
Cursor          arrow_curs;
Cursor          move_curs;
Cursor          resize_cursors[8];
const char	*opt_display = "";
const char	*opt_font = DEF_FONT;
const char	*opt_fg = DEF_FG;
const char	*opt_bg = DEF_BG;
const char	**opt_term = NULL;
const char	*opt_fc = DEF_FC;
int		vdesk = KEY_TO_VDESK(XK_1);
int		opt_snap = DEF_SNAP;
int		quitting = 0;
unsigned int numlockmask = 0;
static void *xmalloc(size_t size);

static void *xmalloc(size_t size) {
	       void *ptr = malloc(size);
	       if (!ptr) {
               exit(1);
       }
       return ptr;
}

int main(int argc, char *argv[]) {
	struct sigaction act;
	int i;
	XEvent ev;

	opt_term = (const char **)xmalloc(3 * sizeof(char *));
	opt_term[0] = DEF_TERM;
	opt_term[1] = opt_term[0];
	opt_term[2] = NULL;

	act.sa_handler = handle_signal;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	sigaction(SIGTERM, &act, NULL);
	sigaction(SIGINT, &act, NULL);
	sigaction(SIGHUP, &act, NULL);

	setup_display();

	/* main event loop here */
	for (;;) {
		XNextEvent(dpy, &ev);
		switch (ev.type) {
			case KeyPress:
				handle_key_event(&ev.xkey); break;
			case ButtonPress:
				handle_button_event(&ev.xbutton); break;
			case ConfigureRequest:
				handle_configure_request(&ev.xconfigurerequest); break;
			case MapRequest:
				handle_map_request(&ev.xmaprequest); break;
			case EnterNotify:
				handle_enter_event(&ev.xcrossing); break;
			case PropertyNotify:
				handle_property_change(&ev.xproperty); break;
			case UnmapNotify:
				handle_unmap_event(&ev.xunmap); break;
		}
	}
	return 1;
}

void setup_display() {
	XGCValues gv;
	XSetWindowAttributes attr;
	XColor dummy;
	XModifierKeymap *modmap;
	KeySym *keysym;
	KeySym keys_to_grab[] = {
		KEY_NEW, KEY_KILL, KEY_LOWER, KEY_MAX, KEY_FIX, KEY_MAXVERT,
		KEY_TOPLEFT, KEY_TOPRIGHT, KEY_BOTTOMLEFT, KEY_BOTTOMRIGHT,
		XK_1, XK_2, XK_3, XK_4, XK_5, XK_6, XK_7, XK_8, XK_9, XK_0, KEY_MAXHORIZ,
		0
	};
	/* used in scanning windows (XQueryTree) */
	unsigned int i, j, nwins;
	Window dw1, dw2, *wins;
	XWindowAttributes winattr;

	dpy = XOpenDisplay(opt_display);
	if (!dpy) { 
		exit(1);
	}
	XSetErrorHandler(handle_xerror);

	xa_wm_state = XInternAtom(dpy, "WM_STATE", False);
	xa_wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False);
	xa_wm_protos = XInternAtom(dpy, "WM_PROTOCOLS", False);
	xa_wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);

	font = XLoadQueryFont(dpy, opt_font);
	if (!font) font = XLoadQueryFont(dpy, DEF_FONT);

	arrow_curs = XCreateFontCursor(dpy, XC_top_left_arrow);
	move_curs = XCreateFontCursor(dpy, XC_fleur);

        resize_cursors[NorthWest] = XCreateFontCursor(dpy,XC_top_left_corner);
        resize_cursors[North] = XCreateFontCursor(dpy,XC_top_side);
        resize_cursors[NorthEast] = XCreateFontCursor(dpy,XC_top_right_corner);
        resize_cursors[East] = XCreateFontCursor(dpy,XC_right_side);
        resize_cursors[SouthEast] = XCreateFontCursor(dpy,XC_bottom_right_corner);
        resize_cursors[South] = XCreateFontCursor(dpy,XC_bottom_side);
        resize_cursors[SouthWest] = XCreateFontCursor(dpy,XC_bottom_left_corner);
        resize_cursors[West] = XCreateFontCursor(dpy,XC_left_side);

	/* find out which modifier is NumLock - we'll use this when grabbing
	 * every combination of modifiers we can think of */
	modmap = XGetModifierMapping(dpy);
	for (i = 0; i < 8; i++) {
		for (j = 0; j < modmap->max_keypermod; j++) {
			if (modmap->modifiermap[i*modmap->max_keypermod+j] == XKeysymToKeycode(dpy, XK_Num_Lock)) {
				numlockmask = (1<<i);
			}
		}
	}
	XFreeModifiermap(modmap);

	/* set up GC parameters - same for each screen */
	gv.function = GXinvert;
	gv.subwindow_mode = IncludeInferiors;
	gv.line_width = 1;  /* opt_bw */
	gv.font = font->fid;

	/* set up root window attributes - same for each screen */
	attr.event_mask = ChildMask | PropertyChangeMask | EnterWindowMask | LeaveWindowMask
		| ButtonMask
		;

	/* now set up each screen in turn */
	num_screens = ScreenCount(dpy);
	screens = (ScreenInfo *)xmalloc(num_screens * sizeof(ScreenInfo));
	for (i = 0; i < num_screens; i++) {
		char *ds, *colon, *dot;
		ds = DisplayString(dpy);
		/* set up DISPLAY environment variable to use */
		colon = rindex(ds, ':');
		if (colon && num_screens > 1) {
			screens[i].display = (char *)xmalloc(14 + strlen(ds));
			strcpy(screens[i].display, "DISPLAY=");
			strcat(screens[i].display, ds);
			colon = rindex(screens[i].display, ':');
			dot = index(colon, '.');
			if (!dot)
				dot = colon + strlen(colon);
			snprintf(dot, 5, ".%d", i);
		} else
			screens[i].display = NULL;

		screens[i].screen = i;
		screens[i].root = RootWindow(dpy, i);

		XAllocNamedColor(dpy, DefaultColormap(dpy, i), opt_fg, &screens[i].fg, &dummy);
		XAllocNamedColor(dpy, DefaultColormap(dpy, i), opt_bg, &screens[i].bg, &dummy);
		XAllocNamedColor(dpy, DefaultColormap(dpy, i), opt_fc, &screens[i].fc, &dummy);

		screens[i].invert_gc = XCreateGC(dpy, screens[i].root, GCFunction | GCSubwindowMode | GCLineWidth | GCFont, &gv);

		XChangeWindowAttributes(dpy, screens[i].root, CWEventMask, &attr);
		for (keysym = keys_to_grab; *keysym; keysym++) {
			grab_keysym(screens[i].root, Mod4Mask, *keysym);
		}
		grab_keysym(screens[i].root, Mod4Mask, XK_Tab);

		/* scan all the windows on this screen */
		XQueryTree(dpy, screens[i].root, &dw1, &dw2, &wins, &nwins);
		for (j = 0; j < nwins; j++) {
			XGetWindowAttributes(dpy, wins[j], &winattr);
			if (!winattr.override_redirect && winattr.map_state == IsViewable)
				make_new_client(wins[j], &screens[i]);
		}
		XFree(wins);
		XDefineCursor(dpy,screens[i].root,arrow_curs);
	}
	current_screen = find_screen(DefaultScreen(dpy));
}
