#!/usr/bin/env perl

###############################################################################
# topper (c) 2011 John Sennesael                                              #
# This program comes with ABSOLUTELY NO WARRANTY.                             #
# This is free software, and you are welcome to redistribute it               #
# under certain conditions.                                                   #
# For detail see enclosed LICENSE file.                                       #
###############################################################################

use lib 'pm';
use strict;
use POSIX;
use topper::output;
use topper::config;
use topper::database;
use topper::datasink;

# Globals. --------------------------------------------------------------------

# Output object.
my $out;
# Configuration object.
my $config;
# Database object.
my $db;
# Datasink object.
my $sink;

# Subroutines. -----------------------------------------------------------------

sub ps_parse_error($$$)
{
  my ($field,$line,$regex) = @_;
  my $errstr = "\n\nERROR: Error parsing field: $field\n";
  $errstr .= "Regular expression: $regex\n";
  $errstr .= "did not match while parsing line:\n";
  $errstr .= "$line\n\n";
  die($errstr);
}

sub get_proc_info()
{
  # Get process info.
  my $ps_cmd = $config->get_ps_command();
  my @procs = `$ps_cmd`;
  $sink->reset_entry_time();
  # Trim head and tail if needed.
  for (my $i = 0 ; $i < $config->get_ps_head_skip ; $i++)
  {
    shift(@procs);
  }
  for (my $i = 0 ; $i < $config->get_ps_tail_skip ; $i++)
  {
    pop(@procs);
  }
  # Begin regex parsing.
  my $memtotal = 0;
  if ($config->get_mem_is_percentage() == 0)
  {
    # Calculate memory percentage based on total system ram versus
    # value returned by ps output. 
    my $cmd = $config->get_total_system_memory_command();
    $memtotal = `$cmd`;
    my $regex = $config->get_total_system_memory_regex();
    if ($regex ne '')
    {
      if ($memtotal =~ m/$regex/)
      {
        $memtotal = $1;
      }
    }
    my $unit = $config->get_total_system_memory_unit();
    $memtotal *= 1024 if ($unit eq 'K');
    $memtotal *= (1024^2) if ($unit eq 'M');
    $memtotal *= (1024^3) if ($unit eq 'G');
    $memtotal *= (1024^4) if ($unit eq 'T');
    $memtotal *= (1024^5) if ($unit eq 'Z');
  }  
  foreach my $procline(@procs)
  {
    $sink->start_new_process();
    my ($user,$pid,$cpu,$mem,$name);
    my $ps_regex_user = $config->get_ps_regex_user();
    my $ps_regex_pid = $config->get_ps_regex_pid();
    my $ps_regex_cpu = $config->get_ps_regex_cpu();
    my $ps_regex_mem = $config->get_ps_regex_mem();
    my $ps_regex_name = $config->get_ps_regex_name();    
    $procline =~ m/$ps_regex_user/ and $user = $1;
    defined($user) or ps_parse_error('user',$procline,$ps_regex_user);
    $procline =~ m/$ps_regex_pid/ and $pid = $1; 
    defined($pid) or ps_parse_error('pid',$procline,$ps_regex_pid);
    $procline =~ m/$ps_regex_cpu/ and $cpu = $1;
    defined($cpu) or ps_parse_error('cpu',$procline,$ps_regex_cpu);
    $procline =~ m/$ps_regex_mem/ and $mem = $1; 
    if ($config->get_mem_is_percentage() == 0)
    {
      if ($memtotal == 0)
      {
        $out->error(0,"Invalid memtotal, please doublecheck 
          total_system_memory_command, total_system_memory regex configurations");
      }
      $mem = ceil((($mem*1024)/$memtotal)*100);
    }
    defined($mem) or ps_parse_error('mem',$procline,$ps_regex_mem);
    $procline =~ m/$ps_regex_name/ and $name = $1; 
    defined($name) or ps_parse_error('name',$procline,$ps_regex_name);
    # if both cpu and mem are zero, we ignore the process.
    if (($cpu == 0) and ($mem == 0))
    {
      next;
    }
    $out->message(1,"user: $user | pid: $pid | cpu: $cpu | mem: $mem | name: $name\n");
    $sink->process_user($user);
    $sink->process_pid($pid);
    $sink->process_cpu($cpu);
    $sink->process_mem($mem);
    $sink->process_name($name);    
    $sink->run_output();    
  }
}

# Entry point. ----------------------------------------------------------------

$out = topper::output->new();
$config = topper::config->new($out);
$config->load_config("../conf/topper.conf");
$db = topper::database->new($config);
$db->connect();
$sink = topper::datasink->new($config,$db,$out);
get_proc_info();
$db->disconnect();
