/*
 * asapm is the APM and ACPI monitor utility for X Windows
 * Copyright (c) 1998-2005  Albert "Tigr" Dorofeev <albert@tigr.net>
 * For the updates see http://www.tigr.net/
 *
 * This software is distributed under GPL. For details see LICENSE file.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include "state.h"
#include "apm_read.h"
#include "apm_x.h"
#include "apm_react.h"
#include "apm_rc.h"
#include "safecopy.h"

struct apm_state state;

char	application_name[256];

char	apm_device_file[256];
char	acpi_device_dir[256];
char	acpi_battery_name[256];

int	force_acpi = 0;
int	force_apm = 0;

char    statuscolor[50],
        greencolor[50],
        yellowcolor[50],
        redcolor[50],
        slidercolor[50],
        sliderbgcolor[50];

/*
 * default check and update intervals in microseconds
 *      x11 events - every 1/100 th of a second
 *      apm status - every second
 */
#define X11_INTERVAL    10000L
#define APM_INTERVAL    1000000L

int     withdrawn = 0;
int     iconic = 0;
int	embossed = 1;
char    display_name[50];
char    mainGeometry[50];

/* Possible locations for resource files */
#define AFTER_SHAREDIR 	"/usr/local/share/afterstep"
#define AFTER_DIR 	"/GNUstep/Library/AfterStep"

/* This function sets the default values to global variables */
void defaults()
{
	safecopy(application_name, "asapm", 256);

	safecopy(apm_device_file, APM_PROC, 256);
	safecopy(acpi_device_dir, ACPI_PROC, 256);
	safecopy(acpi_battery_name, "", 256);

	force_acpi = 0;
	force_apm = 0;

        /* I use RoyalBlue personally, but the author might not like me */
        /* arbitrary aesthetic changes to his progam.  ;)  --Dagmar */
        /* safecopy(statuscolor, "RoyalBlue", 50); */
        safecopy(statuscolor, "LightSeaGreen", 50);
        safecopy(greencolor, "LightSeaGreen", 50);
        safecopy(yellowcolor, "#cd950a", 50);          /* DarkGold */
        /*safecopy(redcolor, "DeepPink", 50);*/
        safecopy(redcolor, "#b82030", 50);
        safecopy(slidercolor, "#303090", 50);
        safecopy(sliderbgcolor, "#b82030", 50);

        safecopy(display_name, "", 50);
        safecopy(mainGeometry, "", 50);

	memset(&state, 0, sizeof(state));
        state.x11_interval = X11_INTERVAL;
        state.apm_interval = APM_INTERVAL;
	state.ac_line_status = AC_UNKNOWN;
	state.battery_status = BATTERY_UNKNOWN;
	state.percent = -1;
	state.system_levels = 1;
	state.system_time = 1;

	state.color_depth = 0; /* use default */

	ClearReactions();
}

/* print the usage for the tool */
void usage() 
{
        printf("Usage : asapm [options ...]\n\n");
        printf("-V              print version and exit\n");
        printf("-h -H -help     print this message\n");
        printf("-name <name>    use the specified name for the window\n");
        printf("-rc <file>      use the specified resource file\n");
        printf("-u <secs>       the update interval in seconds\n");
        printf("-display <name> the name of the display to use\n");
        printf("-bpp <value>	force the color set as for 8/16 bpp screen\n");
        printf("-position <xy>  position on the screen (geometry)\n");
        printf("-withdrawn      start in withdrawn shape (for WindowMaker)\n");
        printf("-iconic         start iconized\n");
        printf("-standout       standing out rather than being pushed in\n");
	printf("-dev <device>	use the specified file as APM/ACPI device location\n");
	printf("-bat <name>	use the specified battery name (ACPI only)\n");
	printf("-acpi		force the use of ACPI only\n");
	printf("-apm		force the use of APM only\n");
	printf("-fail 		fail if cannot read the APM device\n");
        printf("-[no]syslevels  [do not] use system - defined levels for battery status\n");
        printf("-[no]systime    [calculate] or not battery life time instead of\n");
	printf("                using system values supplied by APM driver\n\n");
        printf("-status <color> to be used as the color for time and percent\n");
        printf("-green <color>  to be used as green for the labels\n");
        printf("-yellow <color> to be used as yellow for the labels\n");
        printf("-red <color>    to be used as red for the labels\n");
        printf("-lower <color>  for the indicator of battery charge left\n");
        printf("-upper <color>  for the indicator of battery charge used\n");
        printf("\n");
        exit(0);
}       

