#!/usr/bin/perl

# submit.cgi
# Copyright 1997,1998 Werner G. Krebs. All Rights Reserved.
# Unpubished trade secret Contact author for permission to use or modify.
# THIS IS THE SCRIPT THAT INVOKES THE MORPH SERVER!
# Modified slightly by Nat <nat@ucxray.berkeley.edu>, 6-24-02
# Modified to check for existing entries, 3-28-06

#use File::Path;
require 'config.pm';
require "$PREFIX/lib/cgi-lib.pl";
require "$PREFIX/lib/util.pm";
use CGI ':standard';

if (! param("submit")) {
	&do_form();
	chdir("..");
	exit(0);

} else {

	# Check for old morphs like this one.
	
	#scf added this temproary:
	if (0) 

	#if ((my $confirm = param("confirm")) != 1) 
	{
		my $pdb1 = untaint(param("pdbID1"));
		my $pdb2 = untaint(param("pdbID2"));
		my $chain1 = untaint4(param("chain1"), "A");
		my $chain2 = untaint4(param("chain2"), "A");
		&redundancy_check($pdb1, $pdb2, $chain1, $chain2);
	}

	# Nothing there?  Okay, let's morph it!
	my $ID = &gen_ID;
	my $nconfs = param("nconfs") if param("nconfs");
	&html_error("Range of two to ten conformations _only_ allowed!") if ($nconfs > 10 or $nconfs < 2);

	# Spool the files to directory with same name as ID
	# We have to do this here because CGI.pm is really anal about
	# destroying temp files.
	umask 022;
	mkdir("$UPLOADS/$ID", 0777) or die("Server side error: Can't create upload directory!");
	chdir("$UPLOADS/$ID") or die("Server side error: Can't cd to upload directory!");

	open(STDERR, ">> /tmp/server.log");
	for ($i = $nconfs; $i >= 1; $i--) {
		my $fupload = tmpFileName(param("input_file$i"));

	    if (! param("pdbID$i") and -z $fupload) {
			if ($i == $nconfs) {
				$nconfs--;
				next;
			} else {
				&html_error("Please enter a PDB identifier _or_ a filename for file $i.");
			}
		}
		if (param("pdbID$i") and -s $fupload) {
			&html_error("Please enter _either_ a PDB identifier _or_ a filename for file $i.");
		}
		if (-s $fupload) {
			system("mv $fupload $UPLOADS/$ID/$ID" . "_$i.pdb");
			system("ls -l $UPLOADS/$ID/$ID" . "_$i.pdb >> /tmp/server.log");
		}
	}

	param("email") or &html_error("Please enter an email address!");
	my $EMAIL = param("email");
	param("protein_name") or &html_error("Please enter a protein name!");

	#Set environmental variables for registermovie.pl later down the line.
	$ENV{'MOVIENAME'} = param("protein_name");
	$ENV{'MOVIEID'} = $ID;
	$ENV{'MOVIETYPE'} = param("MOVIETYPE");
	
	param("user_name") or &html_error("Please enter your name!");
	$ENV{'MOVIEUSER_NAME'} = param("user_name");


			#"Email notifications are temporarily disabled pending a security update.  ".
			#"<BR/><B>$ID</B><BR/>".
			#"Instead, please come back in an hour or so and check <a href=\"http://molmovdb.org/cgi-bin/morph.cgi?ID=$ID\">here</a> to see if your job is complete.".
	if ($pid = fork()) {
		$mystring = '<br/><br/>';
		foreach my $key (param()) {
			$val = param($key);
			$mystring=$mystring."$key : $val <br/>";
		}
		&html_msg("The submission is being processed.\nYour confirmation ID is:" .
			"<BR/><B>$ID</B><BR/>".
			"Computation usually takes a few minutes to finish. Please wait a bit and then go to this URL to view your results or check on your job: <br/>".
                        "<a href=\"http://molmovdb.org/cgi-bin/morph.cgi?ID=$ID\"> http://molmovdb.org/cgi-bin/morph.cgi?ID=$ID</a> <br/>".

                        "<BR/><B><font color=red>Note that we are not providing confirmation emails at the moment, with apologies for any inconvenience. Please keep refreshing <a href=\"http://molmovdb.org/cgi-bin/morph.cgi?ID=$ID\"> http://molmovdb.org/cgi-bin/morph.cgi?ID=$ID</a> until the animation page shows up to view your results.</font></B><BR/>".

                        #"<BR/><B>Note that we are not providing confirmation emails at the moment, with apologies for any inconvenience.</B><BR/>".
			#"You will be emailed at the following address when your work is complete:" .
			#"<BR/>$EMAIL<BR/>".
			"$mystring <br/>");
	} elsif (defined $pid) {

		# Mail a copy of the submission to the administrator
		open(MAIL,"| $SENDMAIL -t") or die "Could not send mail.";
		print MAIL <<EOF;
From: $ADMIN
To: $ADMIN,$EMAIL
Subject: [Morph Server] submission $ID

Thank you for your submission $ID.  As a security measure, your submission parameters are no longer included in this email; you can view them on the submission page.  You will receive a second email when your job is complete.  

EOF
		#we used to provide this info, until hackers started using it to spam people..
		#foreach my $key (param()) {
			#$val = param($key);
			#print MAIL "$key : $val\n";
		#}
		
		close(MAIL);

		my $LOGFILE = "$UPLOADS/$ID/test.log";

		if (param("private")) {
			system("touch PRIVATE");
			$ENV{'PRIVATE'} = param("private");
		}

		close(STDERR);
		open(STDIN,"< /dev/null");
		open(STDOUT,">> $LOGFILE");
		open(STDERR,">> $LOGFILE");

		my $cmdline = "";

		#print STDERR "scf22 $nconfs\n";
		#system(" echo \"$nconfs\" > /usr/local/server/temp/nconfs.txt");		

		for (my $i = 1; $i <= $nconfs; $i++) {

			if (param("pdbID$i")) {
				$pfile[$i - 1] = getpdb3(untaint(param("pdbID$i")));
				$pfile[$i - 1] =~ tr/A-Z/a-z/;
			} else {
				my $file = "$ID" . "_$i.pdb";
				print STDERR "Moving $file to webupload$i.pdb\n";
				system("mv $file webupload$i.pdb");
				system("chmod 666 webupload$i.pdb");
                                          
                        #	my $containsEND = `awk '{if ($1 == "END") {print $1}}' `;
			#	if ($containsEND eq "END") {system("echo \"END\" >> webupload$i.pdb");}
			#	system("echo \"$containsEND webupload$i.pdb\" > $TEMP/webuploadslog.txt");

				$pfile[$i - 1] = "webupload$i.pdb";
			}

    		if(! ( -s $pfile[$i-1] ) ) { #PDB retrieval presumably failed.
				my $q = $i - 1;
				&html_error("Zero-length input file $i ($pfile[$q]).");
			}

			# default chain is A because our programs ignore chain ids for PDB
			# files that do not use chains.
			$chain[$i - 1] = "A";
			$chain[$i - 1] = untaint(param("chain$i")) if (param("chain$i"));
			$cmdline .= "$pfile[$i-1] $chain[$i-1] ";
		}

		chdir("$PREFIX/bin") or die "Can't cd $PREFIX/bin.";
		
		$ENV{'MOVIEEMAIL'} = $EMAIL;
		$< = $>; #prevent test.cgi from thinking it is setuid.

		my $nframes = 8;
		$nframes = param("nframes") if param("nframes");
		if ($nframes > 30) {
			&html_error("Please request no more than 30 intermediate frames.\n");
		}
	
		$ENV{'NFRAMES'} = 2 + $nframes;
		$ENV{'HETERO'} = 0;

		#$ENV{'HETERO'} = untaint(param("hetero")) if param("hetero");
		#maybe stats entry doesn't exist yet?
		
		$ENV{'PRIVATE'}= untaint(param("private"))if param("private");

		#---- CALL ACTUAL MORPHING SCRIPTS ----#
		system "./talign.pl $UPLOADS/$ID $nconfs $cmdline </dev/null >> $LOGFILE 2>&1";	
		if ($ENV{'PRIVATE'}) {sqlDo("update stats set private='Y' where mid_=\"$ID\";",'',1);}
		if (! -e "$UPLOADS/$ID/FINISHED") {
			exit;
		}

		$ENV{'NFRAMES'} = $nframes * ($nconfs - 1) + $nconfs;

		system ("./animate_simple.pl $ID $nframes < /dev/null >> $LOGFILE  2>&1" );
	
		if (!-e "$UPLOADS/$ID/micon0.gif") {
			system ("echo Animation failed to produce GIF. >> $LOGFILE");
		} else {
			my $COMMENTS = untaint4(param("description"), 0);
			my $CLASS = untaint4(param("rbutton"), 0);
			$COMMENTS =~ s/\n/\<BR\>/g;
			open(COMMENTS, ">> $UPLOADS/$ID/comments");
			if ($COMMENTS) { print COMMENTS "$COMMENTS\n"; }
			close(COMMENTS);
		}

		open (SENDMAIL, "| /usr/lib/sendmail -t");
		print SENDMAIL <<EOF;
From: The morph server <$ADMIN>
To: $EMAIL, $ADMIN
Subject: [Morph Server] $ID complete

Your animation is now complete.  You may view it here:

$WEBCGI/morph.cgi?ID=$ID

Please contact the administrator by replying to this email if you
experience any problems.  The Morph Server FAQ may also be useful:

http://www.molmovdb.org/help/faq.html

Thank you for using the experimental protein morphing server.

EOF


		exit;
	}

	else {
	   	&html_error("Fork failed!");
	}
}

