/*
 *    wmupmon - A dockapp to monitor system uptime
 *    Copyright (C) 2003  Justin Spadea <jzs@mail.rit.edu>
 *
 *    Based on work by Seiichi SATO <ssato@sh.rim.or.jp>
 *    Copyright (C) 2001,2002  Seiichi SATO <ssato@sh.rim.or.jp>
 *    AND by Mark Staggs <me@markstaggs.net>
 *    Copyright (C) 2002  Mark Staggs <me@markstaggs.net>

 *    This program 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; either version 2 of the License, or
 *    (at your option) any later version.

 *    This program 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 this program; if not, write to the Free Software
 *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#include "dockapp.h"
#include <dockapp.h>
#include "display_link.xpm"
#include "display_stats.xpm"
#include "parts.xpm"
#include "font.xpm"
#include "wmwifi.h"

#define SIZE	    58
#define WINDOWED_BG "  \tc #AEAAAE"
#define MAX_HISTORY 16
#define CPUNUM_NONE -1

typedef enum { LIGHTON, LIGHTOFF } light;
typedef enum { STANDARD, EXTENDED } interface;
Pixmap pixmap;
Pixmap fonts;
Pixmap backdrop_on;
Pixmap display_link;
Pixmap display_stats;
Pixmap backdrop_on_stats;
Pixmap display_error;
Pixmap parts;
Pixmap mask;
static char *display_name = "";
static char *light_color = NULL;	/* back-light color */
static unsigned update_interval = 1;
static light backlight = LIGHTOFF;
static interface gui = STANDARD;
static interface lgui = STANDARD;
Bool wmwifi_learn;
Bool scroll = True;
int count;
struct theme {
    char *bg;
    char *fg;
    char *hi;
    char *mt;
};
struct theme tcur;
struct theme blgt;
struct wifi lwfi;
time_t last_update = 0;
time_t last_swap = 0;
time_t now = 0;

/* prototypes */
static void update(struct wifi *wfi);
static void switch_interface(struct wifi *wfi);
static void do_theme(struct theme thm);
static void draw_junk(struct wifi *wfi);
static void draw_ext(struct wifi *wfi);
static void draw_text(char *text, int dx, int dy, Bool digit);
static void parse_arguments(int argc, char **argv);
static void print_help(char *prog);
static void copy_wifi(struct wifi *lwfi, struct wifi *wfi);
static void clear_wifi(struct wifi *wfi);
static void refresh(struct theme thm);

int main(int argc, char **argv)
{
    XEvent event;
    XButtonPressedEvent *bevent;
    int i;
    struct wifi wfi;

    wfi.ifnum = 0;

    /* Parse CommandLine */
    parse_arguments(argc, argv);

    /* Initialize Application */
    dockapp_open_window(display_name, PACKAGE, SIZE, SIZE, argc, argv);
    dockapp_set_eventmask(ButtonPressMask);

    if (backlight == LIGHTON) {
	do_theme(blgt);
    } else {
	do_theme(tcur);
    }

    /* shape window */
    if (!dockapp_iswindowed)
	dockapp_setshape(mask, 0, 0);
    if (mask)
	XFreePixmap(display, mask);

    /* pixmap : draw area */
    pixmap = dockapp_XCreatePixmap(SIZE, SIZE);

    /* Initialize pixmap */

    if (gui == STANDARD)
	dockapp_copyarea(display_link, pixmap, 0, 0, SIZE, SIZE, 0, 0);
    else
	dockapp_copyarea(display_stats, pixmap, 0, 0, SIZE, SIZE, 0, 0);

    dockapp_set_background(pixmap);
    dockapp_show();
    draw_text("link", 32, 47, False);

    /* Main loop */
    while (1) {
	if (time(NULL) != last_update)
		    update(&wfi);

	    while (XPending(display)) {
		    XNextEvent(display, &event);

		    switch (event.type) {
		    case ButtonPress:
			    bevent = (XButtonPressedEvent *) & event;
			    switch (bevent->button & 0xff) {
			    case Button1:
				    scroll = (scroll) ? False : True;
				    count = 0;
				    break;
			    case Button2:
				    next_if(&wfi);
				    break;
			    case Button3:
				    switch_interface(&wfi);
				    break;
			    }
			    break;
		    default:		/* make gcc happy */
			    break;
		    }
	    }
	    usleep(update_interval*1000000L);
    }
	return 0;
}