/* print the version of the tool */
void version()
{
        printf("asapm : Power Management (APM / ACPI) monitor version 3.1\n");
}               

/*
 * Parse the command line and resource files.
 * Changes the values of global variables to those
 * passed on the command line.
 * If an error occurs during parsing print
 * usage and exit.
 */
void    parsecmdline(int argc, char *argv[])
{
        char    *argument;
        int     i;
	char	*home;
	char	asapmrc_file[256];
 
	/* try to find system resource files at default locations */
	/*safecopy(asapmrc_file, AFTER_SHAREDIR, 256-6);
	strcat(asapmrc_file, "/asapm");
	ReadConfiguration(asapmrc_file);*/
	home = getenv("HOME");
	if ( home ) {
		safecopy(asapmrc_file, home, 256-10);
		strcat(asapmrc_file, "/.asapmrc");
		ReadConfiguration(asapmrc_file);
		/*safecopy(asapmrc_file, home, 256-strlen(AFTER_DIR)-6);
		strcat(asapmrc_file, AFTER_DIR);
		strcat(asapmrc_file, "/asapm");
		ReadConfiguration(asapmrc_file);*/
	} else
		printf("asapm: Warning! The $HOME environment variable is not set!\n");
#ifdef TEST
	ReadConfiguration("asapmrc");
#endif
	/*
	 * Check if there is a resource file name
	 * specified on the command line. That file
	 * overwrites any other - reset previous settings.
	 */
	for (i=1; i<argc; i++) {
		if ( !strncmp(argv[i], "-rc", 3) ) {
			if (++i >= argc)
				usage();
			defaults(); /* erase config read from other files */
			ReadConfiguration( argv[i] );
		}
	}
	/* parse the command line */
        for (i=1; i<argc; i++) {
                argument=argv[i];
                if (argument[0]=='-') {
			if ( !strncmp(argv[i], "-rc", 3) ) {
				++i;
                        } else if (!strncmp(argument,"-withdrawn",10)) {
                                withdrawn=1;
                        } else if (!strncmp(argument,"-iconic",7)) {
                                iconic=1;
                        } else if (!strncmp(argument,"-standout",9)) {
                                embossed=0;
                        } else if (!strncmp(argument,"-syslevels",10)) {
                                state.system_levels=1;
                        } else if (!strncmp(argument,"-nosyslevels",12)) {
                                state.system_levels=0;
                        } else if (!strncmp(argument,"-systime",8)) {
                                state.system_time=1;
                        } else if (!strncmp(argument,"-nosystime",10)) {
                                state.system_time=0;
                        } else if (!strncmp(argument,"-acpi",5)) {
                                force_acpi=1;
				force_apm=0;
                        } else if (!strncmp(argument,"-apm",4)) {
                                force_acpi=0;
				force_apm=1;
                        } else if (!strncmp(argument,"-dev",4)) {
                                if (++i >= argc)
                                        usage();
                                safecopy(apm_device_file, argv[i], 256);
                                safecopy(acpi_device_dir, argv[i], 256);
                        } else if (!strncmp(argument,"-bat",4)) {
                                if (++i >= argc)
                                        usage();
                                safecopy(acpi_battery_name, argv[i], 256);
                        } else if (!strncmp(argument,"-fail",5)) {
                                state.fail=1;
                        } else if (!strncmp(argument,"-position",9)) {
                                if (++i >= argc)
                                        usage();
                                safecopy(mainGeometry, argv[i], 50);
                        } else if (!strncmp(argument,"-status",7)) {
                                if (++i >= argc)
                                        usage();
                                safecopy(statuscolor, argv[i], 50);
                        } else if (!strncmp(argument,"-green",6)) {
                                if (++i >= argc)
                                        usage();
                                safecopy(greencolor, argv[i], 50);
                        } else if (!strncmp(argument,"-yellow",7)) {
                                if (++i >= argc)
                                        usage();
                                safecopy(yellowcolor, argv[i], 50);
                        } else if (!strncmp(argument,"-red",4)) {
                                if (++i >= argc)
                                        usage();
                                safecopy(redcolor, argv[i], 50);
                        } else if (!strncmp(argument,"-lower",6)) {
                                if (++i >= argc)
                                        usage();
                                safecopy(slidercolor, argv[i], 50);
                        } else if (!strncmp(argument,"-upper",6)) {
                                if (++i >= argc)
                                        usage();
                                safecopy(sliderbgcolor, argv[i], 50);
                        } else if (!strncmp(argument,"-name",5)) {
                                if (++i >= argc)
                                        usage();
                                safecopy(application_name, argv[i], 256);
                        } else if (!strncmp(argument,"-display",8)) {
                                if (++i >= argc)
                                        usage();
                                safecopy(display_name, argv[i], 50);
                        } else if (!strncmp(argument,"-bpp",4)) {
                                if (++i >= argc)
                                        usage();
                                state.color_depth = atoi(argv[i]);
                                if ( ( state.color_depth != 8 )  
				  && ( state.color_depth != 16 ) )
                                        usage();
                        } else if (!strncmp(argument,"-u",2)) {
                                if (++i >= argc)
                                        usage();
                                state.apm_interval = 1000000L * atoi(argv[i]);
                                if ( state.apm_interval < 1 )  
                                        state.apm_interval = APM_INTERVAL;
                        } else if (!strncmp(argument,"-V",2)) { 
                                version();
                                exit(0);
                        } else if (!strncmp(argument,"-H",2)) {
                                version();
                                usage();
                        } else if (!strncmp(argument,"-h",2)) {
                                version();
                                usage();
                        } else {
                                version();
                                usage();
                        }       
                } else {
                        version();
                        usage();
                }       
        }       
}