sub do_form{

	require "$PREFIX/lib/cgi-lib.pl";
	
	my $nconfs = 2;
	$nconfs = param("nconfs") if param("nconfs");

	$cgi_data{MOVIETYPE} = "Yale" if !$cgi_data{MOVIETYPE};

	$cgi_data{nframes} = 8 if !$cgi_data{nframes};
	my $checked = "";
	$checked = "CHECKED" if $cgi_data{hetero};
	my $pchecked = "";
	$pchecked = "CHECKED" if $cgi_data{private};
	$ENV{PRIVATE} = $cgi_data{private};

	print "Content-type: text/html", "\n\n";
	print <<EOF;
<HTML>
<HEAD>
<TITLE>Submission Form for the Morphing Server and Database</TITLE>
<link rel=stylesheet href="$WEBROOT/molmovdb.css" type=text/css>
</HEAD>

$HEADER

<DIV CLASS="margin">
<BLOCKQUOTE>
<H2>Submission Form for the Morphing Server and Database</H2>

[ <A HREF="/molmovdb/morph">front page</A> | 
  <A HREF="http://bioinfo.mbb.yale.edu/papers/morphs-nar">citation</A> |
  <A HREF="/cgi-bin/movie.cgi">movie gallery</A> |
  <A HREF="/cgi-bin/beta.cgi">development version</A> |
  <a href="/cgi-bin/multichain.cgi">RNA/DNA</a> |
  <A HREF="/molmovdb/help/faq.html">FAQ list</A> ]

<P>Submissions take anywhere from five minutes to half an hour to process.
You should read the documentation first, especially the FAQ,
if you have any questions about the database; an old but thorough 
description of the server is <A HREF="/molmovdb/help/morph.html">here</A>.</P>

<P>This version of the server only morphs single protein chains; for
RNA and complexes, you want the <A HREF="/cgi-bin/multichain.cgi">
development version</A>.  Some features available there will
be folded into this version soon; in particular, morphing will
switch to using <A HREF="http://cns.csb.yale.edu">CNS</A>, though this
will have little practical impact on the results.</P>

<HR>
<P><SMALL><I>Fields designated by (<FONT COLOR=red>*</FONT>) are required.</I></SMALL>
<BR>

<FORM ENCTYPE="multipart/form-data" METHOD="POST" NAME="morphForm">

<b>Protein Name: (<FONT COLOR=red>*</FONT>)</b>
<INPUT SIZE=60 NAME="protein_name" VALUE="$cgi_data{protein_name}"><br>
<font class="small"><i>Please try to make this as descriptive as possible,
e.g. "Calcium pump ATPase (E1 to E2)" or "RNA pol II initiation to elongation".
These names will be the primary link to the morph in our database, and
assist in our annotation efforts. <b>Please do not enter obfuscated names!</b>
</i></font>

<P>
<b>Number of frames between solved structures (default:8 max:30)</b>
<INPUT SIZE=2 NAME="nframes" VALUE="8"></INPUT>

<P>
<B>Morph Type:</B>
<SELECT NAME = "MOVIETYPE">
	<OPTION VALUE="Yale">Yale (modified XPLOR)</OPTION>
</SELECT>

<BR>
<input type=checkbox name=hetero value=1 $checked>Include heteroatoms?
(<A HREF="$WEBROOT/help/faq.html#hets">DISABLED</A>)</INPUT>
<BR>
<input type=checkbox name=private value=1  $checked>Private            ?
(<A HREF="$WEBROOT/help/faq.html#hets">Strongly discouraged</A>)</INPUT>
<BR>

<P><b>Number of conformations to morph (minimum 2, max 10): (<FONT COLOR=red>*</FONT>)</b>
<INPUT TYPE="hidden" NAME="nconfs" VALUE="2"/><i>Sorry, only two conformations allowed at this time.</i>
<!-- <SELECT NAME = "nconfs">
EOF
    for($i = 2; $i <= 10; $i++) {
		$selected ="";
		$selected = "SELECTED" if ($nconfs == $i);
		print "<OPTION $selected VALUE = \"$i\">$i\n";
	}

	print <<EOF;
</SELECT>
<INPUT TYPE="Submit" NAME="update" VALUE="Update Form"> -->
<p><b><FONT COLOR=red>WARNING: The "SEQRES records" would cause severe trouble for morph server frame calculations, and no results would be generated. Please remove your SEQRES rows in yor PDB file before submission. If you have any problem, please contact Bo Wang at <a href='mailto:wang.bo\@yale.edu'>wang.bo_AT_yale.edu.</a> <br/> For questions regarding preparation of PDB files before submission, as well as the right way to enable JMol for animation visualization upon job completion, a detailed tutorial is offering at <a href="https://youtu.be/aR7tkDw0qBU">https://youtu.be/aR7tkDw0qBU</a></FONT></b></p>
<P><b>PDB identifiers or PDB files for upload: (<FONT COLOR=red>*</FONT>)</b>

EOF

print "<TABLE COLS=3 WIDTH=100% CELLSPACING=2>\n";

for ($i = 1; $i <= $nconfs; $i++) {

    print <<EOF;

<TR>
<TD ALIGN = LEFT>
PDB ID$i:                  
<INPUT NAME="pdbID$i" SIZE = 4 MAXLENGTH = 4 VALUE="$cgi_data{"pdbID$i"}">
</TD>

<TD ALIGN = LEFT>
or PDB File #$i:
<INPUT ALIGN = MIDDLE TYPE="file" NAME="input_file$i">
</TD>

<TD ALIGN = CENTER>
Chain:
<SELECT NAME = "chain$i">
<OPTION SELECTED VALUE="$cgi_data{"chain$i"}">$cgi_data{"chain$i"}
<OPTION VALUE = "A">A
<OPTION VALUE = "B">B
<OPTION VALUE = "C">C
<OPTION VALUE = "D">D
<OPTION VALUE = "E">E
<OPTION VALUE = "F">F
<OPTION VALUE = "G">G
<OPTION VALUE = "H">H
<OPTION VALUE = "I">I
<OPTION VALUE = "J">J
<OPTION VALUE = "K">K
<OPTION VALUE = "L">L
<OPTION VALUE = "M">M
<OPTION VALUE = "N">N
<OPTION VALUE = "O">O
<OPTION VALUE = "P">P
<OPTION VALUE = "Q">Q
<OPTION VALUE = "R">R
<OPTION VALUE = "S">S
<OPTION VALUE = "T">T
<OPTION VALUE = "U">U
<OPTION VALUE = "V">V
<OPTION VALUE = "W">W
<OPTION VALUE = "X">X
<OPTION VALUE = "Y">Y
<OPTION VALUE = "Z">Z
</SELECT>
</TD>
</TR>
EOF
}
	print "</TABLE>\n";

	print <<EOF;
<!--<P><b>Medline Unique Identifiers (UIs):</b>
<BR>
<FONT FACE='arial, Helvetica, sans-serif' SIZE=2>
(These provide a shorthand way of referencing the papers that describe
the motion. If you want to type a full reference in, use the "comments"
section further down.)</FONT>
<PRE><INPUT SIZE=13 NAME="med1" VALUE="$cgi_data{med1}"> <INPUT SIZE=13 NAME="med2" VALUE="$cgi_data{med2}"> <INPUT
SIZE=13 NAME="med3" VALUE="$cgi_data{med3}"> <INPUT SIZE=13 NAME="med4" VALUE="$cgi_data{med4}"> </PRE>
-->
<!--<P><b>Classification of Motion:</b>
<BR><I>See the <A HREF=..>Molecular Motions Database</A> for information on these classifications.</I>
<FONT FACE='arial, Helvetica, sans-serif' SIZE=2>

EOF

#    mkrbox("A.1.i	D-s-2	Known Domain Motion, Shear Mechanism",
#		"A.1.ii	D-h-2	Known Domain Motion, Hinge Mechanism",
#		"A.1.iii	D-?-2	Known Domain Motion, Unclassifiable Mechanism",
#		"A.1.iv	D-n-2	Known Domain Motion, Neither Hinge nor Shear Mechanism",
#		"A.1.v	D-f-2	Known Domain Motion, Partial Refolding of Structure",
#		"A.2.i	D-s-1	Suspected Domain Motion, Shear Mechanism",
#		"A.2.ii	D-h-1	Suspected Domain Motion, Hinge Mechanism",
#		"A.2.iii	D-?-1	Suspected Domain Motion, Unclassifiable Mechanism",
#		"A.2.iv	D-n-1	Suspected Domain Motion, Neither Hinge nor Shear Mechanism",
#		"B.1.i	F-s-2	Known Fragment Motion, Shear Mechanism",
#		"B.1.ii	F-h-2	Known Fragment Motion, Hinge Mechanism",
#		"B.1.iii	F-?-2	Known Fragment Motion, Unclassifiable",
#		"B.1.iv	F-n-2	Known Fragment Motion, Neither Hinge nor Shear Mechanism",
#		"B.2.i	F-s-1	Suspected Fragment Motion, Shear Mechanism",
#		"B.2.ii	F-h-1	Suspected Fragment Motion, Hinge Mechanism",
#		"B.2.iii	F-?-1	Suspected Fragment Motion, Unclassifiable",
#		"B.2.iv	F-n-1	Suspected Fragment Motion, Neither Hinge nor Shear Mechanism",
#		"C----	C----	Complex Motion",
#		"C.1.i	S-a-2	Known Subunit Motion, Involving Allostery",
#		"C.1.ii	S-n-2	Known Subunit Motion, Not Involving Allostery",
#		"C.2.i	S-a-1	Suspected Subunit Motion, Involving Allostery",
#		"C.2.ii	S-n-1	Suspected Subunit Motion, Not Involving Allostery");

    print <<EOF;
</FONT>-->
<P><b>Description:</b><BR>
<font class="small"><i>We would appreciate a paragraph-length description of
what the movie depicts, if known.  These often form the basis for new entries in
the motions database.  Specific literature references are extremely helpful.
<b>If you uploaded PDB files rather than specify IDs to use, please indicate the
actual PDB IDs here!</b></i>
</font><br>
<TEXTAREA NAME="description" ROWS=10 COLS=60 VALUE="$cgi_data{comments}"></TEXTAREA> 

<P><b>Your name</b> (<FONT COLOR=red>*</FONT>):
<INPUT SIZE=30 NAME="user_name" VALUE="$cgi_data{user_name}">
<P><b>Your e-mail address</b> (<FONT COLOR=red>*</FONT>):
<INPUT SIZE=30 NAME="email" VALUE="$cgi_data{email}">



<p>Note 1: By clicking "Submit", you are consenting to have the
morph results automatically included in the public movie listing.  If the
structures are unpublished or you do not wish your data to be publically
viewable, do not use this form!
Instead, contact the site maintainers directly.</p>

<p>
Note 2: For the time being, we are not archiving morphs for long-term storage. Please retrieve your morph result(s) within a few days of job submission. We apologize for any inconvenience this may cause.
</p>



<P>
<INPUT TYPE="submit" NAME="submit" VALUE="Submit">
<INPUT TYPE="reset" VALUE="Clear Form">
<P>

</FORM>

<SCRIPT LANGUAGE="JavaScript1.1">

    function isblank(s) {
	for(var i=0; i<s.length;i++) {
	    var c = s.charAt(i);
	    if ((c != ' ') && (c != '\\n') && (c!='\\t')) return false;
	}
	return true;
    }

function verify(f)
{

    var msg;
    var empty_fields="";
    var errors = "";

    for (var i = 0; i < f.length;i++) {
	var e = f.elements[i];
	if(e.required) {
	    if ((e.value == null) || (e.value == "") || isblank (e.value)) {

		empty_fields += "\\n        " + e.name;
		continue;
	    }
	}
	    
	    if (e.numeric || (e.min != null) || (e.max !=null)) {
		var v = parseFloat(e.value);
		if (isNaN(v) ||
		    ((e.min != null) && (v < e.min)) ||
		    ((e.max != null) && (v > e.max))) {
		    errors += "- The field " + e.name + " must be a number";
		    if (e.min != null)
			errors += " that is greater than " + e.min;
		    if (e.max != null && e.min != null )
			errors += " and less than " + e.max;
		    else if (e.max != null) 
			errors += " that is less than " + e.max;
		    errors += ".\\n";
		}

	    }
	
    }


    if (!empty_fields && !errors) return true;

    msg = "Form has the following errors.\\nPlease correct and re-submit:\\n\\n";

    if (empty_fields) {
	msg += "The following required field(s) is/are empty:\\n" +
	    empty_fields + "\\n";
	if (errors) msg += "\\n";
    }
    msg += errors;
    alert(msg);
    return false;
}

function MorphSubmit() {
    this.protein_name.required = true;
this.nframes.min = 2; this.nframes.max=30; this.user_name.required = true; this.email.required=true; 

return verify(this);
}

document.morphForm.onSubmit = MorphSubmit;

</SCRIPT>
</DIV>
EOF

	&footer();
}

