#!/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;
}