#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <string.h>
#include <stdlib.h>
#include <sys/statfs.h>
#include <stdint.h>
#include <netinet/in.h>

typedef struct {
	unsigned long user;
	unsigned long nice;
	unsigned long system;
	unsigned long idle;
	unsigned long total; //total
}Total_Cpu_Occupy_t;
static Total_Cpu_Occupy_t o_sys_cpu, n_sys_cpu;

typedef struct {
	unsigned int pid;
	unsigned long utime;  //user time
	unsigned long stime;  //kernel time
	unsigned long cutime; //all user time
	unsigned long cstime; //all dead time
	unsigned long total; //total
}Proc_Cpu_Occupy_t;
static Proc_Cpu_Occupy_t o_proc_cpu, n_proc_cpu;

typedef struct {
	unsigned int total;// KB
	unsigned int free;
	//unsigned int proc_used;// KB
	unsigned short used_percent;// x% * 100
}Mem_Usage_t;
static Mem_Usage_t mem_info;

static unsigned long get_cpu_total_occupy(Total_Cpu_Occupy_t *t){

	FILE *fd;
	char buff[1024]={0};

	fd =fopen("/proc/stat", "r");
	if (NULL == fd){
		return 0;
	}

	fgets(buff,sizeof(buff),fd);
	char name[64]={0};
	sscanf(buff,"%s %ld %ld %ld %ld", name, &t->user,&t->nice,&t->system,&t->idle);
	t->total = t->user + t->nice + t->system + t->idle;
	//printf("Get sys cpu, user:%lu, sys:%lu, nice:%lu, idle:%lu, total:%lu\r\n",t->user,t->system,t->nice,t->idle,t->total);
	fclose(fd);

	return (t->user + t->nice + t->system + t->idle);
}

const char* get_items(const char*buffer ,unsigned int item){

	const char *p =buffer;

	int len = strlen(buffer);
	int count = 0;

	for (int i=0; i<len;i++){
		if (' ' == *p){
			count ++;
			if(count == item -1){
				p++;
				break;
			}
		}
		p++;
	}

	return p;
}

#define PROCESS_ITEM_INDEX 14
static unsigned long get_cpu_proc_occupy(Proc_Cpu_Occupy_t *t){

	char file_name[64]={0};
	FILE *fd;
	char line_buff[1024]={0};

	pid_t pid = getpid();
	sprintf(file_name,"/proc/%d/stat",pid);

	fd = fopen(file_name,"r");
	if(NULL == fd){
		return 0;
	}

	fgets(line_buff,sizeof(line_buff),fd);

	sscanf(line_buff,"%u",&t->pid);
	const char *q =get_items(line_buff,PROCESS_ITEM_INDEX);
	sscanf(q,"%lu %lu %lu %lu",&t->utime,&t->stime,&t->cutime,&t->cstime);
	t->total = t->utime + t->stime + t->cutime + t->cstime;
	//printf("Get proc cpu, u:%lu, s:%lu, cu:%lu, cs:%lu, total:%lu\r\n",t->utime,t->stime,t->cutime,t->cstime,t->total);
	fclose(fd);

	return (t->utime + t->stime + t->cutime + t->cstime);
}


#define MAX_VMRSS_LINE 64
static unsigned int get_proc_mem(unsigned int pid){// KB

	char file_name[64]={0};
	FILE *fd;
	char line_buff[512]={0};
	sprintf(file_name,"/proc/%d/status",pid);

	fd =fopen(file_name,"r");
	if(NULL == fd){
		return 0;
	}

	char name[64];
	unsigned int vmrss = 0;
	char *pLine = NULL;
	for (int i=0; i<MAX_VMRSS_LINE;i++){
		pLine = fgets(line_buff,sizeof(line_buff),fd);
		if (pLine == NULL) {
			break;
		}
		if (strncmp(line_buff, "VmRSS", 5) == 0) {
			sscanf(line_buff,"%s %u",name,&vmrss);
			//printf("Get proc mem used:%u\r\n", vmrss);
			break;
		}
	}
	
	fclose(fd);

	return vmrss;
}

#define MAX_MEM_INFO_LINE 32
static void get_memoccupy (Mem_Usage_t *mem) {// KB
    FILE *fd;
	char line_buff[512]={0};

    fd = fopen ("/proc/meminfo", "r");
	if(NULL == fd){
		return ;
	}

	char name[64];
	char *pLine = NULL;
	int count = 0;
	for (int i=0; i<MAX_MEM_INFO_LINE;i++){
		pLine = fgets(line_buff,sizeof(line_buff),fd);
		if (pLine == NULL) {
			break;
		}
		if (strncmp(line_buff, "MemTotal", 8) == 0) {
			sscanf(line_buff,"%s %u",name,&mem->total);
			//printf("total mem:%s %u\n",name,&mem->total);
			count++;
		} else if (strncmp(line_buff, "MemFree", 7) == 0) {
			sscanf(line_buff,"%s %u",name,&mem->free);
			//printf("free mem:%s %u\n",name,&mem->free);
			count++;
		}
		if (count == 2) {
			//printf("Get sys mem total:%u, free:%u\r\n", mem->total, mem->free);
			mem->used_percent = (unsigned short)(100 * (100 - (mem->free*100)/ mem->total));
			//printf("mem used %d\n", mem->used_percent );
			break;
		}
	}

    fclose(fd);
}

