#!/usr/bin/perl -w

# $Id: dasscm 203 2005-12-05 10:50:40Z joergs $

use strict;

use Env qw($DASSCM_PROD $DASSCM_REPO $USER $DASSCM_USER $DASSCM_PW);
use Cwd;
use File::Basename;
use File::stat;
use File::Path;
use File::Copy;
#use POSIX qw/getpgrp tcgetpgrp/;
use Getopt::Long;

#####################################################################
#
# global
#
my $SVN = "svn ";
my $svnOptions = "";
# command line options get stored in options hash
my %options = (); 
# subcommand, that gets executed (add, commit, ...)
my $command;

#####################################################################
#
# util functions
#
sub usage()
{
	print "usage: dasscm <subcommand> [options] [args]\n";
	print "\n";
	print "dasscm is intended to help versioning configuration files\n";
	print "\n";	
	print "Available subcommands:\n";
	print "   add <filename>\n";
	print "   commit <filename>\n";
	print "   diff <filename>\n";
	print "   help <subcommand>\n";
	print "\n";	
	print "preperation:\n";
	print "check out the configuration repository, e.g.\n";
	print "svn checkout --no-auth-cache --username USERNAME https://dass-it.de/svn/lvermgeo/technical/config/\n";
	print "environment variables DASSCM_REPO, DASSCM_PROD and DASSCM_USER are evaluated.\n";
	print "\n";
}

sub check_env()
{
	# DASSCM_PROD
	if ( ! $DASSCM_PROD ) {
		$DASSCM_PROD = "/";
	}
	print "DASSCM_PROD: ".$DASSCM_PROD."\n";
	if ( ! -d $DASSCM_PROD ) {
		die "DASSCM_PROD is not set to a  directory.\n";
	}
		
	# DASSCM_REPO
	if ( ! $DASSCM_REPO ) {
		die "Envirnonment variable DASSCM_REPO not set.\nSet DASSCM_REPO to the directory of the versioning system checkout for this machine.\n";
	}
	print "DASSCM_REPO: ".$DASSCM_REPO."\n";
	if ( ! -d $DASSCM_REPO ) {
		die "DASSCM_REPO must be is not set to the directory of the versioning system checkout for this machine.\n";
	}
	
	# User settings
	# user root is not allowed for checkins.
	# if user is root, DASSCM_USER has to be set, 
	# otherwise USER can be used
	if ( "$USER" eq "root" ) {
		if ( ! $DASSCM_USER ) {
			die "Envirnonment variable DASSCM_USER not set.\nSet DASSCM_USER to your subversion user account.\n";
		} 
		$svnOptions .= " --no-auth-cache "
	} elsif ( ! $DASSCM_USER ) {
		$DASSCM_USER=$USER;
	}
	#$svnOptions .= " --username $DASSCM_USER "	
}


sub check_parameter(@)
{
}

