#!/usr/bin/perl

BEGIN {
use lib 'd:/Programs/Perl/lib';
#use lib '/home/tkamiya/bin/lib';
my $BaseDir = $ENV{'TkPerlDir'};
#print "\nBaseDir: $BaseDir\n";
@INC = ("$BaseDir/lib", "$BaseDir/VNL", "d:/Programs/Perl/lib", @INC);
}

use strict;
use Cwd;

use Utils;

my $ProgName = "xvasp";
my $RootDir = ($^O eq 'MSWin32')? "d:\\Programs\\Perl" : $ENV{TkPerlDir};
my $HomeDir = Deps::MakePath($RootDir, 'VASP');
my $Shell   = ($^O eq 'MSWin32')? "cmd.exe" : "/bin/bash";
my $Editor  = ($^O eq 'MSWin32')? "D:\\Programs\\Editor\\WZEditor6\\wzeditor.exe" : "kedit.exe";
my $Viewer  = ($^O eq 'MSWin32')? "D:\\Programs\\X\\VESTA\\VESTA.exe" : "vesta.exe";

my @CommandList = (
	{Name => "MkDOS",     Cmd => "perl $HomeDir/VASP.pl --Action=MakeDOSCSV --Width=0.1 --IgnoreZero=0 ./DOSCAR DOS-up.csv DOS-dn.csv"},
	{Name => "MkFS",      Cmd => "perl $HomeDir/VASPFS.pl"},
	{Name => "MkSummary", CmdWin => "$HomeDir/MkSummary.bat", CmdUnix => "$HomeDir/MkSummary.sh"},
	{Name => "cat",       Cmd => "{cat}"},
	{Name => "view",      Cmd => "{view}"},
	{Name => "edit",      Cmd => "{edit}"},
	{Name => "ls",        CmdWin => "dir /W .\\%a", CmdUnix => "ls ./%a"},
	{Name => "rls",       CmdWin => "dir /W $HomeDir\\%a", CmdUnix => "ls $HomeDir/%a"},
	{Name => "ps",        CmdWin => "c:\\cygwin\\bin\\ps", CmdUnix => "ps ax"},
	{Name => "cd",        Cmd => "{cd}"},
	{Name => "pwd",       Cmd => "{pwd}"},
	{Name => "pushdir",   Cmd => "{pushdir}"},
	{Name => "popdir",    Cmd => "{popdir}"},
	{Name => "listdir",   Cmd => "{listdir}"},
	{Name => "rsysd",     Cmd => "perl $RootDir/rsys/rsysd.pl"},

	{Name => "bye"}
	);

my @DirStack = (cwd());

if($ARGV[0] eq '') {
	&List();
	&Console();
}
else {
	&Execute($ARGV[0]);
}

exit;

sub Console
{
	while(1) {
		my $dir = cwd();
		print "\n[$ProgName] $dir >>";
		my $line = <>;
		$line =~ s/^\s+//;
		$line =~ s/\s+$//;

		if($line =~ /^[a-zA-Z]:$/) {
			$line = "cd $line";
		}

		my ($cmd, $args) = ($line =~ /^(\S+)\s+(.*)$/);
		$cmd = $line if(!defined $cmd);
		my $cmd0 = $cmd;
		$cmd = lc $cmd;
#print "line: [$cmd]\n";

		if($cmd eq 'bye' or $cmd eq 'quit' or $cmd eq 'exit') {
			exit 0;
		}
		if($cmd eq '' or $cmd eq '?' or $cmd eq 'help' or $cmd eq 'list') {
			&List();
		}
		elsif($cmd eq '!' or $cmd eq 'sh') {
			system($Shell);
		}
		else {
			&Execute($cmd0, $args);
		}
	}
}

