#include "whowatch.h"
#include "proctree.h"

int allocated;
int lines_before_curs;	/* how many lines was inserted before cursor */

static struct process *begin;

void proc_del(struct process *p)
{						
	*p->prev=p->next;				
	if (p->next) p->next->prev = p->prev;
	if (p->proc) p->proc->priv = 0;	
	free(p);
	proc_win.d_lines--;					
	allocated--;					
}

void mark_del(void *vp)
{
	struct process *p = (struct process *) vp;
	struct proc_t *q;

	q = p->proc;
	for(q = q->child; q; q = q->broth.nx)
		if (q->priv) mark_del(q->priv);

	p->proc->priv = 0;	
	p->proc = 0;
}

static inline int is_marked(struct process *p)
{
	return p->proc?0:1;
}

void clear_list()
{
	struct process *p, *q;
	for(p = begin; p; p = q){
		q = p->next;
		proc_del(p);
	}
}

/*
 * If some lines are inserted above cursor, move virtual screen so
 * cursor stays at the same position.
 */
void check_line(int line)
{
	if (!proc_win.first_line && !proc_win.cursor_line) return;
	if (line <= proc_win.cursor_line + proc_win.first_line)
		proc_win.first_line++;
}

void synchronize()
{
	int l = 0;
	struct proc_t *p = tree_start(tree_pid, tree_pid);
	struct process **current = &begin, *z;
	while(p){
		if (*current && p->priv){
			(*current)->line = l++;
			(*current)->proc->priv = *current;
			p = tree_next();
			current = &((*current)->next);
			continue;
		}
		z = malloc(sizeof *z);
		if (!z) allocate_error();
		allocated++;
		proc_win.d_lines++;
		memset(z, 0, sizeof *z);
		check_line(l);
		z->line = l++;
		p->priv = z;
		z->proc = p;
		if (*current){
			z->next = *current;
			(*current)->prev = &z->next;
		}
		*current = z;
		z->prev = current;
		current = &(z->next);
		p = tree_next();
	}

}

void delete_tree_lines()
{
	struct process *u, *p;
	p = begin;
	while(p){
		if (!is_marked(p)){
			p = p->next;
			continue;
		}
		delete_line(&proc_win, p->line);
		u = p;
		while(u) {
			u->line--;
			u = u->next;
		}
		u = p->next;
		proc_del(p);
		p = u;
	}
}

char get_state_color(char state)
{
	static char m[]="R DZT?", c[]="\5\2\6\4\7\7";
	char *s = strchr(m, state);
	if (!s) return '\3';
	return c[s - m];	
}

char *prepare_line(struct process *p)
{
	char *tree;
	if (!p) return 0;
	tree = tree_string(tree_pid, p->proc);
	get_state(p);
	if(show_owner) 
		snprintf(line_buf, buf_size,"\x3%5d %c%c \x3%-8s \x2%s \x3%s", 
			p->proc->pid, get_state_color(p->state), 
			p->state, get_owner_name(p->uid), tree, 
			get_cmdline(p->proc->pid));
	else 
		snprintf(line_buf, buf_size,"\x3%5d %c%c \x2%s \x3%s", 
			p->proc->pid, get_state_color(p->state), 
			p->state, tree, get_cmdline(p->proc->pid));
		
	return line_buf;
}

	
char *proc_give_line(int line)
{
	struct process *p;
	for (p = begin; p ; p = p->next){
		if (p->line == line){
			if (!p->proc) return "\x1 deleted";
			return prepare_line(p);
		}
	}
	return NULL;
}

pid_t pid_from_tree(int line)
{
	struct process *p;
	for (p = begin; p; p = p->next){
		if (p->line == line) return p->proc->pid;
	}
	return 0;
}	

void dump_list()
{
#ifdef DEBUG
	struct process *p = begin;
	fprintf(debug_file,"\nbegin %p\n", begin);
	while(p){
		fprintf(debug_file, "%p next %p, line %d, pid %d %s\n",p,p->next,
			p->line,p->proc->pid, get_cmdline(p->proc->pid));
		p = p->next;
	}
	fflush(debug_file);
#endif
}

void tree_title(struct user_t *u)
{
	char buf[128];
	if (!u) sprintf(buf,"%d processes", allocated);
	else 
        	snprintf(buf, sizeof buf,
                	"%-14.14s %-9.9s %-6.6s %s",
                	u->parent, u->name, u->tty, u->host);
        buf[sizeof buf - 1] = '\0';
	wattrset(info_win.wd, A_BOLD);
        echo_line(&info_win, buf, 1);
}

void clear_tree_title()
{
	WINDOW *w = info_win.wd;
	wmove(w, 1, 0);
	wclrtoeol(w);
	wrefresh(w);
}

void tree_periodic()
{
	update_tree(mark_del);
	delete_tree_lines();
	synchronize();
	maintree(tree_pid);
}

void maintree(int pid)
{
	struct process *p;
	if(!begin) {
		WINDOW *w = proc_win.wd;
		wmove(w, 0, 0);
		wclrtoeol(w);
		wattrset(w, A_NORMAL);
		waddstr(w, "User logged out");		
		return;
	}
	for(p = begin; p ;p = p->next) {
		if(!p->proc) continue;
		
		/* it is above visible screen */
		if(p->line < proc_win.first_line) continue;

		/* below visible screen */
		if(p->line > proc_win.first_line + proc_win.rows - 1)
			break;
		print_line(&proc_win,prepare_line(p), p->line, 0);
	}
}

void refresh_tree()
{
	maintree(tree_pid);
	updatescr(&proc_win);
}


syntax highlighted by Code2HTML, v. 0.9.1