#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

#include <sys/wait.h>
#include <sys/param.h>
#include <sys/types.h>

#include <X11/Xlib.h>
#include <X11/xpm.h>
#include <X11/extensions/shape.h>

#include "../wmgeneral/wmgeneral.h"
#include "../wmgeneral/misc.h"

#include "asmon-master.xpm"
#include "asmon-mask.xbm"

#define ASMON_VERSION "0.4"
#define CHAR_WIDTH 5
#define CHAR_HEIGHT 7

#define BCHAR_WIDTH 6
#define BCHAR_HEIGHT 9

#define BOFFX   (10)
#define BOFFY   (111)
#define BREDX   (3)
#define BREDY   (111)
#define BGREENX (87)
#define BGREENY (66)

#define LITEW   (4)
#define LITEH   (4)

#define B_OFF   (0)
#define B_RED   (1)
#define B_GREEN (2)
long last_pageins=0;
long last_pageouts=0;

long last_swapins=0;
long last_swapouts=0;
float total;
int count=500;

int Xpid;

char	*ProgName;

/* functions */
void usage(void);
void printversion(void);
void asmon_routine(int, char **);
void DrawLite(int state, int dx, int dy);

int main(int argc, char *argv[]) {
	int		i;
	FILE		*fp;
	ProgName = argv[0];

	if (strlen(ProgName) >= 5)
		ProgName += (strlen(ProgName) - 5);

	for (i=1; i<argc; i++) {
		char *arg = argv[i];

		if (*arg=='-') {
			switch (arg[1]) {
			case 'd' :
				if (strcmp(arg+1, "display")) {
					usage();
					exit(1);
				}
				break;
			case 'v' :
				printversion();
				exit(0);
				break;
			default:
				usage();
				exit(0);
				break;
			}
		}
	}
	fp = fopen("/tmp/.X0-lock", "r");
	if(!fp) {
	Xpid=0;
	} else {
        fscanf(fp, " %d", &Xpid);
        fclose(fp);}
	asmon_routine(argc, argv);
	return(0);
}

void usage(void) {

	fprintf(stderr, "\nasmon - by Brad Hall (brad@eclipse.net)\n\t\tbased on Timecop's wmcpu\n\n");
	fprintf(stderr, "The top bar: left is the CPU usage, right is the load average\n");
	fprintf(stderr, "The middle bar: left memory usage devided by ticks into shared, buffers, and\n\t\t cached, respectively, and the number of megs used\n");
	fprintf(stderr, "The lower bar: the left swap usage and the number of megs swappedd avg\n");
	fprintf(stderr, "The bottom: the left is a set of LED's marking page's and swap's, the right is a bar\n\t\t representing the amount of memory that the X server is taking up,\n\t\t and the exact megs\n\n usage:\n");
	fprintf(stderr, "\t-display <display name>\n");
	fprintf(stderr, "\t-h\tthis screen\n");
	fprintf(stderr, "\t-v\tprint the version number\n");
	fprintf(stderr, "\n");
}

void printversion(void) {

	if (!strcmp(ProgName, "asmon")) {
		fprintf(stderr, "%s\n", ASMON_VERSION);
	}
}

int uptime()
{
	FILE *fp;
	float fupt;
	if( (fp = fopen("/proc/uptime", "r")) != NULL)
		fscanf(fp, "%f",&fupt);
	fclose(fp);
	return fupt;
}

