/* option 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

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ncurses.h>
#include <fcntl.h>
#include <libintl.h>
#include <pthread.h>
#include <math.h>

#include "aux.h"
#include "pptop.h"
#include "filter.h"
#include "fields.h"
#include "title.h"
#include "help.h"

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

extern char *sort_key_name;
extern int sort_key_reverse;
extern int lines_to;
extern pthread_mutex_t header_lock;
extern int show_threads;

int lines_to = 0;
long int max_loop = 30;

struct fork_type
{
  char *to_trans;
  int (*fn)(intptr_t);
};

void *
get_num (void *args) 
{
  char c[32], *d;
  struct fork_type *blah = (struct fork_type *)args;
  int in = fileno (stdin);
  long l_c;

  pthread_mutex_lock (&header_lock);
  echo ();
  mvaddstr (fix_head_count () - 1, 0, "");
  clrtoeol ();
  mvaddstr (fix_head_count () - 1, 0, blah->to_trans);
  set_title (blah->to_trans);

  fcntl (in, F_SETFL, fcntl (in, F_GETFL, 0) & ~O_NONBLOCK); 
  getnstr (c, 32);
  l_c = strtol (c, &d, 10);
  blah->fn (l_c);
  fcntl (in, F_SETFL, fcntl (in, F_GETFL, 0) | O_NONBLOCK); 
  noecho ();
  pthread_mutex_unlock (&header_lock);
  return 0;
}

void *
get_string (void *args) 
{
  struct fork_type *blah = (struct fork_type *)args;
  char c[32];
  int in = fileno (stdin);
  long l_c;

  pthread_mutex_lock (&header_lock);
  echo ();
  mvaddstr (fix_head_count () - 1, 0, "");
  clrtoeol ();
  mvaddstr (fix_head_count () - 1, 0, _(blah->to_trans));
  set_title (blah->to_trans);

  fcntl (in, F_SETFL, fcntl (in, F_GETFL, 0) & ~O_NONBLOCK); 
  getnstr (c, 32);
  fcntl (in, F_SETFL, fcntl (in, F_GETFL, 0) | O_NONBLOCK); 
  noecho ();
  blah->fn ((intptr_t) c); 
  pthread_mutex_unlock (&header_lock);
  free (blah);

  return 0;
}

int
set_lines (intptr_t arg)
{
  lines_to = arg;
  return arg;
}

int get_lines (void)
{
  return lines_to ? lines_to : LINES;
}

int
set_delay (intptr_t _arg)
{
  char *arg = (char*) _arg;
  char **tail;
  float f = strtof (arg, tail);

  f *= 10.0;
  if (f >= 0.0)
    max_loop = lrintf (f);

  return max_loop;
}

int
wait_and_check_for_quit (void)
{
  long int i;
  int chr;

  for (i = 0; i < max_loop; i++)
    {
      usleep (100000);		/* 0.1 seconds */
      if (!pthread_mutex_trylock (&header_lock))
	pthread_mutex_unlock (&header_lock);
      else 
	continue;

      chr = getch ();
      switch (chr)
	{
	case 'q':
	  return TRUE;
	case 'l':
	  adjust_headers (LOADMACH_LINE);
	  break; 
	case 'm':
	  adjust_headers (MEMORY_LINE);
	  adjust_headers (PAGER_LINE);
	  break;
	case 's':
	  adjust_headers (CPU_LINE);
	  adjust_headers (PROCESS_LINE);
	  break;

	case 'c': case 'C':
	  {
	    int cl = add_remove_field ("commandline", -1);
	    if (cl != -1)
	      add_remove_field ("command", cl);
	    else if ((cl = add_remove_field ("command", -1)) != -1)
	      add_remove_field ("commandline", cl);
	  }
	  break;

	  /* sorting */
	case 'N':
	  sort_key_name = "PID";
	  sort_key_reverse = 1;
	  break;
	case 'n':
	  sort_key_name = "PID";
	  sort_key_reverse = 0;
	  break;
	case 'P':
	  sort_key_name = "CPU";
	  sort_key_reverse = 1;
	  break;
	case 'p':
	  sort_key_name = "CPU";
	  sort_key_reverse = 0;
	  break;
	case 'T':
	  sort_key_name = "Time";
	  sort_key_reverse = 1;
	  break;
	case 't':
	  sort_key_name = "Time";
	  sort_key_reverse = 0;
	  break;

	case 'e':
	  show_threads = !show_threads;
	  break;

	case 'u':
	  {
	    struct fork_type *blah = malloc (sizeof (struct fork_type));
	    pthread_t t;
	    blah->to_trans = _("Which User (Blank for all): ");
	    blah->fn = change_user;

	    pthread_create(&t, NULL, get_string, blah);
	    pthread_detach(t);
	  }
	  break;

	  /* show # processes */
	case '#':
	  {	
	    struct fork_type *blah = malloc (sizeof (struct fork_type));
	    pthread_t t;
	    blah->to_trans = _("How many lines would you like to show (0 for unlimited): ");
	    blah->fn = set_lines;

	    pthread_create(&t, NULL, get_num, blah);
	    pthread_detach(t);
  
	  }
	  break;

	case 'd':
	  {	
	    struct fork_type *blah = malloc (sizeof (struct fork_type));
	    pthread_t t;
	    blah->to_trans = _("Delay between updates: ");
	    blah->fn = set_delay;

	    pthread_create(&t, NULL, get_string, blah);
	    pthread_detach(t);
  
	  }
	  break;
	  
	case 'z':
	  while ((chr = getch ()) == ERR) usleep (10000);
	  return FALSE;

	case 'f':
	  show_filters ();
	  return FALSE;

	case 'h': case '?': 
	  top_help ();
	  return FALSE;
	}
    }
  /* we got to the end and 'q' has not been pressed */
  return FALSE;
}