sub mkrbox {

    my $i;
    my $option;
    my $checked;
    for($i = 0; $i < scalar @_; $i++) {
		$option = $_[$i];
		$checked = "";
		$checked = " CHECKED" if ($cgi_data{rbutton} eq $option); 
		print "<BR><INPUT TYPE=\"radio\" NAME=\"rbutton\" VALUE=\"$option\" $checked> $option\n";
    }
}

# Look for existing entries in the database.
sub redundancy_check {
	my ($pdb1, $pdb2, $chain1, $chain2) = @_;

	$pdb1 =~ tr/A-Z/a-z/;
	$pdb2 =~ tr/A-Z/a-z/;
	$pdb1 .= ".pdb";
	$pdb2 .= ".pdb";
    my @fields = ("mid_", "protein_name", "inputframe0", "inputchain0",
		"inputframe1", "inputchain1", "nresidues");
	my $list = join(", ", @fields);

	my $db = &db_connect($CGI_USER, $CGI_PASSWD);
	my $query = $db->prepare("SELECT $list FROM stats WHERE inputframe0 = " .
		"'$pdb1' AND inputframe1 = '$pdb2' AND inputchain0 = '$chain1' AND " .
		" inputchain1 = '$chain2'");
	print STDERR "---> $pdb1 $pdb2 $chain1 $chain2\n";
	$query->execute();
	my @list = ();
	while (my @row = $query->fetchrow_array()) {
		push(@list, [ @row ]);
	}

	if (scalar(@list) > 0) 
				{
		print "Content-Type: text/html\n\n";
		my $header = &gc_header();
		print <<EOF;
<HTML>
<HEAD><TITLE>Morph report for $ID</TITLE>
<link rel=stylesheet href=$WEBROOT/molmovdb.css type=text/css>
</HEAD>

$header

<BODY bgcolor=white>
<BLOCKQUOTE>
<h2>Duplicate entry!</h2>
<p>The database already contains at least one morph of this transition.
Search results are listed below.  These may vary in number of frames but
are otherwise identical.</p>
<p>If you need a specific number of intermediate frames not represented here,
please use <a href="submit.cgi?confirm=1">this page</a> and re-enter your
request.</p>
EOF

		&morphTable(\@list, "Similar morphs", 1);

		my $footer = &footer();
		print "</blockquote>\n\n$footer\n</html>\n";
		exit;
	}
}


