// for Non-ASCII locale 
//#include <global.h>

//#include <qtextcodec.h> 
//extern QTextCodec * codec ;
//#define UniString(str)   codec->toUnicode(str)

int 		flag_24_ok; // we presume a kernel 2.4.x

#include <grp.h>
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

//COMMON
bool 	Procview::treeview = 0;		// true
bool 	Procview::flag_show_file_path = false;
bool 	Procview::flag_cumulative = false;			// times cumulative with children's
bool 	Procview::flag_pcpu_single = false;		// %CPU= pcpu/num_cpus


// COMMON: basic field
int Procview::mini_fields[] = {F_PID, F_STAT,F_MEM, F_CPU, F_CMDLINE, F_END};

//COMMON?
// return username from /etc/passwd
char *userName(int uid,int euid)
{
	char buff[128];
	struct passwd *pw = getpwuid(uid);
	if(!pw) {
		// dont have name !
		sprintf(buff, "%d", uid);
	} else
		strcpy(buff,pw->pw_name);

	if(uid!=euid)
		strcat(buff, euid == 0 ? "*" : "+");
	
	return strdup(buff);
}

// return group name (possibly numeric)
char *groupName(int gid,int egid)
{
    char *p;
	struct group *gr = getgrgid(gid);
	if(!gr) {
	    p = (char *)malloc(11);
	    sprintf(p, "%d", gid);
	} else
	    p = strdup(gr->gr_name);
	//	s.append("*");
    return p;
}



Category::~Category()
{}

int Category::compare(Procinfo *a, Procinfo *b)
{
	return string(a).compare(string(b));
}


Cat_int::Cat_int(const char *heading, const char *explain,
		int w, int Procinfo::*member)
: Category(heading, explain), int_member(member), field_width(w)
{}

QString Cat_int::string(Procinfo *p)
{
	QString s;
	s.setNum(p->*int_member);	
	return s;
}

int Cat_int::compare(Procinfo *a, Procinfo *b)
{
	// qsort() only cares about the sign of the number returned by the
	// comparison function; only a subtraction is necessary
	return a->*int_member - b->*int_member;
}

//COMMON
Cat_percent::Cat_percent(const char *heading, const char *explain, int w, float Procinfo::*member)
: Category(heading, explain), float_member(member), field_width(w)
{}

QString Cat_percent::string(Procinfo *p)
{
	QString s;
	s.sprintf("%01.2f", (double)(p->*float_member));
	return s;
}

int Cat_percent::compare(Procinfo *a, Procinfo *b)
{
	float at = a->*float_member, bt = b->*float_member;
	return at < bt ? 1 : (at > bt ? -1 : 0);
}
// added 2006/05/07
Cat_memory::Cat_memory(const char *heading, const char *explain,int w, unsigned long Procinfo::*member)
: Category(heading, explain), uintl_member(member), field_width(w)
{}

QString Cat_memory::string(Procinfo *p)
{
	QString s;
	char buff[128];

	long sizeK,sizeM;
	sizeK=p->*uintl_member;

	sizeM = sizeK/1024;
/*	if ( sizeM > 1024 )
	{
		sprintf(buff,"%dM",sizeM/1024);
	}
	else */
	if ( sizeM > 0 )
	{
		sprintf(buff,"%dM",sizeM);
	}
	else
		sprintf(buff,"%dK",sizeK);

	if ( sizeK == 0 ) 
		s = "0";
	else 
		s = buff;
	return s;
}

int Cat_memory::compare(Procinfo *a, Procinfo *b)
{
	int bu = b->*uintl_member, au = a->*uintl_member;
	return bu >= au ? (bu == au ? 0 : 1) : -1;
}


Cat_uintl::Cat_uintl(const char *heading, const char *explain, int w,
		unsigned long Procinfo::*member)
: Category(heading, explain), uintl_member(member), field_width(w)
{}

QString Cat_uintl::string(Procinfo *p)
{
	QString s;
	s.setNum(p->*uintl_member);	
	return s;
}