sub Execute
{
	my ($cmd, $cmdargs) = @_;
#print "cmdargs: [$cmdargs]\n";

	my $idx = &FindIndex($cmd);
	my $Command = $CommandList[$idx]->{Cmd};
	if(!defined $Command) {
		if($^O eq 'MSWin32') {
			$Command = $CommandList[$idx]->{CmdWin};
		}
		else {
			$Command = $CommandList[$idx]->{CmdUnix};
		}
	}
	$Command =~ s/%a/$cmdargs/g;

	my ($key, $args) = ($Command =~ /^\{(\S+?)\}(.*)$/);
	if(defined $key) {
		if($key eq 'view') {
			&ExecuteExternalCommand($Viewer, $cmdargs, 1);
		}
		elsif($key eq 'edit') {
			&ExecuteExternalCommand($Editor, $cmdargs, 1);
		}
		elsif($key eq 'cat') {
			$cmdargs = &FindFilePath($cmdargs);
			my $cmd = ($^O eq 'MSWin32')? 'type' : 'cat';
			&ExecuteExternalCommand($cmd, $cmdargs, 0);
		}
		elsif($key eq 'cd') {
			if($cmdargs eq '') {
				$cmdargs = $DirStack[0];
			}
			if(!chdir($cmdargs)) {
				print "Error: Can not change working director to [$cmdargs]\n";
			}
			print "Working dir: ", cwd(), "\n";
		}
		elsif($key eq 'pwd') {
			print "Working dir: ", cwd(), "\n";
		}
		elsif($key eq 'pushdir') {
			my $dir = ($cmdargs eq '')? cwd() : $cmdargs;
			my $ns = @DirStack;
			if($dir ne $DirStack[$ns-1]) {
				push(@DirStack, $dir);
			}
			&ListDirectory();
		}
		elsif($key eq 'popdir') {
			my $dir = (@DirStack == 1)? $DirStack[0] : pop(@DirStack);
			chdir($dir);
			print "Working dir: ", cwd(), "\n";
			&ListDirectory();
		}
		elsif($key eq 'listdir') {
			&ListDirectory();
		}
		else {
			print("Error: Invalid command [$Command]\n");
		}
	}
	elsif($Command) {
print "Execute [$Command]\n";
		system($Command);
	}
	else {
		my ($cmd0, $args) = ($cmd =~ /^(\S+)\s+(.*)$/);
		{
			$cmd0 = $cmd if(!defined $cmd0);
			$cmd0 = &FindFilePath($cmd0);
			$cmd = "$cmd0 $args";
print "Execute [$cmd]\n";
			if(!system($cmd) > 32) {
				print("Error: Can not execute [$cmd]\n");
			}
		}
	}
}

sub FindFilePath
{
	my ($fname) = @_;

#print "args [$fname]\n";
	return $fname if(-f $fname);
	my $path = &FindExecutablePath($fname, [$HomeDir]);
	return $path;# if($path ne '');
#	return Deps::MakePath($HomeDir, $fname);
}

sub FindExecutablePath
{
	my ($fname, $dirlist) = @_;
	
	my $sep = ($^O eq 'MSWin32')? ';' : ':';
	my @dirs = (Utils::Split($sep, $ENV{PATH}), @$dirlist);
	for(my $i = 0 ; $i < @dirs ; $i++) {
		my $d = $dirs[$i];
#print "$i: [$d]\n";
		foreach my $ext ('', '.exe', '.com', '.bat', '.wsh', '.pl', '.sh') {
			my $path = Deps::MakePath($d, "$fname$ext");
			return $path if(-f $path);
		}
	}
	return undef;
}

sub ListDirectory
{
	print "Directory list in stack:\n";
	for(my $i = 0 ; $i < @DirStack ; $i++) {
		print "  $i: $DirStack[$i]\n";
	}
}

sub ExecuteExternalCommand
{
	my ($cmd, $cmdargs, $IsBackground) = @_;

#print "args [$cmd][$cmdargs]\n";
	$cmdargs = &FindFilePath($cmdargs);
	if($IsBackground) {
		$cmd = ($^O eq 'MSWin32')? "start $cmd $cmdargs" : "$cmd $cmdargs &";
	}
	else {
		$cmd = "$cmd $cmdargs";
	}
print "$cmd\n";
	system($cmd);
}

sub FindIndex
{
	my ($cmd) = @_;

	if($cmd =~ /^\d+$/) {
		return $cmd if(0 <= $cmd and $cmd < @CommandList);
		return -1;
	}

	$cmd = lc $cmd;
	for(my $i = 0 ; $i < @CommandList ; $i++) {
		return $i if(lc $CommandList[$i]->{Name} eq $cmd);
	}
	return -1;
}

sub List
{
	for(my $i = 0 ; $i < @CommandList ; $i++) {
		printf("%2d:%-8s  ", $i, $CommandList[$i]->{Name});
		print("\n") if(($i+1) % 6 == 0);
	}
	print "\n" if(@CommandList % 6 != 0);
}
