#!/usr/bin/env perl5.6.0

use lib "/usr/lib/perl5/site_perl";
use lib "/usr/lib/perl5/site_perl/i386-linux/auto/Term/ReadKey";
use Getopt::Long;
use bli;

# this hash is broken down for readability and for the help system
my %categories = (
		  spinfs => {
		      mkdir => [\&spin_mkdir, "create a new directory"],
		      rmdir => [\&spin_rmdir, "remove a directory"],
		      ls => [\&spin_readdir, "similar to the Unix ls"],
		      ls2 => [\&spin_readdir2, "print direcotry entries and their fids"],
		      lsf => [\&spin_readdir_fid, "ls a given fid rather than a path"],
		      lookup => [\&spin_lookup_fid, "lookup a fid for a given path"], 
		      getacl => [\&spin_getacl, "get the acl for a file"],
		      clearacl => [ \&spin_clearacl, "clear the acl for a file"],
		      getattr => [\&spin_getattr, "get the attributes of a file"],
		      setattr => [\&spin_setattr, "set the attributes on a file"],
		      create => [\&spin_create, "create a file"],
		      write => [\&spin_write, "write to a file"],
		      read => [\&spin_read, "read from a file"],
		      readfile => [\&spin_read_file, "read a whole file(up to 8k)"],
		      readlink => [\&spin_readlink, "read a symlink"],
		      readmp => [\&spin_readmp, "read a mountpoint"],
		      shutdown => [\&spin_shutdown, "forces the log"],
		      mv => [\&spin_rename, "rename a file"],
		      rm => [\&spin_remove, "remove a file"],
		      rm2 => [\&spin_remove2, "direct spinfs call to remove"],
		      ln => [\&spin_link, "create a link"],
		      sln => [\&spin_symlink, "create a symlink"],
		      setuid => [\&spin_setUid, "set the default uid"],
		      setgid => [\&spin_setGid, "set the default gid"],
		      setdomain => [\&spin_setDomain, "set the default domain"],
		      setids => [\&spin_setIds, "set all of the default ids"],
		      getids => [\&spin_getIds, "get all of the default ids"],
		      getlpuuid => [\&spin_get_lpuuid, "print the UID for the given LP"],
		  },
		  volume => {
		      vcreate => [\&spin_createvolume, "create a volume"],
		      vucreate => [\&spin_createuvolume],
		      vdelete => [\&spin_deletevolume, "delete a volume"],
		      vclone => [\&spin_clonevolume, "clone a volume"],
		      vgetattr => [\&spin_getvattr, "get volume attributes"],
		      vsetattr => [\&spin_setvolattr, "set a volume attribute via the how bit"],
		      vsetmount => [\&spin_setmounted, "set the mountpoint"],
		      vsetvs => [\&spin_setvvs],
		      vsetmin => [\&spin_setvminquota, "set the min quota"],
		      vsetmax => [\&spin_setvmaxquota, "set the max quota"],
		      vsetonline => [\&spin_setonline, "set a volume online"],
		      vsetoffline => [\&spin_setoffline, "set a volume offline"],
		      vclearrestrictedACL => [\&spin_clear_restrictedACL, "clear a restricted ACL on a volume"],
		      vsetrestrictedACL => [\&spin_set_restrictedACL, "set a restricted ACL on a volume"],
		      vquery => [\&spin_queryvol],
		      vgetquotas => [\&spin_getvquotas, "get the volume quotas"],
		      vsetname => [\&spin_setvname, "set the volume name"],
		      vsetid => [\&spin_setvid, "set the volume id"],
		      vsetidname => [\&spin_setvidname, "set the volume id and name"],
		      cmt => [\&spin_createmount, "create a mountpoint"],
		      vadd => [\&spin_addvolume],
		  },
		  misc => {
		      exit => [sub { exit; }, "exit the program"],
		      quit => [sub { exit; }, "exit the program"],
		      connect => [\&gethandle],
		      pvgetattr => [\&print_getvattr],
		      phead => [\&print_header],
		      pfoot => [\&print_footer],
		      debugon => [\&spin_debugon, "turn SpinFS debugging on"],
		      debugoff => [\&spin_debugoff, "turn SpinFS debugging off"],
		      verboseon => [sub { $options{verbose} = 1; 0; }, "set the verbosity flag"],
		      verboseoff => [sub { $options{verbose} = 0; 0; }, "unset the verbosity flag"],
		      setvol => [\&set_volname],
		      readfromfile => [\&readfromfile],
		      rfile => [\&readfromfile],
		      rf => [\&readfromfile],
		      alias => [\&alias],
		      evaluate => [\&evaluate],
		      startpt => [\&start_profiletimer],
		      stoppt => [\&stop_profiletimer],
		      clearpt => [\&clear_profiletimer],
		      printpt => [\&print_profiletimer],
		      cd => [$main::path->ChdirRef, "chdir to the given directory", $path],
		      pwd => [$main::path->PwdRef, "print the current working directory", $path],
		      help => [\&internalhelp, "This command"],
		  },
		  vldb => {
		      vldb_mount_lookup => [\&vldb_mount_lookup],
		      vldb_root_lookup => [\&vldb_root_lookup],
		      vldb_vfsid_lookup => [\&vldb_vfsid_lookup],
		      vldb_addvfs => [\&vldb_addvfs],
		      vldb_delvfs => [\&vldb_delvfs],
		      vldb_dump_maps => [\&vldb_dump_maps],
		      vldb_record_lookup => [\&vldb_record_lookup],
		      vldb_list_vfsid_updates => [\&vldb_list_vfsid_updates],
		      vldb_dblade_lp_update => [\&vldb_dblade_lp_update]
		  },
		  );