int Cat_uintl::compare(Procinfo *a, Procinfo *b)
{
	int bu = b->*uintl_member, au = a->*uintl_member;
	return bu >= au ? (bu == au ? 0 : 1) : -1;
}


Cat_hex::Cat_hex(const char *heading, const char *explain, int w,
		unsigned long Procinfo::*member)
		: Cat_uintl(heading, explain, w, member)
{}

// QString.sprintf 2x speed than glibc.sprintf (by fasthyun@magicn.com) 
// but QString structuring & destructring eat more time 
QString Cat_hex::string(Procinfo *p)
{
	QString s;
	s.sprintf("%8x", (unsigned)(p->*uintl_member));
	return s;
}

//COMMON, 
Cat_swap::Cat_swap(const char *heading, const char *explain)
: Category(heading, explain)
{}

QString Cat_swap::string(Procinfo *p)
{
	QString s;
	// It can actually happen that size < resident (Sun under Solaris 2.6)
	// Possible with Linux ?

	long sizeK,sizeM;
	sizeK=p->size > p->resident ? p->size - p->resident : 0;
	
	sizeM = sizeK /1024;

	if ( sizeM > 0 ) 
		s= QString::number(sizeM) + "M" ;
	else
		s= QString::number(sizeK) + "K" ;

	if (sizeK == 0) 
		s = "0";
	return s;
}

int Cat_swap::compare(Procinfo *a, Procinfo *b)
{
	return (b->size - b->resident) - (a->size - a->resident);
}



Cat_string::Cat_string(const char *heading, const char *explain,
		QString Procinfo::*member)
: Category(heading, explain), str_member(member)
{}

QString Cat_string::string(Procinfo *p)
{
	return p->*str_member;
}


Cat_user::Cat_user(const char *heading, const char *explain)
: Cat_string(heading, explain)
{}

QString Cat_user::string(Procinfo *p)
{
	if(p->uid == p->euid)
		return Uidstr::userName(p->uid);
	else {
		QString s = Uidstr::userName(p->uid);
		s.append(p->euid == 0 ? "*" : "+");
		return s;
	}
}



Cat_group::Cat_group(const char *heading, const char *explain)
: Cat_string(heading, explain)
{}

QString Cat_group::string(Procinfo *p)
{
	if(p->gid == p->egid)
		return Uidstr::groupName(p->gid);
	else {
		QString s = Uidstr::groupName(p->gid);
		s.append("*");
		return s;
	}
}


Cat_wchan::Cat_wchan(const char *heading, const char *explain)
	: Cat_string(heading, explain)
{}

QString Cat_wchan::string(Procinfo *p)
{
#ifdef LINUX 
	return p->wchan_str;
#else
	return Wchan::name(p->wchan); 
#endif 
}



Cat_cmdline::Cat_cmdline(const char *heading, const char *explain)
: Cat_string(heading, explain)
{}

QString Cat_cmdline::string(Procinfo *p)
{
	if(p->cmdline.isEmpty()) {
		QString s("(");
		s.append(p->command);
		s.append(")");
		return s;
	} else {
		if(Procview::flag_show_file_path)
			return p->cmdline;
		else {
			QString s(p->cmdline);
			
			int i = s.indexOf(' ');
			if(i < 0)
				i = s.length();
			if(i > 0) {
				i = s.lastIndexOf('/', i - 1);
				if(i >= 0)
					s.remove(0, i + 1);
			}
			return s;
		}
	}
}