static void do_theme(struct theme thm)
{
    XpmColorSymbol colors[4] =
	{ {"Back0", NULL, 0}, {"Fore0", NULL, 0}, {"High0", NULL, 0},
    {"Mid0", NULL, 0}
    };
    int ncolor = 0;
    int i;

    colors[0].pixel = dockapp_getcolor(thm.bg);
    colors[1].pixel = dockapp_getcolor(thm.fg);
    colors[2].pixel = dockapp_getcolor(thm.hi);
    colors[3].pixel = dockapp_getcolor(thm.mt);
    ncolor = 4;
    /* change raw xpm data to pixmap */
    if (dockapp_iswindowed)
	display_link_xpm[1] = WINDOWED_BG;

    if (!dockapp_xpm2pixmap
	(display_link_xpm, &display_link, &mask, colors, ncolor)) {
	fprintf(stderr, "Error initializing background image.\n");
	exit(1);
    }
    if (!dockapp_xpm2pixmap
	(display_stats_xpm, &display_stats, &mask, colors, ncolor)) {
	fprintf(stderr, "Error initializing background image.\n");
	exit(1);
    }
    if (!dockapp_xpm2pixmap(parts_xpm, &parts, NULL, colors, ncolor)) {
	fprintf(stderr, "Error initializing parts image.\n");
	exit(1);
    }
    if (!dockapp_xpm2pixmap(font_xpm, &fonts, NULL, colors, ncolor)) {
	fprintf(stderr, "Error initializing fonts image.\n");
	exit(1);
    }
}