# now make a more useful internal version of this hash
# and save some values for the help system
my ($columns, $maxcmdlen);
our %cmds;
my @cmds; # for readline.pm
$maxcmdlen = 0;
foreach my $category (keys %categories) {
    foreach my $cmd (keys %{$categories{$category}}){
	push(@cmds, $cmd);
	$cmds{$cmd} = ${$categories{$category}}{$cmd};
	if (length($cmd) > $maxcmdlen){
	    $maxcmdlen = length($cmd);
	}
    }
}
$columns = int(80/($maxcmdlen+2));

%options = (
	    host => "localhost",
	    port => 7700,
	    vfsid => 1024,
	    );

#print "Inc = ", join(',', @INC), "\n";

my $sitelist = "/var/spinmgmt/rdb/_sitelist";
if (-f $sitelist){
    # We have a sitelist file, perhaps we should get our local cluster IP
    # address from there......
    my $hostname = `/bin/hostname`;
    chomp $hostname;
    open(IF, $sitelist);
    while(<IF>){
	next unless /$hostname/;
	chomp;
	my @data = split;
	$data[4] =~ s/\"//g;
	$options{host} = $data[4];
	last;
    }
    close(IF);
}
	    
GetOptions (\%options, 'verbose', 'host=s', 'port=i', 'vfsid=i', 'help');
$currenthost = $options{host};
$| = 1;

Help() if ($options{help});
gethandle(undef, $options{vfsid}, $options{host}, $options{port});
if (@ARGV){
    exit handlecmd(@ARGV);
}
handleinit();	


eval "use Term::ReadLine";    
if ($@){
    # Error inmporting readline, do braindead approach
    while (1){
	print "bli ($currenthost) => ";
	$_ = <STDIN>;
	chomp;
	my @cmd = split;
	if (handlecmd(@cmd) == -6868){
	    if ($cmd[0] =~ /\?/){
		internalhelp();
	    } elsif ($cmd[0] ne "") {
		print "Unknown command: ". join(' ', @cmd). "\n";
	    }
	}
    }
} else {
    my $term = new Term::ReadLine;
    &readline::rl_set('TcshCompleteMode', 'On');
    readline::rl_basic_commands(@cmds);
    while (defined ($_ = $term->readline("bli ($currenthost) => "))){
 	chomp;
#	$term->addhistory($_) if /\S/;
	my @cmd = split;
	if (handlecmd(@cmd) == -6868){
	    if ($cmd[0] =~ /\?/){
		internalhelp();
	    } elsif ($cmd[0] ne "") {
		print "Unknown command: ". join(' ', @cmd). "\n";
	    }
	}
    }
}

sub getvfsrfid {
    my $vfsid = shift;

    return "$vfsid.27.0";
}


sub internalhelp {
    my $long = undef;
    $long = 1 if (@_); # this was the command line help command if any options present
    foreach my $category (sort keys %categories) {
	my $colnum = 0;
	print "$category\n";
	foreach my $cmd (sort keys %{$categories{$category}}){
	    print "\t" if ($long || !$colnum);
	    if ($long) {
		printf("%-".($maxcmdlen+2)."s", $cmd);
		print "@{$cmds{$cmd}}[1]\n";
	    } else {
		$colnum++;
		if ($colnum >= $columns){
		    print "$cmd\n";
		    $colnum = 0;
		} else {
		    printf("%-".($maxcmdlen+2)."s", $cmd);
		}
	    }
	}
	print "\n" if (!$long && colnum);
    }
}

sub Help {
    print <<"xxENDxx";
$0  Usage:
    [-host <hostname>] (defaults to the local cluster port found in the mgmt files)
    [-port RF port] (defaults to 7700)
    [-vfsid VFS id] (defaults to 1024)
    [-verbose]
    [-help]

xxENDxx

    exit(0);
}
