#! /usr/local/bin/perl
eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}'
	if $running_under_some_shell;

# This script is a conversion utility that enables an easy
# migration from an archive based on ftp://bnlarchive.rcsb.org
# to one based on ftp://ftp.rcsb.org

# Copyright 2001
# The Regents of the University of California 
# All Rights Reserved 
#
# Permission to use, copy, modify and distribute any part of this
# software for educational, research and non-profit purposes, without
# fee, and without a written agreement is hereby granted, provided
# that the above copyright notice, this paragraph and the following
# paragraphs appear in all copies. 
#
# Those desiring to incorporate this software into commercial products
# or use it for commercial purposes should contact:
# 
#	Technology Transfer Office
#	University of California, San Diego,
#	9500 Gilman Drive
#	La Jolla, CA 92093-0910,
#	Ph: (858) 534-5815
#	FAX: (858) 534-7345. 
#
# IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY
# PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
# DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE. 
#
# THE SOFTWARE PROVIDED HEREIN IS ON AN "AS IS" BASIS,
# AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE
# MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
# THE UNIVERSITY OF CALIFORNIA MAKES NO REPRESENTATIONS AND EXTENDS
# NO WARRANTIES OF ANY KIND, EITHER IMPLIED OR EXPRESS, INCLUDING,
# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE OF THE
# SOFTWARE WILL NOT INFRINGE ANY PATENT, TRADEMARK OR
# OTHER RIGHTS. 
#

use File::Find;
umask 002;

# default settings, please adjust for local use. The generation of mmCIF
# files can be skipped by setting the respective variables to ""
$BNL_TOP	= "/ftp/PDB/pub/pdb";		# old installation
$RCSB_TOP	= "/ftp/PDB/rcsb/pub/pdb";	# new installation
$MMCIF_DIR	= "/rcsb/data/pdb/distr/mmCIF";	# mmCIF files if available
$PDB2CIF	= "/rcsb/local/bin/pdb2cif.pl";	# PDB to mmCIF converter
$LOG_DIR	= "/tmp";			# location for logs
$COMPRESS	= "/usr/bsd/compress";		# compression utility
$TOUCH		= "/sbin/touch";		# touch utility

# no configuration needed below this point

# check for correct configuration
foreach (qw(BNL_TOP RCSB_TOP MMCIF_DIR PDB2CIF LOG_DIR COMPRESS TOUCH)) {
    if ($_ && ! -e ${$_} ) {
	die "${$_} not found, please correct settings for $_\n";
    }
}

foreach (qw(RCSB_TOP LOG_DIR)) {
    if ($_ && ! -w ${$_} ) {
    	die "cannot write to ${$_}, please correct settings for $_\n";
    }
}

foreach (qw(PDB2CIF COMPRESS TOUCH)) {
    if ($_ && ! -x ${$_} ) {
	die "cannot execute ${$_}, please correct settings for $_\n";
    }
}

# start a new log file
open LOG, ">$LOG_DIR/bnl2rcsb.$$"
    or die "Cannot open $LOG_DIR/bnl2rcsb.$$ for logging\n";
&log("begin logging");

# generate RCSB directory tree
&log("creating RCSB directories");
@RCSB_DIRS = qw(
	data/structures/divided/pdb
	data/structures/divided/mmCIF
	data/structures/divided/structure_factors
	data/structures/divided/structure_factors/nonCIF
	data/structures/divided/nmr_restraints
	data/structures/all/pdb
	data/structures/all/mmCIF
	data/structures/all/structure_factors
	data/structures/all/nmr_restraints
	data/structures/obsolete/pdb
	data/structures/obsolete/mmCIF
	data/structures/obsolete/structure_factors
	data/structures/obsolete/structure_factors/nonCIF
	data/structures/obsolete/nmr_restraints
	data/status
);

foreach $dir (@RCSB_DIRS) {
    &createDir("$RCSB_TOP/$dir");
}

# link in all pdb files
&log("linking in current pdb files");

find({ wanted => \&linkCurrent, no_chdir => 1 },
     "$BNL_TOP/current_release/compressed_files");

&log("creating compressed obsolete pdb files");

find({ wanted => \&linkObsolete, no_chdir => 1 },
     "$BNL_TOP/obsolete_entries/uncompressed_files");

# link in CIF formatted structure factors
&log("linking structure factor files");
&linkSFNMR("$BNL_TOP/structure_factors/CIF_format/");

