/*
* wmacpimon v0.2.1
* (C) 2002 Costantino Pistagna (valvoline@vrlteam.org)
* wmacpimon homepage: http://www.vlrteam.org/wmacpimon
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <getopt.h>
#include <unistd.h>
#include <time.h>
#include "wmacpimon.h"
#include "master.xpm"
#include "wmgeneral/wmgeneral.c"
#include "wmgeneral/misc.h"

/* let's make life simple...and better! :) */
#define copy_xpm_area(x, y, w, h, dx, dy)				\
{									\
    XCopyArea(dockapp->display, dockapp->pixmap, dockapp->pixmap,	\
	    dockapp->gc, x, y, w, h, dx, dy);				\
    dockapp->update = 1;						\
}

Dockapp *dockapp;
ACPInfo *acpinfo;
int count = 0;			/* global timer variable */
int noisy_critical = 0;	/* ring xbell annoyingly if critical? */


static void redraw_window(int i) {
    if (dockapp->update) {
		if(i==0) {
			XCopyArea(dockapp->display, dockapp->pixmap, dockapp->iconwin, dockapp->gc, 0, 0, 64, 64, 0, 0);
			XCopyArea(dockapp->display, dockapp->pixmap, dockapp->win, dockapp->gc, 0, 0, 64, 64, 0, 0);
		}
		if(i==1) {
			XCopyArea(dockapp->display, dockapp->pixmap, dockapp->iconwin, dockapp->gc, 67, 88, 64, 64, 0, 0);
			XCopyArea(dockapp->display, dockapp->pixmap, dockapp->win, dockapp->gc, 67, 88, 64, 64, 0, 0);
		}
		dockapp->update = 0;
    }
}

static void new_window(char *name) {
    XpmAttributes attr;
    Pixel fg, bg;
    XGCValues gcval;
    XSizeHints sizehints;
    XClassHint classhint;
    XWMHints wmhints;

    dockapp->screen = DefaultScreen(dockapp->display);
    dockapp->root = DefaultRootWindow(dockapp->display);

    sizehints.flags = USSize;
    sizehints.width = 64;
    sizehints.height = 64;

    fg = BlackPixel(dockapp->display, dockapp->screen);
    bg = WhitePixel(dockapp->display, dockapp->screen);

    dockapp->win = XCreateSimpleWindow(dockapp->display, dockapp->root,
				       0, 0, sizehints.width,
				       sizehints.height, 1, fg, bg);
    dockapp->iconwin =
	XCreateSimpleWindow(dockapp->display, dockapp->win, 0, 0,
			    sizehints.width, sizehints.height, 1, fg, bg);

    XSetWMNormalHints(dockapp->display, dockapp->win, &sizehints);
    classhint.res_name = name;
    classhint.res_class = name;
    XSetClassHint(dockapp->display, dockapp->win, &classhint);

    XSelectInput(dockapp->display, dockapp->win,
		 ExposureMask | ButtonPressMask | ButtonReleaseMask |
		 StructureNotifyMask);
    XSelectInput(dockapp->display, dockapp->iconwin,
		 ExposureMask | ButtonPressMask | ButtonReleaseMask |
		 StructureNotifyMask);

    XStoreName(dockapp->display, dockapp->win, name);
    XSetIconName(dockapp->display, dockapp->win, name);

    gcval.foreground = fg;
    gcval.background = bg;
    gcval.graphics_exposures = False;

    dockapp->gc =
	XCreateGC(dockapp->display, dockapp->win,
		  GCForeground | GCBackground | GCGraphicsExposures,
		  &gcval);

    attr.exactColors = 0;
    attr.alloc_close_colors = 1;
    attr.closeness = 1L << 15;
    attr.valuemask = XpmExactColors | XpmAllocCloseColors | XpmCloseness;
    if (XpmCreatePixmapFromData(dockapp->display, dockapp->win,
				master_xpm, &dockapp->pixmap,
				&dockapp->mask, &attr) != XpmSuccess) {
	fprintf(stderr, "FATAL: Not enough colors for main pixmap!\n");
	exit(1);
    }

    /* text area is 318x7, or 53 characters long */
    /*dockapp->text = XCreatePixmap(dockapp->display, dockapp->win, 318, 7,
				  DefaultDepth(dockapp->display,
					       dockapp->screen));
    if (!dockapp->text) {
	fprintf(stderr, "FATAL: Cannot create text scroll pixmap!\n");
	exit(1);
    }*/

    XShapeCombineMask(dockapp->display, dockapp->win, ShapeBounding, 0, 0,
		      dockapp->mask, ShapeSet);
    XShapeCombineMask(dockapp->display, dockapp->iconwin, ShapeBounding, 0,
		      0, dockapp->mask, ShapeSet);

    wmhints.initial_state = WithdrawnState;
    wmhints.flags = StateHint;
    wmhints.icon_window = dockapp->iconwin;
    wmhints.icon_x = sizehints.x;
    wmhints.icon_y = sizehints.y;
    wmhints.window_group = dockapp->win;
    wmhints.flags =
	StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
    XSetWMHints(dockapp->display, dockapp->win, &wmhints);

    XMapWindow(dockapp->display, dockapp->win);
}