/* called by timer */
static void update(struct wifi *wfi)
{
    int sw, percent;
    extern int count;
    //char *str = calloc(1, sizeof(wfi->ifname) + sizeof(wfi->essid) + 3);
    char str[512];

	now = time(NULL);

    /* get current link level from /proc/net/wireless */
    copy_wifi(&lwfi, wfi);
    get_wifi_info(wfi);

    if (wfi->max_qual == -1) {
	tcur.bg = "rgb:ff/0/0";
	tcur.fg = "rgb:0/0/0";
	tcur.mt = "rgb:00/00/00";
	do_theme(tcur);
	dockapp_copyarea(display_link, pixmap, 0, 0, 58, 58, 0, 0);
	draw_text("ERROR", (56 / 2) - 5 * 2.5, 4, False);
    } else {
	/* all clear */

	/* If percent == 0, show backlight */
	percent = wfi->link / (wfi->max_qual / 100);
	if (percent > 0) {
	    if (backlight == LIGHTON) {
		refresh(tcur);
	    }
	    backlight = LIGHTOFF;
	} else {
	    if (backlight == LIGHTOFF) {
		refresh(blgt);
	    }
	    backlight = LIGHTON;
	}

	if (gui == STANDARD) {
	    if (gui != lgui) {
		if (backlight == LIGHTOFF)
		    refresh(tcur);
		else
		    refresh(blgt);
		lgui = gui;
	    }
	    /* draw junk */
	    draw_junk(wfi);
	} else {
	    if (gui != lgui) {
		if (backlight == LIGHTOFF)
		    refresh(tcur);
		else
		    refresh(blgt);
		lgui = gui;
	    }
	    draw_ext(wfi);
	}
	count++;
	if (scroll) {
	    dockapp_copyarea(display_link, pixmap, 0, 0, 58, 12, 0, 0);
	    snprintf(str, strlen(wfi->ifname) + strlen(wfi->essid) + 4,
		     "%s - %s", wfi->ifname, wfi->essid);
	    draw_text(str, 52 - (count * 3), 4, False);
	    dockapp_copyarea(display_link, pixmap, 0, 0, 4, 12, 0, 0);
	    dockapp_copyarea(display_link, pixmap, 55, 0, 3, 12, 55, 0);
	    if (count > (strlen(str) * 3))
		count = 1;
	} else {
		int diff = now - last_swap;
		/* swap between ifname and essid every 2 seconds */
		if (diff <= 2)
			sw = 1;
		else if ((diff > 2) && (diff <= 4))
			sw = 2;
		else
			last_swap = now;

	    switch (sw) {
	    case 1:
		dockapp_copyarea(display_link, pixmap, 0, 0, 58, 12, 0, 0);
		draw_text(wfi->ifname,
			  ((56 / 2) - (strlen(wfi->ifname) * 2)), 4,
			  False);
		dockapp_copyarea(display_link, pixmap, 0, 0, 4, 12, 0, 0);
		dockapp_copyarea(display_link, pixmap, 55, 0, 3, 12, 55,
				 0);
		break;
	    case 2:
		dockapp_copyarea(display_link, pixmap, 0, 0, 58, 12, 0, 0);
		draw_text(wfi->essid,
			  ((56 / 2) - (strlen(wfi->essid) * 2)), 4, False);
		dockapp_copyarea(display_link, pixmap, 0, 0, 4, 12, 0, 0);
		dockapp_copyarea(display_link, pixmap, 55, 0, 3, 12, 55,
				 0);
		break;
	    }
	}
	/* show */
    }
    dockapp_copy2window(pixmap);
	time(&last_update);
}
static void refresh(struct theme thm)
{
    do_theme(thm);
    switch (gui) {
    case STANDARD:
	dockapp_copyarea(display_link, pixmap, 0, 0, 58, 58, 0, 0);
	clear_wifi(&lwfi);
	draw_text("link", 32, 47, False);
	break;
    case EXTENDED:
	dockapp_copyarea(display_stats, pixmap, 0, 0, 58, 58, 0, 0);
	clear_wifi(&lwfi);
	draw_text("lnk", 37, 45, False);
	draw_text("lvl", 37, 36, False);
	draw_text("nse", 37, 27, False);
	draw_text("rte", 37, 18, False);
	break;
    }

}
static void switch_interface(struct wifi *wfi)
{
    switch (gui) {
    case STANDARD:
	lgui = gui;
	gui = EXTENDED;
	dockapp_copyarea(display_link, pixmap, 0, 0, 58, 58, 0, 0);
	draw_text("lnk", 37, 45, False);
	draw_text("lvl", 37, 36, False);
	draw_text("nse", 37, 27, False);
	draw_text("rte", 37, 18, False);
	break;
    case EXTENDED:
	lgui = gui;
	gui = STANDARD;
	dockapp_copyarea(display_stats, pixmap, 0, 0, 58, 58, 0, 0);
	draw_text("link", 32, 47, False);
	break;
    }
    dockapp_copy2window(pixmap);
}