sub morphTable { 
    my ($morphs, $title, $USE_IMG) = @_;

    print <<EOF;
<TABLE CELLPADDING="0" WIDTH="800"><TR CLASS="bg"><TD>
<TABLE CELLSPACING="1" CELLPADDING="2" WIDTH="100%">
<TR CLASS="top"><TD CLASS="header1" COLSPAN="8">$title</TD></TR>
<TR CLASS="header2">
<TD CLASS="psred">Morph</TD>
<TD CLASS="psred">Morph name</TD>
<TD CLASS="psgreen">Structure #1</TD>
<TD CLASS="psgreen">Structure #2</TD>
<TD CLASS="psgreen">Residues</TD></TR>
EOF

    my $COLOR = 1;
    for (my $i = 0; $i < scalar(@$morphs); $i++) {
        ($COLOR == 2) ? $COLOR-- : $COLOR++;

        print qq(<TR CLASS="gray$COLOR">\n);
        if ($USE_IMG) {
            print <<EOF;
<TD CLASS="thumbnail"><A HREF="morph.cgi?ID=$$morphs[$i][0]">
<IMG SRC="$WEBROOT/uploads/$$morphs[$i][0]/sicon.png" BORDER="0"></A></TD>
EOF
        } else {
            print <<EOF;
<TD CLASS="cell3">
<A CLASS="plain" HREF="morph.cgi?ID=$$morphs[$i][0]">$$morphs[$i][0]</A></TD>
EOF
        }

        my $pdb0 = &filterId($$morphs[$i][2]);
        my $pdb1 = &filterId($$morphs[$i][4]);

        print <<EOF;
<TD CLASS="cell3"><A CLASS="plain" HREF="morph.cgi?ID=$$morphs[$i][0]">$$morphs[$i][1]</A></TD>
<TD CLASS="cell3">$pdb0 [ $$morphs[$i][3] ]</TD>
<TD CLASS="cell3">$pdb1 [ $$morphs[$i][5] ]</TD>
<TD CLASS="cell3">$$morphs[$i][6]</TD></TR>
</TR>
EOF
    }
    print "</TABLE>\n</TD></TR></TABLE>\n";
}

sub filterId {
    my ($pdb) = @_;

    $pdb =~ s/\.pdb$//;

    if ($pdb =~ /webupload/) {
        return "upload";
    } else {
        return qq(<A CLASS="plain" HREF="http://www.rcsb.org/pdb/cgi/explore.cgi?pdbId=$pdb">$pdb</A>);
    }
}