// hmm COMMON? almost same...but Solaris's zombie process...
Cat_start::Cat_start(const char *heading, const char *explain)
: Category(heading, explain)
{}
// don't let your confidence be shaken, just learn what you can from this young master. 
QString Cat_start::string(Procinfo *p)
{
 #ifdef SOLARIS
 	if( p->state == 'Z' )
        return "-";		// Solaris zombies have no valid start time
#endif
	Proc *proc=p->proc;
	//	time_t start = boot_time + p->starttime / (unsigned)HZ;
	QString s;
	//time_t start = proc->boot_time + p->starttime / proc->clk_tick;
	time_t  start= p->starttime ;
	char *ct = ctime(&start); 	// ctime(sec)
	time_t sec =p->starttime - proc->boot_time ;//secs 
	//if(p->tv.tv_sec - start < 86400) {
	if( sec < 86400) {	// 24hours
		ct[16] = '\0';
		s = ct + 11;	// Hour:minu
	} else 
	{
		ct[10] = '\0';
		s = ct + 4;		// Date 
	}
	return s;
}

int Cat_start::compare(Procinfo *a, Procinfo *b)
{
    unsigned long bs = b->starttime, as = a->starttime;
    return bs >= as ? (bs == as ? 0 : 1) : -1;
}


/* ========================  Procview ============================  */
float Procview::avg_factor = 1.0;

Procview::Procview()
{
	//Proc::Proc(); //call once more ?
	cats.clear();
	reversed = FALSE;
	viewproc = ALL;
	treeview = TRUE;
	idxF_CMD=0;	// **** important ****
	viewfields = USER;
	set_fields();

	sortcat = 0;	// categories[F_PID];
	sort_column=-1;
	sortcat_linear = NULL; 
	enable=true;
	maxSizeHistory=1200;
	refresh(); // before reading Watchdog list
}


// COMMON: 
// Description :
// 		View mode : ALL , OWNER, NO-ROOOT , HIDDEN, NETWORK 
bool Procview::accept_proc(Procinfo *p)
{
	QString pid;
	static int my_uid = getuid();
	bool    result;
	
	result=true;
	
	//BAD
	if(false and viewproc == NETWORK )
	{	
		/*
		p->read_fds();
		if(p->sock_inodes.size()==0)
			result=false;		
		for(int i=0;i<p->sock_inodes.size();i++)
		{
			SockInode *sn=p->sock_inodes[i];
			Sockinfo *si=Procinfo::socks.value(sn->inode,NULL);
			if(si)
			{
				si->pid=p->pid;
				linear_socks.append(si);			
			}
		}
		*/
	}
	else
	if (viewproc==ALL) 
		result=true;
	else
	if ( viewproc == OWNED ) 
		result=(p->uid == my_uid);
	else 
	if ( viewproc == NROOT )  
		result=(p->uid != 0);
	else 
	if ( viewproc == RUNNING)	
		result= strchr("ORDW", p->state) != 0  ;
	
	/*
 	if ( viewproc == HIDDEN)
	{
		result=false;  
		for(int j=0;j<hidden_process.size();j++)
			if(hidden_process[j]==p->command)
				result=true ;
	}
	else 
	{
		for(int j=0;j<hidden_process.size();j++)
			if(hidden_process[j]==p->command)
				result=false;
	} */

	if(result==false) return false;   // dont go further !! for better speed 
	
	///if(search_box==NULL)		return result;
	if(filterstr=="") return result;

	if(filterstr=="*" )	return true;



	// Notice:
	//  1. some process name maybe different CMDLINE.  ex) Xorg
	if(p->cmdline.contains(filterstr,Qt::CaseInsensitive)) //search_box->text() 
		return true;	
	if(p->command.contains(filterstr,Qt::CaseInsensitive))
		return true;
	if(p->username.contains(filterstr,Qt::CaseInsensitive)) 
		return true;

	pid= pid.setNum(p->pid);  //=QString::number(p->pid);
	if(pid.contains(filterstr,Qt::CaseInsensitive)) 	
		return true;
		
	///printf("search_Box =%s , %s \n",search_box->text().toAscii().data(),p->command.toAscii().data());
		
	return false;
}

extern "C"
{
    typedef int (*compare_func)(const void *, const void *);
}

/*
template<class T>
void Svec<T>::sort(int (*compare)(const T *a, const T *b))
{
    qsort(vect, used, sizeof(T), (compare_func)compare);
}
*/