sub get_filenames(@)
{
	my $filename_prod = $_[0];
	if ( !($filename_prod =~ m/^\//) ) {
		$filename_prod = cwd()."/".$filename_prod;
	}

	-r $filename_prod or die "$filename_prod is not accessable";
	
	# TODO: dirname buggy: eg. "/etc/" is reduced to "/",
	#	"/etc" is used as filename
	my $dirname_prod = dirname($filename_prod);
	chdir $dirname_prod or die $!;
	$dirname_prod = cwd();
	my $basename = basename($filename_prod);
	
	print "dir: ".$dirname_prod."\n";
	print "fn: ".$basename."\n";
		
	my $dirname_repo = $DASSCM_REPO."/".$dirname_prod;
	my $filename_repo = "$dirname_repo/$basename";
	
	return ($basename,$dirname_prod,$dirname_repo,$filename_prod,$filename_repo);
}


sub run_command
{
  my $command = shift;

  #print "executing command: " . $command . "\n";

  open(RESULT, $command . ' 2>&1 |' );
  my @result = <RESULT>;
  close(RESULT);
  my $retcode = $?>>8;

  #print @result;
  #if( $retcode ) { print "return code: " . $retcode . "\n"; }

  return($retcode, @result);
}



sub run_interactive
{
	system( @_ );
	if ($? == -1) {
		printf "failed to execute: $!\n";
	} elsif ($? & 127) {
		printf "child died with signal %d, %s coredump\n",
			($? & 127),  ($? & 128) ? 'with' : 'without';
	} elsif( $? >> 8 != 0 ) {
			printf "child exited with value %d\n", $? >> 8;
	}
	return( $? >> 8 );
}


#####################################################################
#
# functions

sub help(;@)
{
	if( @_ == 0 ) {
		usage();
	} else {
		print "help for @_: ...\n";
	}
}


sub login(@)
{
	check_parameter(@_,1);
	#check_env();
	
        #$DASSCM_USER $DASSCM_PW
        my $output_user = "";
        if( $DASSCM_USER ) {
            $output_user = " ($DASSCM_USER)";
        }
            
        print "Enter DASSCM user name",$output_user,": ";
        my $input_user = <STDIN>;
        chomp($input_user);
        print "Enter DASSCM user password: ";
        my $input_pw = <STDIN>;
        chomp($input_pw);

        # TODO: test svn login

        $ENV{'DASSCM_USER'} = $input_user;
        $ENV{'DASSCM_PW'} = $input_pw;

        exec( "bash" ) or die "can't login";

}

#
# add (is used for command add and commit)
#
sub add(@)
{
	check_parameter(@_,1);
	check_env();
	
	(my $basename, my $dirname_prod, my $dirname_repo, my $filename_prod, my $filename_repo) = get_filenames($_[0]);
		
	if( $command eq "add" ) {
		mkpath($dirname_repo);
	}
	
	# update complete repository
	my $retcode = run_interactive( "$SVN update $svnOptions $DASSCM_REPO" );

	copy( $filename_prod, $filename_repo ) or die $!;
	
	if( $command eq "add" ) {
		# already checked in?
		chdir($DASSCM_REPO);
		# also add the path to filename.
		for my $dir (split('/', $dirname_prod) ) {
			if( $dir ) {
				run_command( "$SVN add --non-recursive $dir" );
				chdir $dir;
			}
		}
		run_command( "$SVN add $basename" );
	}
	
	if( $options{'message'} ) {
		$svnOptions .= " --message \"$options{'message'}\" ";
	}

	# commit calls $EDITOR. uses "system" here, to display output
	$retcode = run_interactive( "$SVN commit $svnOptions --username $DASSCM_USER $DASSCM_REPO" );

	print $filename_prod."\n";
	print $dirname_repo."\n";
}


sub blame(@)
{
	check_parameter(@_,1);
	check_env();
	
	(my $basename, my $dirname_prod, my $dirname_repo, my $filename_prod, my $filename_repo) = get_filenames($_[0]);

	my $retcode = run_interactive( "$SVN blame $svnOptions $filename_repo" );
}



sub diff(@)
{
	check_parameter(@_,1);
	check_env();
	
	(my $basename, my $dirname_prod, my $dirname_repo, my $filename_prod, my $filename_repo) = get_filenames($_[0]);
		
	#print "$basename,$dirname_prod,$dirname_repo\n";

	(my $rc_update, my @result)=run_command( "$SVN update $filename_repo" );
	if( $rc_update != 0 ) {
		print @result;
		die;
	}
	
	(my $rc_diff, my @diff)=run_command( "diff $filename_repo $filename_prod" );
	print @diff;	
}

#####################################################################
#
# main
#

my $number_arguments = @ARGV;

if ($number_arguments > 0) {
	# get subcommand and remove it from @ARGV
	$command = $ARGV[0];
	shift @ARGV;


	# get command line options and store them in options hash
	my $result = GetOptions ( \%options, 'message=s' );
	# print options
	foreach my $option (keys %options) {
		print $option.": ".$options{$option}."\n";
	}

	$_=$command;
	if (m/help/i) {
		help(@ARGV);
	} elsif (m/login/i) {
		# rewrite command. just to make sure
		login( @ARGV );
	} elsif (m/add/i) {
		# rewrite command. just to make sure
		$command = "add";
		add( @ARGV);
	} elsif (m/commit/i) {
		# rewrite command. just to make sure	
		$command = "commit";	
		add( @ARGV);
	} elsif (m/blame/i) {
		blame(@ARGV);			
	} elsif (m/diff/i) {
		diff(@ARGV);
	} elsif (m/activate/i) {
		activate(@ARGV);
	} else {
		usage();
		check_env();
	}
        # login
        # commitall
        # revert
        # status (chkconf)
}