static int open_display(char *display) {
    dockapp->display = XOpenDisplay(display);
    if (!dockapp->display) {
		fprintf(stderr, "Unable to open display '%s'\n", display);
		return 1;
    }
    return 0;
}

static void display_temp(int percent) {
    static int op = -1, obar;
    unsigned int bar;

    if (op == percent)
	return;

    if (percent < 0)
	percent = 0;
    if (percent > 100)
	percent = 100;

    if (percent < 100) {	/* 0 - 99 */
	copy_xpm_area(95, 48, 8, 7, 37, 17);
	if (percent >= 10)
	    copy_xpm_area((percent / 10) * 6 + 67, 28, 5, 7, 40, 17);
	copy_xpm_area((percent % 10) * 6 + 67, 28, 5, 7, 46, 17);
    } else
	copy_xpm_area(95, 37, 21, 9, 37, 16);	/* 100% */
    op = percent;

    bar = percent / 1.8518;

    if (bar == obar)
	return;

    copy_xpm_area(66, 0, bar, 8, 5, 5);
    if (bar < 54)
	copy_xpm_area(66 + bar, 18, 54 - bar, 8, bar + 5, 5);
    obar = bar;
}

static void display_load(int percent) {
    static int op = -1;
	
    if (op == percent)
	return;

    if (percent < 0)
	percent = 0;
    if (percent > 100)
	percent = 100;

    if (percent < 100) {	/* 0 - 99 */
	copy_xpm_area(95, 48, 8, 7, 43, 50);
	if (percent >= 10)
	    copy_xpm_area((percent / 10) * 6 + 67, 28, 5, 7, 46, 50);
	copy_xpm_area((percent % 10) * 6 + 67, 28, 5, 7, 52, 50);
    } else
	copy_xpm_area(95, 37, 15, 9, 43, 49);	/* 100% */
    op = percent;
}
static void display_speed(char *speed) {
    int i,j,step;

	for(i=0,step=7;i<4;i++,step+=7) {
			j=speed[i];
			j-=48;
			copy_xpm_area(j * 7 + 1, 76, 6, 11, step, 32);
	}
	copy_xpm_area(72, 67, 7, 7, 35, 32);
	copy_xpm_area(42, 67, 7, 7, 42, 32);
	copy_xpm_area(150, 67, 7, 7, 49, 32);
}
static void display_capacity(int capacity) {
    int i,j,step;
	char *tmp;
	tmp = (char *)malloc(sizeof(char)*10);
	bzero(tmp, 10);
	sprintf(tmp, "%d", capacity);

	for(i=0,step=74;i<5;i++,step+=7) {
			j=tmp[i];
			j-=48;
			copy_xpm_area(j * 7 + 1, 76, 6, 11, step, 120);
	}
	copy_xpm_area(72,67,7,7,step,120);
	copy_xpm_area(132,67,7,7,step+7,120);
}
static void display_fan(void) {
	if (acpinfo->cooling == 1)
		copy_xpm_area(66, 37, 14, 9, 5, 16)
	else
		copy_xpm_area(66, 47, 14, 9, 5, 16);
}
static void display_charge(int i) {
	if (i == 0) copy_xpm_area(84, 48, 3, 3, 120, 140)
	if (i == 1) copy_xpm_area(90, 48, 3, 3, 120, 140)
	if (i == 2) copy_xpm_area(90, 52, 3, 3, 120, 140)
}

static void display_led(void) {
	if (acpinfo->state == 1)
		copy_xpm_area(81, 37, 13, 9, 19, 16)
	else
		copy_xpm_area(81, 47, 13, 9, 19, 16);
}

static void display_batt(void) {
	if (acpinfo->batt == 1) {
		copy_xpm_area(117, 37, 12, 7, 85, 105)
		copy_xpm_area(130, 47, 11, 7, 73, 105)
	}
	else {
		copy_xpm_area(117, 47, 12, 7, 85, 105);
		copy_xpm_area(130, 37, 11, 7, 73, 105)
	}
}


static void display_perc(int percent) {
    static int op = -1, obar;
    unsigned int bar;

    if (op == percent)
	return;

    if (percent < 0)
	percent = 0;
    if (percent > 100)
	percent = 100;

    if (percent < 100) {	/* 0 - 99 */
	copy_xpm_area(95, 48, 8, 7, 104, 105);
	if (percent >= 10)
	    copy_xpm_area((percent / 10) * 6 + 67, 28, 5, 7, 107, 105);
	copy_xpm_area((percent % 10) * 6 + 67, 28, 5, 7, 113, 105);
    } else
	copy_xpm_area(95, 37, 15, 9, 104, 104);	/* 100% */
    op = percent;

    bar = percent / 1.8518;

    if (bar == obar)
	return;

    copy_xpm_area(121, 0, bar, 8, 72, 93);
    if (bar < 54)
	copy_xpm_area(121 + bar, 18, 54 - bar, 8, bar + 72, 93);
    obar = bar;
}