# link in NMR restraint files
&log("linking NMR restraint files");
&linkSFNMR("$BNL_TOP/nmr_restraints");

# link or generate mmCIF files
&log("creating compressed mmCIF files");

if ($MMCIF_DIR) {
    find({ wanted => \&linkMmCIF, no_chdir => 1 },
         $MMCIF_DIR);
}

if ($PDB2CIF) {
    find({ wanted => \&generateMmCif, no_chdir => 1 },
         "$RCSB_TOP/data/structures/divided/pdb",
	 "$RCSB_TOP/data/structures/obsolete/pdb");
}

# finished!
&log("completed conversion sucessfully!");

# linkCurrent gets called from the recursive find routine
# files are linked into the applicable directories
sub linkCurrent() {
    local $bnldir = $File::Find::dir;
    local $file   = $File::Find::name;
    $file =~ s,.*/(pdb.(..).\....\.Z)$,$1, or return;

    local $two = $2;

    local $targetDir = "$RCSB_TOP/data/structures/divided/pdb/$two";
    if ( !-d $targetDir ) {
	mkdir($targetDir, 0775) or die "cannot create $targetDir: $!\n";
    }

    link("$bnldir/$file", "$targetDir/$file")
	or die "cannot hardlink $targetDir/$file -> $bnldir/$file: $!\n";

    local $rcsbAll = "$RCSB_TOP/data/structures/all/pdb";
    symlink("../../divided/pdb/$two/$file", "$rcsbAll/$file")
	or die "cannot symlink $rcsbAll/$file -> ../../$two/$file: $!\n";
}

# linkObsolete gets called from the recursive find routine
# files are compressed into the applicable directories
sub linkObsolete() {
    local $bnldir = $File::Find::dir;
    local $file   = $File::Find::name;
    $file =~ s,.*/(pdb.(..).\....)$,$1, or return;

    local $two = $2;

    local $targetDir = "$RCSB_TOP/data/structures/obsolete/pdb/$two";
    if ( !-d $targetDir ) {
	mkdir($targetDir, 0775) or die "cannot create $targetDir: $!\n";
    }

    system("$COMPRESS -c $bnldir/$file > $targetDir/$file.Z");
    system("$TOUCH -amr $bnldir/$file $targetDir/$file.Z");
}

# linkSFNMR links in structure factors and NMR restraints files
# entries corresponding to obsolete PDB files are placed in the correct
# location
sub linkSFNMR($) {
    my $bnldir = shift;
    my ($pattern, $rcsbAll, $td);
    my $targetDir = "$RCSB_TOP/data/structures/divided/";

    if ($bnldir =~ /structure_factors/) {
	$pattern = 'r(.(..).)sf\.ent\.Z$';
	$targetDir .= "structure_factors";
    } else {
    	$pattern = '(.(..).)\.mr\.Z$';
	$targetDir .= "nmr_restraints";
    }

    ($rcsbAll = $targetDir) =~ s,divided,all,;
    my $grepPattern = $pattern;
    $grepPattern =~ s,\(|\),,g;

    opendir BNLDIR, $bnldir;
    map {

	/$pattern/;
	$pdbId = $1; $two = $2;
	$td = "$targetDir/$two";

	if (-e "$RCSB_TOP/data/structures/obsolete/pdb/$two/pdb$pdbId.ent") {
	    $td =~ s,divided,obsolete,;
	}

	if ( !-d $td ) {
	    mkdir($td, 0775) or die "cannot create $td: $!\n";
	}

	link "$bnldir/$_", "$td/$_"
	    or die "cannot hardlink $td/$_ -> $bnldir/$_: $!\n";

	if ($td !~ /obsolete/) {
	    symlink("$td/$_", "$rcsbAll/$_")
		or die "cannot symlink $rcsbAll/$_ -> $td/$_: $!\n";
	}

    } grep { /$grepPattern/ } readdir(BNLDIR);
    closedir(BNLDIR);
}

# linkMmCIF() compresses existing mmCIF files if necessary and stores them
# in the correct location. It is called from a recursive find() routine.
sub linkMmCIF() {
    
# log a message and print it to STDOUT too
sub log($) {
    my $msg = shift;
    $time = localtime(time);
    print "$time - $msg\n";
    print LOG "$time - $msg\n";
}

# recursively create a directory
sub createDir($) {
    local $dir = shift;
    if ($dir =~ m,(.+)/,) { &createDir($1); }
    return if ( -d $dir );
    mkdir($dir, 0775) or die "cannot create directory $dir: $!\n";
}