// table view - sort
void Procview::linearize_tree(QVector<Procinfo *> *ps, int level, int prow, bool hide)
{
	static_sortcat = sortcat;
	//ps->sort(reversed ? compare_backwards : compare);
    if(reversed) 
		qsort(ps->data(), ps->size(), sizeof(Procinfo *),(compare_func)  compare_backwards);
	else qsort(ps->data(), ps->size(), sizeof(Procinfo *),(compare_func)  compare);

	int size=ps->size();
	//printf("level=%d prow=%d size=%d\n",level,prow,size);
	for(int i = 0; i < size; i++) 
	{
		Procinfo *p = (*ps)[i];
	//	if (p->pid<6 )	printf("pid=%d level=%d parent_row=%d\n",p->pid,p->pid,p->parent_row);	
		p->level = level;
		p->lastchild = false;
		p->table_child_seq=i;   // ************* where using ? -> sequence
		p->parent_row=prow;
		if(!hide) linear_procs.append(p); //need !!
		if(p->table_children.size())// and !p->hidekids) 
			linearize_tree(&p->table_children, level + 1, linear_procs.size() - 1,hide | p->hidekids );
	}

	if(size > 0)
		(*ps)[size - 1]->lastchild = true;
}

/// basic,memory,job fields 
void Procview::set_fields_list(int fields[])
{
	cats.clear();
	for(int i = 0; fields[i] != F_END; i++)
	{
		if(fields[i]==F_CPUNUM and Proc::num_cpus<2) continue; // not correctly work

		Category *c=categories.value(fields[i],NULL);
		if(c){
			// printf("name=%s\n",c->name);
			cats.append(c);
			}
	}
	return;
}


// return the column number of a field, or -1 if not displayed
int Procview::findCol(int field_id)
{
	for(int i = 0; i < cats.size(); i++)
		if(cats[i]->id==field_id)
			return i;
	return -1;
}

// basis 
// void Procview::fieldArrange()
void Procview::addField(int Fid, int where)
{
//	where=-1; 
//	printf("Fid =%d where=%d\n",Fid,where);
//	where=pstable->clickedColumn();
	if( where ==0 )
	{	
       	//if (pstable->treeMode())  where=1;
	}

	if (Fid==F_CMDLINE)
		where=cats.size(); 	//always should be the last column
			
	if( where <0 ) {
			// this is default
			where=cats.size(); 
	}

	if(where> cats.size()) // CMD_LINE ! ??????
		where=1;

	if(treeview and cats.size()>0 and cats[0]->id== F_CMD) // if command exists
	{
		if(where==0) where=1; // this problem
	}

	Category *newcat = categories[Fid];
//	printf("name =%s where=%d\n",newcat->name,where);
	if (cats.indexOf(newcat)<0)  // if not in the list ****
		cats.insert(where,newcat); 
}

// add a category to last
void Procview::addField(char *name)	// interface 
{
	//QString str=sl[i];
	int id = field_id_by_name(name);
	if(id>=0)
		addField(id); // add to last

	return;
	
	Category *cat = cat_by_name(name);
	if(cat)
		cats.append(cat);
}

void Procview::removeField(int field_id)
{
	for(int i = 0; i < cats.size();)
	{
//	 	printf("Fid=%d cats[%d].id=%d \n",field_id,i,cats[i]->id);
		if(cats[i]->id==field_id)
		{
			if(cats[i]->id==F_CMD and !treeview) idxF_CMD=-1;		
			cats.remove(i);
			break;
		}
		else 
			i++;
	}
//	printf("Fid=%d cats.size=%d\n",field_id,cats.size());
}

//	1. write_settings()
//	DEL? -> not yet
void Procview::update_customfield()
{
	int i;
//	printf("update custom_fields\n");
	
	customfields.clear();	

	for(i=0;i<cats.size();i++)
		customfields.append(cats[i]->name);
	
	if(treeview)
	{
		int idx=customfields.indexOf("COMMAND");// == removeField(F_CMD);
		if(idx>=0) customfields.removeAt(idx);
		
		if(idxF_CMD>=0)
		{
		/* if(customfields.size()<=idxF_CMD)
			customfields.append(categories[F_CMD]->name);
		else	*/
			customfields.insert(idxF_CMD,categories[F_CMD]->name);
		}
	}
	
	return;
}