/* called when mouse button pressed */
static void draw_ext(struct wifi *wfi)
{
    char buffer[25];
    double rate = wfi->bitrate.value;

    if (lwfi.link != wfi->link) {
	sprintf(buffer, "%.f", wfi->link);
	draw_text(buffer, 15, 45, True);
    }

    if (lwfi.level != wfi->level) {
	sprintf(buffer, "%d", wfi->level - 0x100);
	draw_text(buffer, 15, 36, True);
    }

    if ((lwfi.noise - 0x100) != (wfi->noise - 0x100)) {
	sprintf(buffer, "%d", wfi->noise - 0x100);
	draw_text(buffer, 15, 27, True);
    }

    if (lwfi.bitrate.value != wfi->bitrate.value) {
	if (rate >= GIGA) {
	    sprintf(buffer, "%.fgb", rate / GIGA);
	    draw_text(buffer, 9, 18, False);
	} else {
	    if (rate >= MEGA) {
		sprintf(buffer, "%.fmb", (rate / MEGA));
		draw_text(buffer, 9, 18, False);
	    } else {
		sprintf(buffer, "%.fkb", rate / KILO);
		draw_text(buffer, 3, 18, False);
	    }
	}
    }

}
static void draw_text(char *text, int dx, int dy, Bool digit)
{
    int ax, ay = 1, bx, len, i;
    char tmptext[255] = "";

    len = strlen(text);
    bx = 4;

    /*
       for (i = 0; i < len; i++) {
       digit = (!isalpha(text[i])) ? True : False;
       }
     */

    if (digit) {
	if (len == 4)
	    dx -= 6;
	strcat(tmptext, text);
	if (len == 3)
	    strcat(tmptext, text);
	if (len == 2) {
	    tmptext[0] = 0x20;
	    tmptext[1] = text[0];
	    tmptext[2] = text[1];
	    len++;
	}
	if (len == 1) {
	    tmptext[0] = ' ';
	    tmptext[1] = ' ';
	    tmptext[2] = text[0];
	    len += 2;
	}
    } else {
	strcpy(tmptext, text);
    }

    for (i = 0; i < len; i++) {
	if (isalpha(tmptext[i])) {
	    ax = ((tolower(tmptext[i]) - 97) * 6) + 1;
	    ay = 1;
	} else {
	    ax = ((tmptext[i] - 33) * 6) + 1;
	    ay = 10;
	}
	/* Space */
	if (tmptext[i] == 0x20)
	    ax = 79;
	/* Draw Text */
	dockapp_copyarea(fonts, pixmap, ax, ay, 6, 8, dx, dy);
	dx += 6;
    }

}

