#!/usr/bin/perl -w

use strict;
use Socket;


# Define subroutines

sub show_help;
sub print_entry;


# Define variables

my (@playerlist, @serverlist, @maplist, %servers, %rank);
my ($home, $arg, $mode) = ($ENV{'HOME'}, "", 0);
my ($score, $server) = (0, "");


# Parse any command line arguments...

while (@ARGV)
{
  $arg = shift (@ARGV);
  
  show_help,                exit if $arg =~ /^-(-h(e(lp?)?)?|h)$/;
  $mode=1,                  next if $arg =~ /^-(-p(l(a(y(er?)?)?)?)?|p)$/;
  $mode=2,                  next if $arg =~ /^-(-s(e(r(v(er?)?)?)?)?|s)$/;
  $mode=3,                  next if $arg =~ /^-(-m(ap?)?|m)$/;

  parse_error ($arg),       exit if $arg =~ /^-/;
  
  push (@playerlist, $arg), next if $mode == 1;
  push (@serverlist, $arg), next if $mode == 2;
  push (@maplist, $arg),    next if $mode == 3;
}



# Find/Parse configuration file

if (open (CONFIGFILE, "$home/.var/config/x/xpilot/metapilot") ||
    open (CONFIGFILE, "$home/.metapilot") ||
    open (CONFIGFILE, "$home/.metapilotrc"))
{
  while (<CONFIGFILE>)
  {
    /^\s*(player|PLAYER|Player)\s*:\s*(.*)$/ && push @playerlist, $2;
    /^\s*(server|SERVER|Server)\s*:\s*(.*)$/ && push @serverlist, $2;
    /^\s*(map|MAP|Map)\s*:\s*(.*)$/ && push @maplist, $2;
  }
  
  close (CONFIGFILE);
}


for (my ($count)=0; $count<=$#serverlist; ++$count)
{
  $serverlist[$count] =~ s/\./\\./g;
}


if ($ENV{'DEBUG'})
{
  print "Players: ".join (', ', @playerlist)."\n";
  print "Servers: ".join (', ', @serverlist)."\n";
  print "Maps: ".join (', ', @maplist)."\n\n";
}



# Open up a connection to the metaserver; sort the servers listed there...

my ($iaddr, $paddr);

$iaddr = inet_aton ("meta.xpilot.org")  ||
  die "Unable to locate metaserver: $!\n";

$paddr = sockaddr_in (4401, $iaddr);

socket (METASERVER, PF_INET, SOCK_STREAM, getprotobyname ("tcp")) ||
  die "Unable to create socket: $!\n";

connect (METASERVER, $paddr) || 
  die ("Unable to connect to metaserver: $!\n");

while (<METASERVER>)
{
  chomp;
  
  my ($score, $count) = 0, 0;

  my ($version, $server, $port, $num_players, $map, $size, $written_by,
      $status, $max_players, $fps, $player_list, $sound, $uptime,
      $num_team_bases, $timing, $ipaddress, $num_free_bases,
      $num_queued_players) = split (':');

  next if $servers{"$server:$port"};
  $servers{"$server:$port"} = $_;

  for ($count=0; $count<=$#serverlist; ++$count)
  {
    ++$score if $server =~ /$serverlist[$count]/i;
    ++$score if $server =~ /\b$serverlist[$count]\b/i;
    ++$score if $server =~ /^$serverlist[$count]$/i;
  }

  for ($count=0; $count<=$#playerlist; ++$count)
  {
    ++$score if $player_list =~ /$playerlist[$count]/i;
    ++$score if $player_list =~ /\b$playerlist[$count]\b/i;
    ++$score if $player_list =~ /(^|,)$playerlist[$count]=/i;
  }

  for ($count=0; $count<=$#maplist; ++$count)
  {
    ++$score if $map =~ /$maplist[$count]/i;
    ++$score if $map =~ /\b$maplist[$count]\b/i;
    ++$score if $map =~ /^$maplist[$count]$/i;
  }

  ++$score if $player_list;
  $score-=9 if ($map =~ /(The (Newbie )?Globe|Random Land|CloudScape)/);

  printf "%-30s %d\n", $server, $score  if $ENV{'DEBUG'};
  
  $rank{$score} .= ($rank{$score} ? "," : "")."$server:$port";
}

close (METASERVER);



# Print out the servers ranked by score...

foreach $score (sort (keys (%rank)))
{
  next if $score < 1;
  foreach $server (split (',', $rank{$score}))
  {
    print_entry ($servers{$server});
  }
}

exit;



# Online help...

sub show_help
{
    print <<EOT;
Usage: $0 [OPTION]...

  -h, -\-help,               display this message
  -p, -\-player PLAYERLIST   watch out for player(s)
  -s, -\-server SERVERLIST   watch out for server(s)
  -m, -\-map MAPLIST         watch out for map(s)

EOT
}


# More online help (for people that can't get the options right)

sub parse_error
{
  my ($arg) = @_;
  print "$0: illegal option '$arg'\n";
  print "Try \'$0 --help\' for more information.\n";
}


# Display routine...

sub print_entry
{
  my ($line) = @_;

  my ($version, $server, $port, $num_players, $map, $size, $written_by,
      $status, $max_players, $fps, $player_list, $sound, $uptime,
      $num_team_bases, $timing, $ipaddress, $num_free_bases,
      $num_queued_players) = split (':', $line);  

  
  # Print the servername...
  
  printf "%-28s  %s\n",
    $server.($port == 15345 ? "" : ":$port"), 
    $map.($sound=~/yes/ ? " (sound)" : ""),

  
  # Print the players...

  my (@players) = split (",", $player_list);

  while (@players)
  {
    my ($name,$client) = split ("=", shift (@players));

    # Remove the team from the end of the client
    $client =~ s/\{([0-9]+)\}$//; 
    my ($team) = ($1 ? "Team $1" : "");

    # Remove spaces and trailing junk
    $client =~ s/[ ].*//;

    if ($team)
    {
      printf "  %-15s  %-7s  %s\n",
        $name,
        $team,
        $client;
    }
    else
    {
      printf "  %-15s  %s\n",
        $name,
        $client;
    }
   }

  print "\n";
}