// Description : FIELD movement by mouse drag 
//				  From col To place
void Procview::moveColumn(int col, int place) 
{
	int i;

	int f_size=cats.size();
	if( col < 0 or place <0 or f_size <= col or f_size<=place)
	{
		printf("QPS code bugs!! : moveColumn() col=%d place=%d cats.size=%d\n",col,place,cats.size());
		return;
	}

	//void Procview::fieldArrange()
	if( treeview==true )  
	{
		// *** important : COMMAND field should be the first field in TreeMode!
		if(place==0)	return;
		if(cats[col]->index==F_CMD) place=0; 
	}
	
	// COMMAND_LINE field should always be the last field 
	//if(cats[place]->index==F_CMDLINE) return; 
	if(cats[col]->index==F_CMDLINE) place=cats.size() - 1;

	Category *cat = cats[col]; // Danger!

	cats.insert(place,cat); //first  insert 
	if(place<col) col++;
	cats.remove(col);	 //second  remove idx

	// refresh();
	///update_customfield();
}


// always called when linear to tree 
void Procview::saveCOMMANDFIELD()
{

	idxF_CMD=-1;
	for(int i=0;i<cats.size();i++)
		if(cats[i]->id==F_CMD)
		{	
		//	printf("saveCOMMANDFIELD\n"); 
		//	hasF_CMD=true;
			idxF_CMD=i;
		}
}

// call by 
// 		1.void Pstable::setTreeMode(bool treemode)
//		2.void Procview::set_fields()
void Procview::fieldArrange()
{

	if(treeview) {
		// Tree Mode 
		saveCOMMANDFIELD(); // save 
	
		// If COMMAND isn't the leftmost column, move it to leftmost
		if(idxF_CMD>=0) 	cats.remove(idxF_CMD); //removeField(F_CMD);
		cats.insert(0,categories[F_CMD]);
		
		// PID sort for convenience (default)  
		for(int i = 0; i < cats.size(); i++)
			if( cats[i]->index == F_PID ) 
			{
				reversed = FALSE;
				sortcat = cats[i];
				//// pstable->setSortedCol(i);   
			}
	} 
	else	
	{
		//Linear_Mode:
		if(cats[0]->index==F_CMD) 	cats.remove(0); //removeField(F_CMD);

		//recover COMMAND field
		if(idxF_CMD>=0)
		{
			//printf(".a.a.\n");
			addField(F_CMD,idxF_CMD);
		}	

		//sort set
	}
	
}

void Procview::setTreeMode(bool b)
{
	if(treeview==false) 
	{
		if(sortcat_linear==NULL)
			sortcat_linear=sortcat;
		else
			sortcat=sortcat_linear;
	}
}

void Procview::setSortColumn(int col, bool r)
{
	//qDebug("xxx error? col>=cats.size() %d",col);
	if(col>=cats.size())
	{
		qDebug("hmmm error? col>=cats.size() %d",col);
		return;
	}

		// if(!procview->treeview) just reverse the lines
	if(col == sort_column) 
		reversed=!reversed;
	else 
		reversed=false;
	sortcat=cats[col];
	sort_column = col;
}


Category *Procview::static_sortcat = 0;
int Procview::compare(Procinfo *const *a, Procinfo *const *b)
{
	if(static_sortcat==0)	return 0;
	int r = static_sortcat->compare(*a, *b);
	return (r == 0) ? ((*a)->pid > (*b)->pid ? 1 : -1) : r;
}

int Procview::compare_backwards(Procinfo *const *a, Procinfo *const *b)
{
	if(static_sortcat==0)	return 0;
	int r = static_sortcat->compare(*b, *a);
	return (r == 0) ? ((*b)->pid > (*a)->pid ? 1 : -1) : r;
}