static void draw_junk(struct wifi *wfi)
{
    int num = wfi->link;
    int percent;
    int y1 = 5;
    char tmp[255];

    if (lwfi.link != wfi->link) {

	if (wfi->max_qual > -1) {
	    if (num < 0)
		num = 0;

	    /* Calculate Link percentage */
	    percent = num / (wfi->max_qual / 100);
	    num = percent;

	    /* draw digits */

	    sprintf(tmp, "%d", num);
	    draw_text(tmp, 6, 47, True);

	    dockapp_copyarea(display_link, pixmap, 10, 21, 15, 24, 10, 21);
	    dockapp_copyarea(display_link, pixmap, 37, 16, 18, 30, 37, 16);

	    if (num > 0) {
		/* Level bar 1 ( > 1 - 20%) */
		dockapp_copyarea(parts, pixmap, 70, 27, 2, 2, 37, 44);
	    }
	    if (num > 20) {
		/* Level bar 2 (18.4 - 40%) */
		dockapp_copyarea(parts, pixmap, 70, 27, 2, 2, 41, 44);
		dockapp_copyarea(parts, pixmap, 74, 22, 2, 7, 41, 37);
		/* Antenna */
		dockapp_copyarea(parts, pixmap, 2, y1, 15, 24, 10, 21);
	    }
	    if (num > 40) {
		/* Level bar 3 (36.8 - 60%) */
		dockapp_copyarea(parts, pixmap, 70, 27, 2, 2, 45, 44);
		dockapp_copyarea(parts, pixmap, 74, 22, 2, 7, 45, 37);
		dockapp_copyarea(parts, pixmap, 74, 22, 2, 7, 45, 30);
		/* Antenna */
		dockapp_copyarea(parts, pixmap, 18, y1, 15, 24, 10, 21);
	    }
	    if (num > 60) {
		dockapp_copyarea(parts, pixmap, 70, 27, 2, 2, 49, 44);
		dockapp_copyarea(parts, pixmap, 74, 22, 2, 7, 49, 37);
		dockapp_copyarea(parts, pixmap, 74, 22, 2, 7, 49, 30);
		dockapp_copyarea(parts, pixmap, 74, 22, 2, 7, 49, 23);
		/* Antenna */
		dockapp_copyarea(parts, pixmap, 34, y1, 15, 24, 10, 21);
	    }
	    if (num > 80) {
		/* Level bar 5 (73.6 - 100%) */
		dockapp_copyarea(parts, pixmap, 70, 27, 2, 2, 53, 44);
		dockapp_copyarea(parts, pixmap, 74, 22, 2, 7, 53, 37);
		dockapp_copyarea(parts, pixmap, 74, 22, 2, 7, 53, 30);
		dockapp_copyarea(parts, pixmap, 74, 22, 2, 7, 53, 23);
		dockapp_copyarea(parts, pixmap, 74, 22, 2, 7, 53, 16);
		/* Antenna */
		dockapp_copyarea(parts, pixmap, 50, y1, 15, 24, 10, 21);
	    }
	}
    }

}
static void copy_wifi(struct wifi *lwfi, struct wifi *wfi)
{
    memcpy(lwfi->ifname, wfi->ifname, 255);
    memcpy(lwfi->essid, wfi->essid, IW_ESSID_MAX_SIZE + 1);
    lwfi->ifnum = wfi->ifnum;
    lwfi->link = wfi->link;
    lwfi->level = wfi->level;
    lwfi->noise = wfi->noise;
    lwfi->bitrate.value = wfi->bitrate.value;
}
static void clear_wifi(struct wifi *wfi)
{
    //memcpy(wfi->ifname, 0, 255);
    //memcpy(wfi->essid, 0, IW_ESSID_MAX_SIZE + 1);
    wfi->ifnum = 0;
    wfi->link = (float) 0;
    wfi->level = 0;
    wfi->noise = 0 - 0x100;
    wfi->bitrate.value = 0;
}
static void parse_arguments(int argc, char **argv)
{
    int i;
    int integer;
    //dockapp_isbrokenwm = True;

    /* Default to Classic Theme */
    tcur.bg = "rgb:8e/96/8a";
    tcur.hi = "rgb:76/7c/6f";
    tcur.mt = "rgb:44/44/44";
    tcur.fg = "rgb:00/00/00";
    blgt.bg = "rgb:6E/C6/3B";
    blgt.fg = "rgb:00/00/00";
    blgt.mt = "rgb:00/00/00";
    blgt.hi = "rgb:6c/b2/37";


    for (i = 1; i < argc; i++) {
	if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h"))
	    print_help(argv[0]), exit(0);
	else if (!strcmp(argv[i], "--version") || !strcmp(argv[i], "-v"))
	    printf("%s version %s\n", PACKAGE, VERSION), exit(0);
	else if (!strcmp(argv[i], "--display") || !strcmp(argv[i], "-d")) {
	    display_name = argv[i + 1];
	    i++;
	} else if (!strcmp(argv[i], "--backlight")
		   || !strcmp(argv[i], "-bl")) {
	    backlight = LIGHTON;
	} else if (!strcmp(argv[i], "--light-color")
		   || !strcmp(argv[i], "-lc")) {
	    light_color = argv[i + 1];
	    blgt.bg = argv[i + 1];
	    i++;
	} else if (!strcmp(argv[i], "--interval")
		   || !strcmp(argv[i], "-i")) {
	    if (argc == i + 1)
		fprintf(stderr,
			"%s: error parsing argument for option %s\n",
			argv[0], argv[i]), exit(1);
	    if (sscanf(argv[i + 1], "%i", &integer) != 1)
		fprintf(stderr,
			"%s: error parsing argument for option %s\n",
			argv[0], argv[i]), exit(1);
	    if (integer < 1)
		fprintf(stderr, "%s: argument %s must be >=1\n",
			argv[0], argv[i]), exit(1);
	    update_interval = integer;
	    i++;
	} else if (!strcmp(argv[i], "--learn")
		   || !strcmp(argv[i], "-l")) {
	    wmwifi_learn = True;
	} else if (!strcmp(argv[i], "--scroll-on")
		   || !strcmp(argv[i], "+s")) {
	    scroll = True;
	} else if (!strcmp(argv[i], "--scroll-off")
		   || !strcmp(argv[i], "-s")) {
	    scroll = False;
	} else if (!strcmp(argv[i], "--windowed")
		   || !strcmp(argv[i], "-w")) {
	    dockapp_iswindowed = True;
	} else if (!strcmp(argv[i], "--theme-classic")
		   || !strcmp(argv[i], "-tc")) {
	    tcur.bg = "rgb:8e/96/8a";
	    tcur.hi = "rgb:76/7c/6f";
	    tcur.mt = "rgb:44/44/44";
	    tcur.fg = "rgb:00/00/00";
	} else if (!strcmp(argv[i], "--theme-snow")
		   || !strcmp(argv[i], "-ts")) {
	    tcur.hi = "rgb:cc/cc/cc";
	    tcur.mt = "rgb:aa/aa/aa";
	    tcur.bg = "rgb:ff/ff/ff";
	    tcur.fg = "rgb:00/00/00";
	} else if (!strcmp(argv[i], "--theme-new")
		   || !strcmp(argv[i], "-tn")) {
	    tcur.hi = "rgb:00/49/41";
	    tcur.mt = "rgb:02/7e/72";
	    tcur.bg = "rgb:20/20/20";
	    tcur.fg = "rgb:20/b2/ae";
	} else if (!strcmp(argv[i], "--hilight-color")
		   || !strcmp(argv[i], "-hi")) {
	    tcur.hi = argv[i + 1];
	    i++;
	} else if (!strcmp(argv[i], "--midtone-color")
		   || !strcmp(argv[i], "-mt")) {
	    tcur.mt = argv[i + 1];
	    i++;
	} else if (!strcmp(argv[i], "--background-color")
		   || !strcmp(argv[i], "-bg")) {
	    tcur.bg = argv[i + 1];
	    i++;
	} else if (!strcmp(argv[i], "--foreground-color")
		   || !strcmp(argv[i], "-fg")) {
	    tcur.fg = argv[i + 1];
	    i++;
	} else if (!strcmp(argv[i], "--broken-wm")
		   || !strcmp(argv[i], "-bw"))
	    dockapp_isbrokenwm = True;
	else {
	    fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0],
		    argv[i]);
	    print_help(argv[0]), exit(1);
	}
    }
}