int main(int argc, char **argv) {
    char *display = NULL;
    char ch;
    int update = 0, update2 = 0;
	int but_stat=0, min=2, max, ithrott, othrott, ibatt, obatt;
	char psave=0;
	char str[10];
	char shutdown=0;
	char *prcfile;
	FILE *fd;
	
	prcfile = (char *)malloc(sizeof(char)*128);
    dockapp = calloc(1, sizeof(Dockapp));
    acpinfo = calloc(1, sizeof(ACPInfo));
    dockapp->blink = OFF;
    init_acpinfo();
	strcpy(prcfile, ".wmacpimon.prc");
	
    /* parse command-line options */
    while ((ch = getopt(argc, argv, "pd:b:c:s:h")) != EOF) {
		switch (ch) {
			case 'c':
	    		if (optarg) {
					acpinfo->crit_level = atoi(optarg);
					if ((acpinfo->crit_level < 0) || (acpinfo->crit_level > 100)) {
		    			fprintf(stderr, "Please use values between 0 and 100%%\n");
		    			acpinfo->crit_level = 10;
		    			fprintf(stderr, "Using default value of 10%%\n");
					}
	    		}
	    	break;
			case 'b':
	    		if (optarg) strncpy(prcfile, optarg, 128);
	    	break;
			case 'd':
	    		if (optarg) display = strdup(optarg);
	    	break;
			case 'p':
	    		psave=1;
	    	break;
			case 's':
	    		if (optarg) shutdown=atoi(optarg);
	    	break;
			case 'h':
	    		printf("wmacpimon v%s (c) 2002 Costantino Pistagna (valvoline@vrlteam.org)\n"
					"usage: wmacpimon [-d] [-b] [-p] [-c] [-s]\n\n"
		   			"-d display\tdisplay on remote display <display>\n"
		   			"-b value\tprcfile for wmacpimond comunication (default: ~/.wmacpimon.prc)\n"
		  			"-p\t\tset powersave mode\n"
		  			"-c value\tset critical level (default to 10)\n"
					"-s value\tshutdown pc when battery value (percent) has reached\n"
		   			"-h\t\tdisplay this help\n\n", ver);
	    	return 0;
	    	break;
		}
	
    }

	if(!(fd = fopen(prcfile, "r"))) {
		fprintf(stderr, "wmacpimon: prcfile open error\n");
		exit(-1);
	}
	
    /* see if whatever we want to use is supported */
    if (power_init()) exit(1);

    /* open local or command-line specified display */
    if (open_display(display)) exit(1);

    /* make new dockapp window */
    new_window("wmacpimon");

	/* add mouse region */
	AddMouseRegion(1, 0, 0, 64, 64);

 	/* get/set initial statistics */
    acquire_info();
    acquire_info2();
	display_speed(acpinfo->speed);
	display_capacity(acpinfo->currcap);
	display_fan();
	display_led();
	display_batt();
	display_charge(acpinfo->charge);
	max = acpinfo->load;
	ibatt=obatt=acpinfo->batt;
	othrott=ithrott=0;
	sprintf(str, "echo -n %d:%d > %s", ibatt, ithrott, prcfile);
	system(str);

    /* main loop */
    while (1) {
		XEvent event;
		while (XPending(dockapp->display)) {
	    	XNextEvent(dockapp->display, &event);
	    	switch (event.type) {
	    		case Expose: /* update */
					dockapp->update = 1;
					while (XCheckTypedEvent(dockapp->display, Expose, &event));
					redraw_window(but_stat);
				break;
	    		case DestroyNotify:
					XCloseDisplay(dockapp->display);
					exit(0);
				break;
				case ButtonPress:
					but_stat += CheckMouseRegion(event.xbutton.x, event.xbutton.y);
					but_stat %= 2;
				break;
	    	}
		}
		if (update++ == 20) {
			acquire_info();
			if(psave==1) {
				obatt=ibatt;
				othrott=ithrott;
				if (acpinfo->batt == 0) ibatt=0;
				else ibatt=1;
				if ((acpinfo->load > max+min) || (acpinfo->load < max-min)) {
					if(acpinfo->load < 20) ithrott=4;
					if(acpinfo->load > 20 && acpinfo->load < 50) ithrott=2;
					if(acpinfo->load > 50) ithrott=0;
					max = acpinfo->load;
				}
				bzero(str, strlen(str));
				sprintf(str, "echo -n %d:%d > %s", ibatt, ithrott, prcfile);
				if(othrott != ithrott || obatt != ibatt) system(str);
			}
			update = 0;	
		}		
		if (update2++ == 90) {
	   		acquire_info2();
			if(shutdown > 0 && acpinfo->remain < shutdown) {
				sprintf(str, "echo -n HALT > %s", prcfile);
				system(str);
			}
			update2 = 0;
		}
		display_speed(acpinfo->speed);
		display_capacity(acpinfo->currcap);
		display_fan();
		display_led();
		display_batt();
		display_charge(acpinfo->charge);
		display_perc(acpinfo->remain);
		display_temp(acpinfo->percentage);
		display_load(acpinfo->load);
		redraw_window(but_stat);
		usleep(100000);
    }
    return 0;
}