// COMMON
Category *Proc::cat_by_name(const char *s)
{

	if(s) {
		// java style
		QHashIterator<int,Category *> i(categories);
		while (i.hasNext()) {
			const char *p;
			i.next();
			p=i.value()->name;
			if(*p==' ') p++;
			if(strcmp(p, s) == 0)
				return i.value();
//     cout << i.key() << ": " << i.value() << endl;
		}

	}
	return 0;
}

//COMMON
//call by 
int  Proc::field_id_by_name(const char *s)
{
	if(s) {
		//STL style
		QHash<int,Category *>::iterator i = categories.begin();
		while (i != categories.end()) {
			if(strcmp(i.value()->name, s) == 0)	
				return i.key();	//cout << i.key() << ": " << i.value() << endl;
			++i;
		}	 	

	}	
	return -1;
}

// postInit 
void Proc::commonPostInit()
{
	// java style
	/*
	QHashIterator<int,Category *> i(categories);  // a little suck!
	while (i.hasNext()) {
			i.next(); 
			i.value()->index=i.key();
			i.value()->id=i.key();
	}*/
	
	//STL style , set id 
	QHash<int,Category *>::iterator i = categories.begin();
	while (i != categories.end()) {
		i.value()->index=i.key();
		i.value()->id=i.key();
		//cout << i.key() << ": " << i.value() << endl;
		++i;
	}	 

	num_opened_files=0;		    // test
	num_process = 0;  			//	64bit
	num_network_process = 0; 	// 64bit

	dt_total = 0; // diff system tick  
	dt_used = 0; // for infobar

	loadavg[0] = loadavg[1] = loadavg[2] = 0.0;  // CPU load avg 1min,5min,15minute
	
	Proc::num_cpus = 0;
	Proc::old_num_cpus = 0;

	Proc::mem_total = 0;
	Proc::mem_free = 0;
	
	Proc::mem_buffers = 0;
	Proc::mem_cached = 0;
	// mem_shared = 0; // only linux kernel 2.4.x???

	Proc::swap_total = 0;
	Proc::swap_free = 0;

	Proc::qps_pid = -1;
	Proc::loadQps = 0.0;  
	

	Proc::cpu_times_vec = 0;	// array.
	Proc::old_cpu_times_vec = 0;
	
	Proc::boot_time = 0;
	Proc::clk_tick = 100; //for most system
	
	
	current_gen=0; // !
	mprocs=NULL;
	hprocs=NULL;

	clk_tick=sysconf(_SC_CLK_TCK); //****** The  number  of  clock ticks per second.  
	// 
	// printf("Qps: hz=%d\n",clk_tick);

///	Procinfo::init_static();
}

// COMMON?
// 	called by Procview::rebuild()
// 	using procs, makes root_procs for TABLE_View
void Procview::build_tree(Proclist &procs)
{
	Procinfo *p;
	int proc_n=0;
	
	// children clear
	root_procs.clear(); 
	
	QHash<int,Procinfo*>::iterator i;
	for (i = procs.begin(); i != procs.end();)
	{
		Procinfo *p = i.value(); 
		p->table_children.clear();  
		if(p->accepted=accept_proc(p)) proc_n++;
		++i;
	}

	Proc::num_process=proc_n;      // count process
	
	// find parent of a process
  	for (i = procs.begin(); i != procs.end();++i)
	{
		p=i.value();  // always not NULL
		
		if(p->accepted) 
		{
			Procinfo *parent = 0;
			int virtual_parent_pid; 

			if(p->isThread())
				virtual_parent_pid=p->tgid; // thread's leader ID.
			else 
				virtual_parent_pid=p->ppid;

			
			if(p->pid < p->ppid)
			{	
				// this occurs !! a reporter mailed to me 
			}
			
			parent = procs.value(virtual_parent_pid,NULL); // if pid not found, then return NULL.

			//	printf("thread_leader=0 (%d) %s\n",p->tgid,p->command.ascii());
			if(treeview and parent and parent->accepted )  
			{
				//p->table_child_seq=parent->table_children.size();
				parent->table_children.append(p);
			} 
			else						
			{
				// 1.init(pid=1) process  
				// 2.some process which parent not accepted 
				// 3.(null) thread has TGID=0,PPID=0
				// 4.when not tree mode
				root_procs.append(p);
			}
		} 
	}	
}