int main(int argc, char *argv[])
{
	struct timeval tp;
	struct timezone tzp;

	long old_time, new_time;

	defaults();
	parsecmdline(argc, argv);
	CheckAPMEvents( );
	if (state.error) {
		printf("asapm: critical error. Bailing out...\n");
		return 1;
	}
	/* ignore the state change flags */
	state.flags = 0;

	initializeWindow(argc, argv,
			display_name,
			mainGeometry,
                        statuscolor,
			greencolor,
			yellowcolor,
			redcolor,
			slidercolor,
			sliderbgcolor,
			application_name,
			withdrawn,
			iconic,
			embossed);
	if (state.error) {
		printf("asapm: critical error. Bailing out...\n");
		return 1;
	}
        /* Handle the X events and check the APM state in a loop */

	gettimeofday(&tp, &tzp);
	old_time = tp.tv_sec;

        while (1) {
         	gettimeofday(&tp, &tzp);
		if ( tp.tv_sec != old_time ) {
			new_time = tp.tv_sec;
			if ( abs(new_time - old_time ) >= 
					(state.apm_interval / 1000000L) ) {
				gettimeofday(&tp, &tzp);
				old_time = new_time;
				CheckAPMEvents();
			}
                }       
                
                CheckX11Events();

		if (state.update) {
			Redraw();
			state.update = 0;
			React();
		}

		if (state.error) {
			printf("asapm: critical error. Bailing out...\n");
			break;
		}
                
                usleep(state.x11_interval);
        }       
	Cleanup();
	return 0;
}



syntax highlighted by Code2HTML, v. 0.9.1