void asmon_routine(int argc, char **argv)
{
	/* /proc/stat   kernel/system statistics
	cpu  3357 0 4313 1362393
	The number of jiffies (1/100ths of a second)
	that the system spent in user mode, user
	mode with low priority (nice), system mode,
	and the idle task, respectively.  The last
	value should be 100 times the second entry
	in the uptime pseudo-file. */

	static float cpustat[4];   /* remember the statistics read last time */
	int		xpm_X = 0, xpm_Y = 0,i;
	XEvent	Event;
	FILE		*fp;
	char		str[32];
	float info[4],ftmp, ratio;
	long old_Xsize=-1;
	long Xsize=0;
	int upt,days=0,hours=0,mins=0;
	int old_mins=-1,old_hours=-1;

   char buf[1024], XFileName[256];
    long pageins=0;
    long pageouts=0;
    long swapins=0;
    long swapouts=0;



	/* Open 64x64 window */
	openXwindow(argc, argv, asmon_master_xpm, asmon_mask_bits, asmon_mask_width, asmon_mask_height);

	while(1) {

		if( (fp = fopen("/proc/stat", "r")) != NULL)
		{
			long int CPUuser,CPUnice,CPUsyst;
			fscanf(fp, "%s %f %f %f %f", str, info, info+1, info+2, info+3);

			if(cpustat[0] != 0)
			{
				float fields[4], total = 0.0;
				for(i = 0; i < 4; i++)
				{ fields[i] = info[i] - cpustat[i]; total += fields[i]; }
				if(total > 0)
				{
					CPUuser=(fields[0]*100)/80;
					CPUnice=(fields[1]*100)/80;
					CPUsyst=(fields[2]*100)/80;
					total = CPUuser + CPUnice + CPUsyst;
					if ( total > 26 ) total = 26;
					copyXPMArea(3,84,total,9,5,5);
					copyXPMArea(3,102,(26-(CPUuser+CPUnice+CPUsyst)),9,5+CPUuser+CPUnice+CPUsyst,5);

					
		copyXPMArea(16,46,2,14,32,2);
				}
			}
		for(i=0; i < 4; i++) cpustat[i] = info[i];
		fclose(fp);
		}




	/* /proc/loadavg
	The load average numbers give the number of jobs in
	the run queue averaged over 1, 5 and 15 minutes.
	They are the same as the load average numbers given
	by uptime(1) and other programs. */

	if( (fp = fopen("/proc/loadavg", "r")) != NULL)
	{
      int tempy, tempa;
		static float oldv = 0.0;

		fscanf(fp, "%f", &ftmp);
		if(oldv != ftmp)
		{
			oldv = ftmp;
			i=ftmp*26;
			tempa=ftmp*100;
			tempy=tempa%10;
			copyXPMArea(3+(tempy*6),66,6,9,50,5);
			tempy=tempa/10;
			tempy=tempy%10;
			copyXPMArea(3+(tempy*6),66,6,9,44,5);
			copyXPMArea(65,66,3,9,41,5);
			tempy=tempa/100;
			copyXPMArea(3+(tempy*6),66,6,9,34,5); 
		}
		fclose(fp);
	}
	/* /proc/meminfo
	This is used by free(1) to report the amount of
	free and used memory (both physical and swap) on
	the system as well as the shared memory and buffers
	used by the kernel. */

	if( (fp = fopen("/proc/meminfo", "r")) != NULL)
	{
		static float stotal=0.0, suser=0.0, sshared=0.0, sbuffers=0.0;
		char junk[512];
		float used, freeM, shared, buffers, cached;
		long int MEMshar,MEMbuff,MEMcach;
		float user;

		int tempy, tempa;

		long int MEMswap, swaptotal, swapused, swapfreeM;

		fgets(junk, 500, fp);
		fscanf(fp, "Mem: %f %f %f %f %f %f\nSwap: %ld %ld %ld",  &total, &used, &freeM, &shared, &buffers, &cached, &swaptotal, &swapused, &swapfreeM);
		user = total - freeM - shared - buffers;
		if(user < 0.0)
		{
			user = 0.0;
			buffers = total - freeM - shared;
		}
		if(stotal != total || suser != user || sshared != shared || sbuffers != buffers)
		{
			stotal = total; suser = user; sshared = shared; sbuffers = buffers;
			if ( (total/101048576) >= 1) {
			MEMshar=(shared/total)*27;
			MEMbuff=(buffers/total)*27;
			MEMcach=(cached/total)*27;
			} else {
			MEMshar=(shared/total)*35;
			MEMbuff=(buffers/total)*35;
			MEMcach=(cached/total)*35;
			}
			copyXPMArea(3,75,((used/total)*35),9,5,19);
			copyXPMArea(3,102,1,9,5+MEMshar,19);
			copyXPMArea(3,102,1,9,7+MEMshar+MEMbuff,19);
			copyXPMArea(3,102,(30-((used/total)*35)),9,((used/total)*35),19);

			tempa=used/1048576;
			tempy=tempa%10;
    			copyXPMArea(3+(tempy*6),66,6,9,50,19);
			tempy=tempa/10;
			copyXPMArea(3+(tempy*6),66,6,9,44,19);
			tempy=tempa/100;
			if ( tempy != 0 ) {
			    copyXPMArea(3+(tempy*6),66,6,9,38,19);
			copyXPMArea(16,46,2,14,35,16);  }
			else {
			copyXPMArea(16,46,2,14,41,16); } 
		}
		/* SWAP Meter */
		if ( (total/101048576) >= 1) 
		    MEMswap=(swapused*31)/swaptotal;
		else MEMswap=(swapused*36)/swaptotal;
		copyXPMArea(3,75,MEMswap,9,5,33);
		copyXPMArea(3,102,(54-(MEMswap)),9,5+MEMswap,33);

    		tempa=swapused/1048576;
		tempy=tempa%10;
		copyXPMArea(3+(tempy*6),66,6,9,50,33);
		tempy=tempa/10;
		copyXPMArea(3+(tempy*6),66,6,9,44,33);
		tempy=tempa/100;
		if ( tempy != 0 ) {
		    copyXPMArea(3+(tempy*6),66,6,9,38,33);
		    copyXPMArea(16,46,2,14,42,16); }
		else {
    		copyXPMArea(16,46,2,14,41,30); }
		
		fclose(fp);
	}

count++;
if (count > 10) {
    count = 0;

if (Xpid == 0) {
   upt=uptime();
   mins=(upt/60)%60;
   hours=(upt/3600)%24;
   days=(upt/86400);
   if(old_hours!=hours)
      {
	 printf("%03d:%02d:",days,hours);
	 old_hours=hours;
      }
   if(old_mins!=mins)
      {
      int tempy;
	old_mins=mins;
	tempy=mins%10;
	copyXPMArea(3+(tempy*6),66,6,9,50,48);
	tempy=mins/10;
	copyXPMArea(3+(tempy*6),66,6,9,44,48);
	copyXPMArea(63,66,3,9,41,48);
	tempy=hours%10;
	copyXPMArea(3+(tempy*6),66,6,9,34,48);
	tempy=hours/10;
	copyXPMArea(3+(tempy*6),66,6,9,28,48);
	copyXPMArea(63,66,3,9,25,48);
	tempy=days%10;
	copyXPMArea(3+(tempy*6),66,6,9,18,48); 
      }
} else {

    sprintf(XFileName, "/proc/%d/status", Xpid);

// fprintf(stderr, "filename: %s\t", XFileName);
    fp = fopen(XFileName, "r");

    if (!fp)
        return;

    while( fgets(buf, 127, fp) )
    {
        if (strstr(buf, "VmSize"))
        {
            sscanf(buf, "VmSize: %ld", &Xsize);
        }
    }
ratio=Xsize/(total/1024);
// fprintf(stderr, "total: %f, Xsize: %ld, Ratio: %f\n", total, Xsize, ratio);
   if(old_Xsize!=Xsize)
      {
      int tempy, tempa;
	old_Xsize=Xsize;
	Xsize=Xsize/1024;
	tempy=Xsize%10;
	copyXPMArea(3+(tempy*6),66,6,9,50,48);
	tempa=Xsize/10;
	tempy=tempa%10;
	copyXPMArea(3+(tempy*6),66,6,9,44,48); 
	copyXPMArea(16,46,2,14,41,46);  
	copyXPMArea(6,84,((ratio)*30),10,18,48);
	copyXPMArea(3,102,(35-((ratio)*30)),10,((18+(ratio))*25),48);
      }
    fclose(fp);
}

}
    fp = fopen("/proc/stat", "r");

    if (!fp) 
	return;

    //gather data...
    while( fgets(buf, 127, fp) )
    {
        if (strstr(buf, "page"))
        {
            sscanf(buf, "page %ld %ld", &pageins, &pageouts);
        }

        if (strstr(buf, "swap"))
        {
            sscanf(buf, "swap %ld %ld", &swapins, &swapouts);
        }
    }

    // ----- page in / out ---------------

    if (pageins > last_pageins)
    {
        DrawLite(B_RED, 5, 48);
    }
    else
    {
        DrawLite(B_OFF, 5, 48);
    }

    if (pageouts > last_pageouts)
    {
        DrawLite(B_RED, 10, 48);
    }
    else
    {
        DrawLite(B_OFF, 10, 48);
    }

    last_pageins = pageins;
    last_pageouts = pageouts;

    // --------- swap in/out ------------------

    if (swapins > last_swapins)
    {
        DrawLite(B_RED, 5, 53);
    }
    else
    {
        DrawLite(B_OFF, 5, 53);
    }

    if (swapouts > last_swapouts)
    {
        DrawLite(B_RED, 10, 53);
    }
    else
    {
        DrawLite(B_OFF, 10, 53);
    }

    last_swapins = swapins;
    last_swapouts = swapouts;

    
    fclose(fp);






	RedrawWindowXY(xpm_X, xpm_Y);
	while (XPending(display))
	{
		XNextEvent(display, &Event);
		switch (Event.type)
		{	
			case Expose:
				RedrawWindowXY(xpm_X, xpm_Y);
				break;
			case DestroyNotify:
				XCloseDisplay(display);
				exit(0);
				break;
			}
		}
//   		usleep(250000L);
   		usleep(200000);
   	}              
}

void DrawLite(int state, int dx, int dy)
{
    switch(state)
    {
    case B_RED:
        copyXPMArea(BREDX, BREDY, LITEW, LITEH, dx, dy);
        break;
    case B_GREEN:
        copyXPMArea(BGREENX, BGREENY, LITEW, LITEH, dx, dy);
        break;
    default:
    case B_OFF:
        copyXPMArea(BOFFX, BOFFY, LITEW, LITEH, dx, dy);
        break;
    }

}