#define MAX_PARTITION_NUM 32
#define MAX_PT_NAME_LEN 128
#define MAX_PT_VALUE_LEN 32
#define MAX_PT_TITLE_LEN 256
typedef struct {
	char mountpoint_path[MAX_PT_NAME_LEN];
	unsigned int total;// MB
	unsigned int used;// MB
}Pt_Info_t;

typedef struct {
	unsigned char	pt_count;
	Pt_Info_t pt[MAX_PARTITION_NUM];
}Partitions_t;
static Partitions_t pt_info;

static int get_sysDiskUsage()
{
	FILE * fp;
	char filesystem[MAX_PT_NAME_LEN],available[MAX_PT_VALUE_LEN],use[MAX_PT_VALUE_LEN],mounted[MAX_PT_NAME_LEN],buf[MAX_PT_TITLE_LEN];
	unsigned int blocks, used;

	fp=popen("df -m", "r");
	fgets(buf,MAX_PT_TITLE_LEN,fp);// skip

	pt_info.pt_count = 0;
	while(6 == fscanf(fp,"%s %u %u %s %s %s",filesystem,&blocks,&used,available,use,mounted))
	{
		pt_info.pt[pt_info.pt_count].total = blocks;
		pt_info.pt[pt_info.pt_count].used = used;
	//	printf("disk total used: %d %d\n",pt_info.pt[pt_info.pt_count].total, pt_info.pt[pt_info.pt_count].used );
		strncpy(pt_info.pt[pt_info.pt_count].mountpoint_path, mounted, MAX_PT_NAME_LEN);

		pt_info.pt_count++;
		if (pt_info.pt_count >= MAX_PARTITION_NUM)
		{
			break;
		}
	}
	//printf("disk count=%d\n", pt_info.pt_count);

	pclose(fp);

	return 1;
}

void init_sys_stat()
{
	get_cpu_total_occupy(&o_sys_cpu);
	//get_cpu_proc_occupy(&o_proc_cpu);
}

int get_sys_stat(unsigned char *pBuf, int bufLen)
{
	get_cpu_total_occupy(&n_sys_cpu);
	//get_cpu_proc_occupy(&n_proc_cpu);

	get_memoccupy (&mem_info);
	//mem_info.proc_used = get_proc_mem(n_proc_cpu.pid);

	get_sysDiskUsage();

	// calc proc cpu percent
	unsigned short sys_cpu_percent = 0, proc_cpu_percent = 0;
	if (n_sys_cpu.total != o_sys_cpu.total)
	{
		//proc_cpu_percent = (unsigned short)((n_proc_cpu.total - o_proc_cpu.total)*10000/(n_sys_cpu.total - o_sys_cpu.total));
		sys_cpu_percent = (unsigned short)((n_sys_cpu.system + n_sys_cpu.user - o_sys_cpu.system - o_sys_cpu.user)*10000/(n_sys_cpu.total - o_sys_cpu.total));
	}
	memcpy(&o_sys_cpu, &n_sys_cpu, sizeof(n_sys_cpu));
	//memcpy(&o_proc_cpu, &n_proc_cpu, sizeof(n_proc_cpu));

	int statLen = 9 + (pt_info.pt_count * 8);
	if (statLen > bufLen)
	{
		return 0;
	}

	int i;/*
	printf("sys/proc cpu:%d:%d\r\nmem total:%d, proc:%d, per:%d\r\npt num: %d\r\n", 
			sys_cpu_percent, proc_cpu_percent, mem_info.total, mem_info.proc_used, mem_info.used_percent, pt_info.pt_count);
	for (i=0; i<pt_info.pt_count; i++)
	{
		printf("pt[%d], used/total:[%u/%u]\r\n", i, pt_info.pt[i].used, pt_info.pt[i].total);
	}*/

	//printf("cpu_usage=%d, mem total=%d, mem free=%d, mem usage=%d, disk num=%d\n", sys_cpu_percent, mem_info.total, mem_info.free,mem_info.used_percent,pt_info.pt_count);
	unsigned int temp_u32;
	unsigned short temp_u16;
	//temp_u16 = htons(proc_cpu_percent);
	//memcpy(pBuf, &temp_u16, 2);
	temp_u16 = htons(sys_cpu_percent);
	memcpy(pBuf, &temp_u16, 2);
	temp_u32 = htonl(mem_info.total);
	memcpy(pBuf+2, &temp_u32, 4);
	//temp_u32 = htonl(mem_info.proc_used);
	//memcpy(pBuf+8, &temp_u32, 4);
	temp_u16 = htons(mem_info.used_percent);
	memcpy(pBuf+6, &temp_u16, 2);
	pBuf[8] = pt_info.pt_count;
	for (i=0; i<pt_info.pt_count; i++)
	{
		temp_u32 = htonl(pt_info.pt[i].total);
		memcpy(pBuf+9+8*i, &temp_u32, 4);
		temp_u32 = htonl(pt_info.pt[i].used);
		memcpy(pBuf+13+8*i, &temp_u32, 4);
	}
	return statLen;
}


