#!/usr/local/bin/perl -w

use strict;
use Log::Log4perl qw(:easy);
use DB_File;
use Tk;

my %sudo_programs = map { $_ => 1 } 
                    qw(synaptic);

my @misc_paths = qw(/usr/sbin);

my($home) = glob "~";
my $spotty_dir = "$home/.spotty";

#Log::Log4perl->easy_init();

if(! -d $spotty_dir) {
  mkdir $spotty_dir, 0755 or
    LOGDIE "Cannot mkdir $spotty_dir ($!)";
}

  # Init database
my %DB_FILE;
tie %DB_FILE, 
    "DB_File", "$spotty_dir/db_file.dat" 
        or LOGDIE "$!";

  # Application window
my $top = MainWindow->new();
$top->geometry("-0+0");

my($input, $first_match, $label_text);

my $label = $top->Label(
  -textvariable => \$label_text, 
  -width        => 20 );

my $entry = $top->Entry( 
  -textvariable    => \$input, 
  -validatecommand => \&validate,
  -validate        => "key",
);

$entry->pack( -side => "left" );
$label->pack( -side => "left" );

$entry->bind("<Control-Key-q>", \&bail);
$entry->bind("<Return>", 
             sub { launch($input) });
$entry->bind("<Tab>", \&complete);

$entry->focus();
MainLoop;

###########################################
sub bail {
###########################################

  $top->destroy();
}

###########################################
sub validate {
###########################################
  my($got) = @_;
  $label_text = join "\n", matches($got);
  return 1;
}

###########################################
sub matches {
###########################################
  my($got) = @_;

  my @all = sort keys %DB_FILE;
  my @matches = grep { /^$got/ } @all;
  if(@matches) {
      $first_match = $matches[0];
  } else {
      $first_match = undef;
  }
  return @matches;
}

###########################################
sub complete {
###########################################

  $input = $first_match;
  launch($input);
}

###########################################
sub launch {
###########################################
  my($program) = @_;

  my $path = path_search( $program );

  LOGDIE "$program not found ",
         "in path ($ENV{PATH})" unless
             defined $path;

  $DB_FILE{ $program }++ if defined $path;
  DEBUG "Launching $path";
  untie %DB_FILE;
  if(exists $sudo_programs{ $program } ) {
      exec "xterm", "-e", "sudo", "$path";
  } else {
      exec $path;
  }
  LOGDIE "exec $path failed: $!";
}

###########################################
sub path_search {
###########################################
  my($program) = @_;

  DEBUG "PATH is $ENV{PATH}";

  for my $path ( split(/:/, $ENV{PATH}), 
                 @misc_paths ) {
      if(-x "$path/$program") {
          DEBUG "$program found in $path";
          return "$path/$program";
      }
  }

  ERROR "$program not found";
  return undef;
}
