#include 
#include 
#include 
#include 
#include 

#define BLU "\033[1;34m"
#define GRE "\033[1;32m"
#define YEL "\033[1;33m"
#define RED "\033[1;31m"
#define RES "\033[0m"

/*
 * 5 years in seconds : 
 *
 * 60*60*24*30*12*5 = 155520000 
 *
 * 9 bytes for integer part and 2 bytes for floating part, x2
 *
 */

#define BAR_SIZE  51
#define BUFF_SIZE 22
#define MEMO_SIZE 100
#define CORE_NUMB get_nprocs_conf()

/*
 *
 * /proc/uptime 11267.58 43986.27
 *
 * This file contains two numbers (values in seconds): the uptime of the system 
 * (including time spent in suspend) and the amount of time spent in the idle process 
 *
 * /!\ Second value is core dependant /!\
 *
 * /proc/meminfo
 *
 * [voidboy@voidsys swag]$ cat /proc/meminfo 
 * MemTotal:        7972252 kB
 * MemAvailable:    7467072 kB
 *
 */

struct procInfo {
	float uptime;
	float idle;
};

struct memoInfo {
	int total;
	int avail;
};

void ramInfo(struct memoInfo *m)
{
	FILE    *f = fopen("/proc/meminfo", "r");
	int      i = 0;
	int      j = 0;
	char *buff = (char*)calloc(MEMO_SIZE,sizeof(char)); 

	fread(buff,sizeof(char),MEMO_SIZE,f);
	while(buff[i] != '\n') {i++;}
	buff[i] = '\0';
	sscanf(buff,"MemTotal:        %d kB", &m->total);
	while(buff[i] != '\n') {i++;}
	j = i + 1;
	while(buff[i] != '\n') {i++;}
	buff[i] = '\0';
	sscanf(buff+j,"MemAvailable:  %d kB", &m->avail);

	fclose(f);
	free(buff);
}

void cpuInfo(struct procInfo *p)
{
	FILE    *f = fopen("/proc/uptime", "r");
	int      i = 0;
	char *buff = (char*)calloc(BUFF_SIZE,sizeof(char));

	fread(buff,sizeof(char),BUFF_SIZE,f);
	while(buff[i] != 0x20) {i++;}
	buff[i]   = '\0';
	p->uptime = strtof(buff, NULL);
	p->idle   = strtof(buff+i+1, NULL);

	fclose(f);
	free(buff);
}

void setBar(char *b, float l)
{
	int i = (int)(l / 2.0);

	for(;i<BAR_SIZE;i++)
		b[i] = ' ';
}

void rstBar(char *b)
{
	strcpy(b,"||||||||||||||||||||||||||||||||||||||||||||||||||");
}


float ramLoad(struct memoInfo m)
{
	return 100.0 - ((float)m.avail / (float)m.total) * 100.0;
}

float avgCpuLoad(struct procInfo p)
{
	return 100.0 - ((p.idle / CORE_NUMB) / p.uptime) * 100.0;
}

char *pickClr(float l)
{
	if(l >= 0.0 && l > 30.0)
		return BLU;
	else if(l >= 30.0 && l > 60.0)
		return GRE;
	else if(l >= 60.0 && l > 80.0)
		return YEL;
	else
		return RED;
}

int main(int argc, char *argv[])
{
	int    i       = 0;
	char   *l      = "-\\|/";
	char   *z      = malloc(BAR_SIZE * sizeof(char));
	char   *clrCpu = BLU;
	char   *clrRam = BLU;
	float  loadCpu = 0.0; 
	float  loadRam = 0.0;
	struct procInfo pi = { .uptime  = 0,
		               .idle    = 0};
	struct memoInfo ri = { .total   = 0,
		               .avail   = 0};
	struct timespec ts = { .tv_sec  = 0,
	                       .tv_nsec = 250000000L};
	rstBar(z);
	while(1)
	{
		cpuInfo(&pi);
		ramInfo(&ri);
		loadCpu = avgCpuLoad(pi);
		loadRam = ramLoad(ri);
		clrCpu  = pickClr(loadCpu);
		clrRam  = pickClr(loadRam);
		setBar(z,loadRam);
		for(i=0;i<4; i++)
		{
			printf("\rCPU : %c ~ %s%.2f%%%s",l[i],clrCpu,loadCpu,RES);
			printf(" | ");
			printf("RAM : [%s%s%s] ~ %s%.2f%%%s",clrRam,z,RES,clrRam,loadRam,RES);
			fflush(stdout);
			nanosleep(&ts, NULL);
		}
		rstBar(z);
	}
	free(z);

	return 0;
}