/* filter functions for pptop

   Copyright (C) 2002 James A. Morrison.

   Written by James A. Morrison <ja2morri@uwaterloo.ca>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA */

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif 

#define _(STRING) gettext (STRING)
#define N_(STRING) STRING

#define UNORPHANED_FILTER 0
#define USER_FILTER 1
#define LEADER_FILTER 2
#define CTTY_FILTER 3
#define PARENT_FILTER 4
#define ALIVE_FILTER 5

#define FILTER_COUNT 6


#include <unistd.h>
#include <ps.h>
#include <pwd.h>
#include <ncurses.h>
#include <libintl.h>
#include <stdint.h>

#include "aux.h"
#include "filter.h"

int cur_uid;

struct active_filter
{
  const struct ps_filter *filter;

  /* ACTIVE has three states, 0 for inactive, -1 for inverted, and 1 for
     active */
  int active;
};

struct active_filter *filters[FILTER_COUNT];

/* Changes the state of alter to state. 
   States, 1 active, 0 inactive, -1 inverted and active. */
int adjust_filter (int alter, int state)
{
  filters[alter]->active = state;
  return filters[alter]->active;
}

int do_filters (struct proc_stat_list *psl)
{
  int i = 0;
  
  for (; i < FILTER_COUNT; i++)
    if (filters[i]->active)
      proc_stat_list_filter (psl, filters[i]->filter, 
			     filters[i]->active == -1);

  return 0;
}

int show_filters (void)
{
  int changes = 0, i;
  signed char c = '\0';

  while (c != (' ' - 'a'))
    {
      int line = 1;

      erase ();
      for (i = 0; i < FILTER_COUNT; i++)
	{
	  char e[4];

	  snprintf (e, 4, "%c", i + 'a');
	  mvaddstr (line, 1, e);

	  if (filters[i]->active == 1)
	    mvaddstr (line, 3, "+");
	  else if (filters[i]->active == -1)
	    mvaddstr (line, 3, "-");
	  
	  mvaddstr (line++, 5, filters[i]->filter->name);
	  clrtoeol ();
	}
      mvaddstr (LINES - 4, 0, _("+ Filter is Active"));
      clrtoeol ();
      mvaddstr (LINES - 3, 0, _("- Filter is reversed"));
      clrtoeol ();
      bold_text (LINES - 1, 0, _("Press space to return to top"));
      clrtoeol ();

      while ((c = getch ()) == ERR) usleep (10000);

      c -= 'a';
      if ((c < FILTER_COUNT) && (c >= 0))
	{
	  if (++filters[c]->active > 1)
	    filters[c]->active = -1;
	  changes++;
	}
    }

  return changes;
}

int change_user (intptr_t _name)
{
  char *name = (char*) _name;
  struct passwd *blah = getpwnam (name);
  if (!blah)
    filters[USER_FILTER]->active = 0;
  else
    {
      cur_uid = blah->pw_uid;
      filters[USER_FILTER]->active = 1;
    }

  return 0;
}

int top_user_filter (struct proc_stat *ps)
{
  if (cur_uid == ps->owner_uid)
    return 1;
  else
    return 0;
}

const struct ps_filter ps_user_filter =
  {"user", PSTAT_OWNER_UID, top_user_filter};
struct active_filter user_filter =
  {&ps_user_filter, 0};

struct active_filter not_leader_filter =
  {&ps_not_leader_filter, 0};

struct active_filter unorphaned_filter =
  {&ps_unorphaned_filter, 0};

struct active_filter ctty_filter =
  {&ps_ctty_filter, 0};

struct active_filter parent_filter =
  {&ps_parent_filter, 0};

struct active_filter alive_filter =
  {&ps_alive_filter, 0};

int
setup_filters (void)
{

  cur_uid = getuid ();
  filters[USER_FILTER] = &user_filter;
  filters[LEADER_FILTER] = &not_leader_filter;
  filters[UNORPHANED_FILTER] = &unorphaned_filter;
  filters[CTTY_FILTER] = &ctty_filter;
  filters[PARENT_FILTER] = &parent_filter;
  filters[ALIVE_FILTER] = &alive_filter;

  return 0;
}
