#!/usr/bin/perl -w
# -*- perl -*-
use P4CGI ;
use strict ;
#
#################################################################
#  CONFIGURATION INFORMATION 
#  All config info should be in P4CGI.pm
#
#################################################################
#
#  P4 depot tree browser
#
#################################################################

###
### Handle file spec argument
###
				# * Get path from argument
my $fspc = &P4CGI::cgi()->param("FSPC") ;
$fspc =~ s/\.\.\.$// if defined $fspc ;
$fspc =  &P4CGI::htmlEncode($fspc) ;

				# Find out if we have multiple depots
my @depots ;
my $err2null = &P4CGI::REDIRECT_ERROR_TO_NULL_DEVICE() ;
&P4CGI::p4call(\@depots,"dirs \"//*\" $err2null") ;
my $moreThanOneDepot = (@depots > 1) ;
				# Set server ROOT
my $ROOT ;
if($moreThanOneDepot) {
    $ROOT = "/" ;
}
else {
    $ROOT = "$depots[0]/" ;
    $ROOT =~ s|//|/|g ;
} ;
				# canonicalize to either "/.../" or "/"
$fspc = $ROOT unless defined $fspc ;
$fspc = "/$fspc/" ;
while($fspc =~ s|//|/|) {} ;
				# Find out if we are at root
my $weAreAtROOT = ($fspc eq $ROOT) ;
if($weAreAtROOT) { &P4CGI::cgi()->delete("FSPC") ; } ;

###
### handle "Hide deleted files" argument
###

				# * Get HIDEDEL argument (Hide deleted files)
my $hidedel = P4CGI::cgi()->param("HIDEDEL") ;
if(&P4CGI::HIDE_DELETED() == 0) {
    $hidedel = "NO" unless defined $hidedel and $hidedel eq "YES" ;    
}
else {
    $hidedel = "YES" unless defined $hidedel and $hidedel eq "NO" ;    
}

my $p4DirsDOption = "" ;	# Set -D option for "p4 dirs" if hide deleted
$p4DirsDOption = " -D" if $hidedel eq "NO" ;

###
### Figure out "back" buttons
###
my @back ;

my $tmp = "$fspc" ;		# Copy arg
my $lastd ;
if($tmp =~ /([^\/]+\/)$/) {
    $lastd = $1 ;
} ;
$tmp =~ s|[^/]+/$|| ;		# Remove last subdir
my $upTarget = $tmp ;

				# 
while($tmp ne $ROOT) {
    $tmp =~ s|([^/]+)/$|| or last ;
    my $f = $1 ;
    unshift @back,&P4CGI::ahref("FSPC=$tmp$f",
				"HIDEDEL=$hidedel",
				"HELP=Up to /$tmp$f",
				"/$f") ;
} ;
unless($weAreAtROOT) {
    unshift @back,&P4CGI::ahref("FSPC=$ROOT",
				"HIDEDEL=$hidedel",
				"HELP=Up to depot root",
				"[ROOT]") ;
}
if(defined $lastd) {
    push @back,"/$lastd" ;
}

my @options ;

###
### Create link to changes for all files below
###
push @options,&P4CGI::buttonLink("changeList.cgi",
				 "View changes for /$fspc...",
				 "CMD=changes",
				 "FSPC=/$fspc...",
				 "Changes") ;
###
### Create link to changes for all files below
###
push @options,&P4CGI::buttonLink("changeList.cgi",
				 "View pending changes for /$fspc...",
				 "CMD=changes",
				 "STATUS=pending",
				 "FSPC=/$fspc...",
				 "Pending") ;
###
### Create link to open files for all files below
###
push @options,&P4CGI::buttonLink("fileOpen.cgi",
				 "View currently open files for /$fspc...",
				 "FSPC=/$fspc...",
				 "Open files") ;
###
### Create link to view changes for a specific user below this point
###
push @options,&P4CGI::buttonLink("searchPattern.cgi",
				 "Find changes by user, description etc.",
				 "FSPC=/$fspc...",
				 "Find changes") ;

###
### Create link to recently modified files
###
push @options,&P4CGI::buttonLink("findFiles.cgi",
				 "Find files by name and date in /$fspc...",
				 "FSPC=/$fspc...",
				 "Find Files") ;


###
### Create link to depot statistics
###
push @options,&P4CGI::buttonLink("depotStats.cgi",
				 "View depot statistics for /$fspc...",
				 "FSPC=/$fspc...",
				 "Statistics") ;

###
### Create link to recently modified files
###
push @options,&P4CGI::buttonLink("jobList.cgi",
				 "View jobs related to files /$fspc...",
				 "FSPC=/$fspc...",
				 "LIST=Y",
				 "Jobs") ;


###
### Get subdirs
###
my @allSubDirsWithFiles ;
 &P4CGI::p4call(\@allSubDirsWithFiles,"dirs \"/$fspc*\" $err2null") ;
my %nonDeleted = map { ($_,$_) ; } @allSubDirsWithFiles ;


my @subdirs ;
&P4CGI::p4call(\@subdirs,"dirs $p4DirsDOption \"/$fspc*\" $err2null") ;
map  { my $dir = $_ ;
       my $dirname ;
       ($dirname = $dir) =~ s|^.*/|/| ;
       my $divstart = "" ;
       my $divend = "" ;
       unless(defined $nonDeleted{$dir}) {
	   $divstart = "<span class=\"deleted\">" ;
	   $divend = "</span>" ;
       } ;
       $_ = $divstart. P4CGI::ahref("FSPC=$dir",
				    "HIDEDEL=$hidedel",
				    "HELP=Descend to subdir",
				    $dirname) . $divend ;
   } @subdirs ;
unless($weAreAtROOT) {
    unshift @subdirs,&P4CGI::ahref("FSPC=$upTarget",
				   "HIDEDEL=$hidedel",
				   "HELP=Up",
				   "/..") ;
}

###
### Get files
###
my @files ;
my $totalFiles = 0 ;
my @tmp ;
&P4CGI::p4call(\@tmp,"files \"/$fspc*\" $err2null") ;
@files = map  { /([^\#]+)\#(.*)/ ;
		$totalFiles++ ;
		my $file=$1 ;
		my $info=$2 ;
		$file =~ s/^.*\/// ;
		my ($rev,$inf) = split / - /,$info ;
		my $pfile = "$file" ;
		my $prev ;
		my $spanStart = "" ;
		my $spanEnd = "" ;
		if($inf =~ /^delete/) {
		    $prev = "\#$rev";
		    $spanStart = "<span class=\"deleted\">" ;
		    $spanEnd = "</span>" ;
		    if($hidedel eq "YES") { 
			$pfile = undef ;
		    }
		    else {
			$pfile= "$file";
		    }
		} 
		else {
		    $prev = &P4CGI::ahref(-url => "fileViewer.cgi",
					  "FSPC=/$fspc$file",
					  "REV=$rev",
					  "HELP=View head revision of file",
					  "\#$rev") ;
		};
		if($pfile) {
		    $pfile = join("",
				  ($spanStart,
				   &P4CGI::ahref(-url => "fileLogView.cgi",
						 "FSPC=/$fspc$file",
						 "HELP=View file log",
						"$pfile") ,
				   "&nbsp;$prev" ,
				   $spanEnd )) ;
		} ;
		defined $pfile?$pfile:() ;
	    } @tmp ;

###
### Create link for "hide/view deleted files" 
###
my $toggleHide ;
if($hidedel eq "YES") {
    $toggleHide = &P4CGI::buttonCell($ENV{SCRIPT_NAME},
				     "Click to show deleted files",
				     "FSPC=/$fspc",
				     "HIDEDEL=NO",
				     "Show deleted") ;
}
else {
    $toggleHide = &P4CGI::buttonCell($ENV{SCRIPT_NAME},
				     "Click to hide deleted files",
				     "FSPC=/$fspc",
				     "HIDEDEL=YES",
				     "Hide deleted") ;
}


###
### Set help target
###
&P4CGI::SET_HELP_TARGET("depotTreeBrowser") ;

###
### Start page printout
###
print
    &P4CGI::start_page("Depot Tree Browser",
		       $toggleHide) ;


my $sarg=$weAreAtROOT?"[ROOT]":"/$fspc" ; # replace // with [ROOT]


my $currpath ;
print &P4CGI::start_framedTable("Location") ;
if(@back > 0) {
    $currpath = join('',@back) ;
}
else {
    $currpath = "[ROOT]" ;
}
print 
    "  <tr>\n".
    "    <td class=\"TreeBrowser\">$currpath</td>\n".
    "  </tr>\n".
    "  <tr>\n".
    "  <td>\n" .
    join(" ",@options) .
    "  </td>\n" .
    "  </tr>\n" .
    &P4CGI::end_framedTable() ;

###
# Make table with three columns
#
sub makeThreeColumns(@)
{
    my $l = @_ ;
    my $len = int((@_+2)/3) ;  
    if($l < 10) { $len = int($l/2) ; } ;
    if($l < 6) { $len = $l ; } ;
    while(@_ < ($len*3)) { push @_,"" ;} ; # To avoid error messages
    return join("\n",(&P4CGI::start_table(" COLS=3 class=\"TreeBrowser\""),
		      &P4CGI::table_row({-class => "TreeBrowser",
					 -text => join("<br>\n",@_[0..$len-1])},
					{-class => ($len<$l)?"TreeBrowser":"Empty",
					 -text => join("<br>\n",@_[$len..(2*$len)-1])},
					{-class => ($len*2<$l)?"TreeBrowser":"Empty",
					 -text => join("<br>\n",@_[(2*$len)..(3*$len)-1])}),
		      &P4CGI::end_table())) ;
}

if($weAreAtROOT and $moreThanOneDepot) {
    print
	"<br>" ,
	&P4CGI::start_framedTable("Depots") ;
    if(@subdirs>0) {
	print makeThreeColumns(@subdirs) ;
    }    
    print &P4CGI::end_framedTable() ;
}
else {
    print "<br>", &P4CGI::start_framedTable("Directories") ;
    if(@subdirs>0) {
	print makeThreeColumns(@subdirs) ;
    }
    else {
	print "<br>[No more subdirectories]<br>" ;
    } ;
    print &P4CGI::end_framedTable() ;
    print "<br>", &P4CGI::start_framedTable("Files") ;
    print " (deleted files hidden)" if ($hidedel eq "YES" and $totalFiles > @files);
    print "\n";
    if(@files>0) {
	print makeThreeColumns(@files) ;
    }
    else {
	print "<br>[No files in this directory]<br>" ;
    }
    print &P4CGI::end_framedTable() ;
} ;

print &P4CGI::end_page() ;

#
# That's all folks
#