//COMMON
//BOTTLENECK No.3   0.5%
//re-sort the process list , ::rebuild() for Table
// called by Pstable::refresh()
void Procview::rebuild()
{
	linear_procs.clear();  //Svec<Procinfo *> procs in Proview
#ifdef LINUX
	linear_socks.clear();
#endif

	//Procinfo *pi = getProcinfoByPID(Procinfo::qps_pid);
	//if(pi) Procinfo::loadQps=pi->pcpu;
//	printf("rebuild\n");	

	/* if(mprocs)
	{
		build_tree(*mprocs);
	}
	else */
		build_tree(Proc::procs);

	linearize_tree(&root_procs, 0, -1);
}

// COMMON: CORE 
// Description: update the process list      BottleNeck 1.5%
// 		read /proc/*
// 		called by Procview::refresh(), every UPDATE .
void Proc::refresh()
{
	current_gen++;
	
	// TEST for Process History 
	SysHistory *s=new SysHistory;
	
	history.append(s);
	hprocs=&(s->procs);
	
	//init
	///num_opened_files=0;
	Proc::num_process=0; 
	Proc::num_network_process=0; 
	
	Proc::read_loadavg();
	
	Proc::read_system(); // **** should be every refresh !!

	//s->load_cpu=(float)Proc::dt_used/Proc::dt_total;  //after read_system(); 
	s->load_cpu=load_cpu; //after read_system(); 
	s->time=time(NULL); // save current time in seconds since epoch

	//TEST
	//Procinfo::read_sockets(); // for future, BottleNect 2%
	read_byte=0;
	write_byte=0;

///	Proc::read_sockets(); // test

	read_proc_all(); //Linux, Solaris...
	
	s->load_io=(float)(read_byte + write_byte )/(50*1024*1024); //dt_total;
	// printf("rw=[%d,%d] %f\n",read_byte, write_byte,s->load_io);

	// remove non-existing processes, remove Procinfos of nonexisting processes
	QHash<int,Procinfo*>::iterator i;
	for ( i = procs.begin(); i != procs.end();)
	{
		Procinfo *p = i.value(); 
		if(p->generation != current_gen) {
//			printf("delete %d\n",p->pid);
			i=procs.erase(i);   
		 	delete p;
		} 
		else
		{	
		//	p->table_children.clear();  // for rebuild()
		//	p->accepted=accept_proc(p);
			++i;
		}
	}
	
//	TESTING
	while(history.size()>=maxSizeHistory)
	{	
		//if(history.isEmpty()==false)
		delete history.takeFirst();
	}
}


//COMMON
// read new process info
void Procview::refresh()
{
	/****************************************************************/
	/* Procview.procs has the procinfo 								*/
	/****************************************************************/
	if(enable) 
	{
		//printf("Procview::refresh()\n");
		Proc::refresh(); 	// read "/proc/*", then update the process list
	}
}


SysHistory::~SysHistory()
{
	Procinfo *p;
	foreach(p,procs)
	{
		delete p;
	}
	procs.clear();//remove all (key,val)
}


/* check
Category *Proc::cat_by_name(const char *s)
{
    if( s )
    {
        for( int i = 0; i < categories.size(); i++ )
            if( strcmp(categories[i]->name, s) == 0 )
                return categories[i];
    }
    return 0;
} 


int  Proc::field_id_by_name(const char *s)
{
    if( s )
    {
        for( int i = 0; i < categories.size(); i++ )
            if( strcmp(categories[i]->name, s) == 0 )
                return i;
    }
    return -1;
}
*/