static void print_help(char *prog)
{
    printf("Usage : %s [OPTIONS]\n", prog);
    printf("wmwifi - Wireless signal strength monitor dockapp\n");
    printf("  -d,  --display <string>        display to use\n");
    printf("  -bl, --backlight               turn on back-light\n");
    printf
	("  -lc, --light-color <string>    back-light color(rgb:6E/C6/3B is default)\n");
    printf
	("  -fg, --foreground-color <string>    foreground color(rgb:00/00/00 is default)\n");
    printf
	("  -bg, --background-color <string>    background color(rgb:8e/96/8a is default)\n");
    printf
	("  -hc, --hilight-color <string>    background highlight color(rgb:76/7c/6f is default)\n");
    printf
	("  -mt, --midtone-color <string>    midtone highlight color(rgb:44/44/44 is default)\n");
    printf
	("  -i,  --interval <number>       number of secs between updates (1 is default)\n");
    printf
	("  -h,  --help                    show this help text and exit\n");
    printf
	("  -v,  --version                 show program version and exit\n");
    printf
	("  -w,  --windowed                run the application in windowed mode\n");
    printf
	("  -bw, --broken-wm               activate broken window manager fix\n");
    printf
	("  -l, --learn                    enter learning mode (may break quality)\n");
    printf
	("  +s, --scroll-on                scroll interface name and essid\n");
    printf
	("  -s, --scroll-off               use <= 0.5 style interface and essid\n");
    printf
	("  -tc, --theme-classic           Theme: use <= 0.5 style interface theme\n");
    printf("  -ts, --theme-snow              Theme: Snow\n");
    printf("  -tn, --theme-new               Theme: New\n");
}
