#!/usr/bin/perl -s
$WWWROOT = $ENV{'WWWROOT'};
#$main::DEBUG = 1;
use MBGD;
use MBGD::WWW;
use Digest::MD5;
use ClustTree;
use MBGD::FunctionCategory;
use MBGD::Taxonomy;
use ConsenseTitle;
use RECOG;
use RECOG::RecogCommon;
require "libMBGDaxes.pl";
require "MBGD_common.pl";

my(@Superkingdoms) = ( 'Bacteria', 'Archaea', 'Eukaryota' );

$| = 1;

$WWW = MBGD::WWW->new;
$uid = $WWW->uid;

%Args = $WWW->cgiGetArgs;

if (!exists($Args{'display_function'})) {
    $Args{'display_function'} = '';
}
if (!exists($Args{'display_motif'})) {
    $Args{'display_motif'} = '';
}
if (!exists($Args{'cutoff_motif'})) {
    $Args{'cutoff_motif'} = '0.001';
}
if ($Args{'cutoff_motif'} <= 0) {
    $Args{'cutoff_motif'} = '0.001';
}

%param = $WWW->uInfo->getHomolParamHash;

$progname = $Args{'prog'};

if ($Args{'multigenome'}) {
    &exec_multigenome;
##  exit
} elsif ($Args{'multicluster'}) {
    if (ref $Args{'cluster'} eq 'ARRAY') {
        foreach $cl (@{$Args{'cluster'}}) {
            ($clid, @orfs) = split(/,/, $cl);
            $clid =~ s/[A-Z]//;
            foreach $orf (@orfs) {
                $ORF{$orf} = 1;
            }
            push(@clustList, $clid);
        }
    } else {
        ($clid, @orfs) = split(/,/, $Args{'cluster'});
        foreach $orf (@orfs) {
            $ORF{$orf} = 1;
        }
    }
    $cmdname = 'hcluster'; $progname = 'hcluster';
}

if (!$Args{'matvalues'}) {
    $Args{'matvalues'} = $param{sim_measure};
}
if ($Args{'distmat'} || $Args{'redraw'}) {
    $EXEC_CLUSTER = 1;
}
if ($Args{'mali'}) {
    $cmdname = 'mali';
} elsif ($Args{'hcluster'} || $Args{'redraw'}) {
    $cmdname = 'hcluster';
    $progname = 'hcluster';
} elsif ($Args{'distmat'}) {
    $cmdname = 'hcluster';
    $progname = 'distmat';
} else {
    $cmdname = `basename $0`; chop $cmdname;
}

if ($Args{'clustid'} =~ /^H(\d+)$/) {
	$Args{'homclustid'} = $1;
}
if (defined $Args{'homclustid'}) {
    my($db) = MBGD::DB->new($main::DBNAME_RECOG);
    my($sql) = "select clustid from cluster_result_$Args{tabid} where homclustid='$Args{'homclustid'}'";
    my($sth) = $db->execute($sql);
    my(@tmplist);
    while (($clustid) = $sth->fetchrow_array) {
	push(@tmplist, $clustid);
    }
    $Args{'clustid'} = join(',', @tmplist);
print STDERR ">>$Args{homclustid},$Args{clustid}\n";
} elsif (defined $Args{'clustid'}) {
    $Args{'clustid_orig'} = $Args{'clustid'};

    my @tmplist;
    # delete the first character ("O")
    foreach $clustid (split(/,/, $Args{clustid})) {
        $clustid =~ s/^[A-Z]//;
        $clustid =~ s/\.\d+$//;
        push(@tmplist, $clustid);
    }
    $Args{'clustid'} = join(',', @tmplist);
}

#
$specs = $param{'species'};
$specs =~ s/\|/,/g;
@spec_list = split(',', $specs);
if (defined $Args{'tabid'}) {
    $Args{'tabid'} = $Args{'tabid'};
} else {
    $Args{'tabid'} = $WWW->uInfo->currentTableID;
}
if ($Args{'tabid'}) {
    my($dbname) = $main::DBNAME_RECOG;
    my($db) = MBGD::DB->new($dbname);
    my($sql) = "select * from cluster_tables_idx where clusterID='$Args{'tabid'}'";
    my($sth) = $db->execute($sql);
    if ($sth->rows() != 0) {
        my($ref) = $sth->fetchrow_hashref();
        my($splist) = ($ref->{'cmd'} =~ /\-SPEC=(\S+)/);
        @spec_list = split(',', $splist);
    }
}
else {
    $Args{'tabid'} = 'default';
    $Args{'tabid'} = upd_tabid($Args{'tabid'});
}
$WWW->uInfo->saveTableIDs($Args{'tabid'});

foreach my$sp (@spec_list, $Args{'annotsp'}) {
    next if ($sp =~ /^\s*$/);
    next if ($sp =~ /[^0-9A-Z]/i);

    $spec_hash{"$sp"} = 1;
}

if (ref $Args{'orfs'} eq 'ARRAY') {
    foreach $orf (@{$Args{'orfs'}}) {
        $orf =~ s#\(\d+\)## if ($EXEC_CLUSTER);
        $ORF{$orf} = 1;
        $ORF_checked{$orf} = 1;
    }
} elsif (defined $Args{'orfs'}) {
    foreach $orf (split(/,/, $Args{'orfs'})) {
        $orf =~ s#\(\d+\)## if ($EXEC_CLUSTER);
        $ORF{$orf} = 1;
        $ORF_checked{$orf} = 1;
    }
} elsif (defined $Args{'clustid'}) {
    foreach $clustid (split(/,/, $Args{clustid})) {
        push(@treeRes, &readClustTree($Args{'tabid'}, $clustid));

        if (($Args{'tabid'} =~ /^addspec$/i) && ($Args{'annotsp'} =~ /^\s*$/) && ($Args{'add_spname'} !~ /^\s*$/)) {
            ($Args{'annotsp'}) = ($Args{'add_spname'} =~ /([^\:]+)/);
        }

        #
        my($tax) = MBGD::Taxonomy->new();
        my($sta) = $tax->is_default_spec($Args{'annotsp'});
        if (!$sta) {
            $clust_addspec_ref->{"$clustid"} = get_clust_addspec($uid, $Args{'tabid'}, $clustid, $Args{'annotsp'});
        }
    }

    $clustorf_ref = getClustOrfsFromTreeRes(@treeRes);
    %ORF = &getOrfsFromTreeRes(@treeRes);

    foreach my$orf (split(/,/,$Args{'add_spname'})) {
        $ORF{$orf} = 1;
    }
    foreach $clustid (split(/,/, $Args{clustid})) {
        my($clust_ref) = $clust_addspec_ref->{"$clustid"};
        foreach my$sp (keys(%{$clust_ref})) {
            my($clustsp_ref) = $clust_ref->{"$sp"};
            foreach my$name (keys(%{$clustsp_ref})) {
                my($orf) = join(':', $sp, $name);
                $ORF{$orf} = 1;
            }
        }
    }
}
@entnames = keys %ORF;
if (! @entnames) {
    foreach $orf (split(/,/,$Args{'allorfs'})) {
        $orf =~ s#\(\d+\)## if ($EXEC_CLUSTER);
        $ORF{$orf}= 1;
        push(@entnames, $orf);
    }
}

for ($i = 1; $i < @entnames; $i++) {
    ($org) = split(/:/, $entnames[$i]);
    $orgnames{$org} = 1;
}

if ($Args{'drawmap'}) {
    ## Compare ORF maps
    my($reforg, $refname) = split(/:/, $entnames[0]);
    my($org_std_names) = '';
    $refname =~ s/\(\d+\)$//;
    for ($i = 1; $i < @entnames; $i++) {
        ($org) = split(/:/, $entnames[$i]);
        next if ($org eq 'sp');
        next if ($org eq 'str');
        next if ($org eq 'qry');
        $org_std_names .= '&' if ($org_std_names);
        $orgname = $entnames[$i]; $orgname =~ s/\(\d+\)$//;
        $org_std_names .= "org_std_name=$orgname";
    } 
    my($input);
    $input = "organism=$reforg&genename=$refname&width=20000&$org_std_names";
    $input .= "&tabid=$Args{'tabid'}";
    $ENV{'CONTENT_LENGTH'} = length($input);
    exec("$WWWROOT/htbin/RECOG/RECOG_multi_region_html.pl <<EOF
$input
EOF");
} elsif ($Args{'drawtree'}) {
    my $input;
    my $genes = join(',', @entnames);
    $input = "tabid=$Args{tabid}&size=$Args{size}&";
    $input .= "genes=$genes&";
    exec("$WWWROOT/htbin/drawClusterTree.pl <<EOF
$input
EOF");
} elsif ($Args{'getseq'}) {
    ## Get sequences (Protein or DNA)
    my($OPT);
    $progname = 'getaaseq';
    if ($Args{'seqtype'} =~ /^nt/i) {
        $progname = 'getntseq';
        $OPT .= "-up=$Args{'up'}" if ($Args{'up'});
        $OPT .= " -down=$Args{'down'}" if ($Args{'down'});
        $OPT .= " -delimiter='$Args{'delimiter'}'" if ($Args{'delimiter'} ne '');
    }

    if (!defined($clustorf_ref)) {
        my(%orf_clust);
        foreach my$name (@entnames) {
            $orf_clust{"$name"} = '';
        }
        print exec_getseq($progname, $OPT, %orf_clust);
    }
    else {
        print "Content-type: text/plain\n";
        print "\n";

        #
        my($sfunc_ref) = sub {
            my($acid, $ascid) = split(/\./, $a);
            $ascid = 'out' if ($ascid ne '' && $ascid == 0);
            my($bcid, $bscid) = split(/\./, $b);
            $bscid = 'out' if ($bscid ne '' && $bscid == 0);

            $acid <=> $bcid
                ||
            length($ascid) <=> length($bscid)
                ||
            $ascid <=> $bscid
                ||
            $ascid cmp $bscid;
        };
        my(@clustid_list) = split(/,/, $Args{'clustid_orig'});
        my(%hash_out_clustid);
        foreach my$clustid (sort $sfunc_ref @clustid_list) {
            my($cid, $scid) = split(/\./, $clustid);
            if (exists($out_clustid{"$cid"})) {
                next;
            }
            elsif (exists($out_clustid{"$cid.$scid"})) {
                next;
            }
            else {
                if ($scid eq '') {
                    $hash_out_clustid{"$cid"} = 1;
                }
                else {
                    $hash_out_clustid{"$cid.$scid"} = 1;
                    $hash_out_clustid{"$cid.0"} = 1;
                }
            }
        }

        #
        my(@list_out_clustid) = sort $sfunc_ref keys(%hash_out_clustid);
        foreach my$clustid (@list_out_clustid) {
            my(%orf_clust) = getClustOrfsFromMysql($Args{'tabid'}, $clustid);

            print exec_getseq($progname, "-text $OPT", %orf_clust);
        }
    }
    exit(0);

} elsif ($Args{'homclust'}) {
    ## Find Homologous Clusters
    my($cmd);
    local(*SEL);
    my($entnames) = join(',', @entnames); $entnames =~ s/\(\d+\)//g;
    my($entcnt) = 0+@entnames;
    my(%Cnt);

    #
    my($select_spec) = '';
    my(%default_species);
    if ($Args{'tabid'} =~ /^addspec$/i) {
        my($default_species) = main::getSpeciesForAddspec({'hgenes' => \@entnames});
        foreach my$sp (split(/\,/, $default_species)) {
            $default_species{"$sp"} = 1;
        }
        $select_spec = join(',', keys(%default_species));
    }

    $paramfile = $WWW->uInfo->paramfile;

    $cmd = "$CMD_select -GetParam=$paramfile -FILTER -GENES2=$entnames";
    $cmd .= " -SPEC=$select_spec" if ($select_spec ne '');
    print STDERR  "CMD :: $cmd\n" if ($main::DEBUG);
    open(SEL, "$cmd |") || die "Can not execute $cmd($!)";
    while (<SEL>) {
        ($a, $b, $from1,$to1,$from2,$to2,$dist,$score) = split;

        if ($Args{'tabid'} =~ /^addspec$/i) {
            my($sp1, $name1) = split(/\:/, $a);
            my($sp2, $name2) = split(/\:/, $b);
            if (!exists($default_species{"$sp1"})) {
                next;
            }
            if (!exists($default_species{"$sp2"})) {
                next;
            }
        }

        if ($ORF{$b}) {
            $Score{$a} += $score;
            $Dist{$a} += $dist;
            $Cnt{$a}++;
        } elsif ($ORF{$a}) {
            $Score{$b} += $score;
            $Dist{$b} += $dist;
            $Cnt{$b}++;
        }
    }
    close(SEL);
    foreach $g (keys %Cnt) {
        my $score = int($Score{$g} / $Cnt{$g});
        my $dist = int($Dist{$g} / $Cnt{$g});
        if ($orfs) {
            $orfs .= "&";
        }
        $orfs .= "hgenes=$g,$Dist{$g},$Score{$g},$Cnt{$g}";
    }
    $ENV{'REQUEST_METHOD'} = '';
    my($qopt) = "$orfs&motif=1&qcount=$entcnt&tabid=$Args{tabid}";
    if ($Args{'annotsp'} !~ /^\s*$/) {
        $qopt .= "&annotsp=$Args{'annotsp'}";
    }
	exec(qq{$WWWROOT/htbin/cluster -STDIN<<EOF
$qopt&
EOF
});

} elsif ($Args{'phylopat'}) {
    my(%spfound,$sp,$phylopat);
    foreach $name0 (@entnames) {
        my ($sp,$name) = split(/:/,$name0);
        $spfound{$sp} = 1;
    }

    my(@default_spec_list) = main::MBGD_SpecTableGetDefaultSpecies();
    my($default_spec_hash_ref) = {};
    foreach my$sp (@default_spec_list) {
        $default_spec_hash_ref->{"$sp"} = 1;
    }

    my(@sp_list) = split(/,/, $specs);
    if ($Args{tabid} =~ /^addspec$/i) {
        @sp_list = main::MBGD_SpecTableGetAllSpec();
    }
    foreach $sp (@sp_list) {
        if ($spfound{$sp}) {
            $phylopat .= 'o';
        }
        elsif (($Args{tabid} =~ /^addspec$/i) && !exists($default_spec_hash_ref->{"$sp"})) {
            $phylopat .= '_';
        }
        else {
            $phylopat .= 'x';
        }
    }
    my($qopt) = "show_summary=1&tabid=$Args{tabid}&mismatch=$Args{mismatch}&existsp=$phylopat&map_type=$Args{map_type}";
    exec(qq{$WWWROOT/htbin/cluster<<EOF
$qopt&
EOF
});
}

$entnames = "'" . join("' '", @entnames) . "'";
$cutoff = $Args{'cutoff'};
$Color = 1 if ($Args{'Color'});

%html_opt = ();

$html_opt{-style} = {src=>['/css/mbgd.css', '/css/mbgd_button.css']};
$html_opt{-script} = {src=>'/js/mbgd.js'};
if ($cmdname eq 'mali') {
    $Color = 1;
    $html_opt{-title} = "Multiple Sequence Alignment";
    $html_opt{-style} = {src=>"/css/mbgd_ali.css"};
} elsif ($cmdname eq 'hcluster') {
    $html_opt{-title} = "Cluster";
}
$html_opt{-onload} = "setup_tab_action();";

$WWW->start_html(%html_opt);

        print "<style type=\"text/css\">\n";
        print ".popup_menu {\n";
        print "  position         : absolute;\n";
        print "  visibility       : hidden;\n";
        print "  cursor           : pointer;\n";
        print "  left             : 0px;\n";
#        print "  font-size        : small;\n";
        print "  background-color : #e8f8e8;\n";
        print "  border           : 2px solid green;\n";
        print "}\n";
        print "\n";
        print ".menu_tab_sel {\n";
        print "  background-color : #d8f0d8;\n";
        print "  cursor           : pointer;\n";
        print "  font-size        : large;\n";
#        print "  font-weight      : bold;\n";
        print "  text-decoration  : none;\n";
        print "  color            : black;\n";
        print "}\n";
        print ".menu_tab {\n";
        print "  background-color : #b0d2b0;\n";
        print "  cursor           : pointer;\n";
        print "  font-size        : large;\n";
#        print "  font-weight      : bold;\n";
        print "  text-decoration  : underline;\n";
        print "  color            : black;\n";
        print "}\n";
        print "</style>\n";
        print "\n";

        print '<script language="JavaScript" src="/js/hcluster.js" type="text/javascript"></script>' . "\n";

print "<H2> Ortholog Cluster "; # $Args{clustid}";
if ($cmdname eq 'hcluster') {
    print "</H2>\n";
} elsif ($cmdname eq 'mali') {
    print "Multiple alignment ";
    print "(ClustalW)" if ($progname eq 'clustal');
    print "(MAP)" if ($progname eq 'map');
    print "(MAFFT)" if ($progname eq 'mafft');
    print "</H2>\n";
} else {
    print "detailed comparison </H2>\n";
}

if ($cmdname eq 'hcluster') {
    my($OPT, $DISPOPT);
    my($cmd);
    local(*INFO);

    if (! $Args{'method'}) {
        $Args{'method'} = 'mean';
    }

    if ($Args{matvalues} eq 'score') {
        $OPT .= " -S";
    }
    if ($cutoff) {
        $OPT .= " -c$cutoff";
    }
    else {
    }
    $OPT .= " -o1 -n1";
    $DISPOPT = " -SHOW_ALLDIST" if ($progname eq 'distmat');

    # Obtaining the clustering tree
    if ($EXEC_CLUSTER) {
        undef(@treeRes) if (!$Args{'distmat'});
        undef(@distRes);
        $paramfile = $WWW->uInfo->paramfile;
        my($cmd) = "$WWWROOT/bin/hcluster.pl -paramfile=$paramfile -OPT='$OPT' $DISPOPT $entnames";
        print STDERR "Exec :: $cmd\n" if ($main::DEBUG);
        open(CLST, "$cmd |") || die "";
        while (<CLST>) {
            next if (/^#/);
            last if (m#^//#);
s#[\r\n]*$##;
            push(@treeRes, $_) if (!$Args{'distmat'});
        }
        if ($progname eq 'distmat') {
            push(@distRes, "#####\n");
            while (<CLST>) {
                push(@distRes, $_);
            }
        }
        close(CLST);
    }

    if (!$EXEC_CLUSTER || $Args{'distmat'}) {
        if (defined @treeRes) {
            ## already defined
        } elsif ($Args{clustid}){
            push(@treeRes, &readClustTree($Args{tabid}, $Args{clustid}));
        } elsif (@clustList) {
            foreach $cl (@clustList) {
                push(@treeRes, &readClustTree($Args{tabid}, $cl), "\n");
            }
        }
    }

    # treeRes  parse
    my($tree_list_ref) = parseMultiTree(\@treeRes);

        # superkingdom / phylum ˴ؤ
        my($tax) = MBGD::Taxonomy->new();
        my(@all_spec) = $tax->get_all_spec();
        my($species_ref) = {};
        foreach my$superkingdom ( @Superkingdoms ) {
            my(@Phylum)  = ();
            my(@Class)   = ();
            $tax->find_tree(\@Phylum, {
                            match_rank => 'superkingdom',
                            match_name => $superkingdom,
                            get_rank => 'phylum'});

            #
            $species_ref->{'kingdom,phylum'}->{"$superkingdom"} = \@Phylum;
            foreach my$phylum (@Phylum) {
                # eliminate genomes of different strains in the same species
                my @spnames = $tax->get_species( {
                                                match_rank => 'phylum',
                                                match_name => $phylum,
#                                                one_strain => 'genus',
                                                });
                $species_ref->{'kingdom,phylum,sp'}->{"$superkingdom"}->{"$phylum"} = \@spnames;

                next if ($phylum !~ /^Proteobacteria$/i);

                #
                $tax->find_tree(\@Class, {
                                match_rank => 'phylum',
                                match_name => $phylum,
                                get_rank => 'class'});
                $species_ref->{'kingdom,phylum,class'}->{"$superkingdom"}->{"$phylum"} = \@Class;
                foreach my$class (@Class) {
                    my @spnames = $tax->get_species( {
                                                    match_rank => 'class',
                                                    match_name => $class,
#                                                    one_strain => 'genus',
                                                    } );
                    $species_ref->{'kingdom,phylum,class,sp'}->{"$superkingdom"}->{"$phylum"}->{"$class"} = \@spnames;
                }
            }
        }

        #
        my(@sporf_list);
        my($sporf_ref) = {};

        #  Tree  parse checkbox  index ʤɤ
        # 饹̤ descr 
        my($db) = MBGD::DB->new($ENV{'MYSQL_DB'});
        my($orfnum) = 0;
        my($sporf_ref) = {};
        my($file_cons_title_conf) = "$ENV{'MBGD_HOME'}/etc/ConsenseTitle.conf";
        my($cons_title_ref) = ConsenseTitle->new($file_cons_title_conf);
        foreach my$line (@treeRes) {
            if ($line =~ /^Cluster\s+(\d+)/) {
                $sporf_ref->{'CLUSTER_ID'} = $1;
                my($cid) = $sporf_ref->{'CLUSTER_ID'};
                if (exists($clust_addspec_ref->{"$cid"})) {
                    my($clust_ref) = $clust_addspec_ref->{"$cid"};
                    foreach my$sp (keys(%{$clust_ref})) {
                        my($clustsp_ref) = $clust_ref->{"$sp"};
                        foreach my$name (keys(%{$clustsp_ref})) {
                            my($orfname) = "$sp:$name";
                            my($gene) = MBGD::Gene->get($db, [$orfname]);
                            $sporf_ref->{"$sp"}->{"$name"} = $gene->{'descr'};
                        }
                    }
                }
            }
            elsif ($line =~ /^(.*[\+\*]\-\s+)(.*)$/) {
                $tree = $1;
                $data = $2;
next if ($data =~ /\[cluster \d/);
                ($orfdom, $from, $to) = split(/\s+/, $data);
                if ($orfdom =~ /^(.*)\((\d+)\)$/) {
                    $orfname = $1; $domain = $2;
                } else {
                    $orfname = $orfdom;
                }
                my($gene) = MBGD::Gene->get($db, [$orfname]);

                my($sp, $nm) = split(/\:/, $orfname);
                if (!exists($sporf_ref->{"$sp"})) {
                    $sporf_ref->{"$sp"} = {};
                }
                if (!exists($sporf_ref->{"$sp"}->{"$nm"})) {
                    $sporf_ref->{"$sp"}->{"$nm"} = $gene->{'descr'};
                    $cons_title_ref->set_title($gene->{'descr'});
                }

                # SP:ORF б checkbox  index ¸
                if (!exists($spname2idx_ref->{"$orfname"})) {
                    $spname2idx_ref->{"$orfname"} = [];
                }
                push(@{$spname2idx_ref->{"$orfname"}}, $orfnum);
                $orfnum++;
            }
            elsif ($line =~ /^$/) {
                my($n) = scalar(keys(%{$sporf_ref}));
                if ($n != 0) {
                    my($maxtit, $maxtit_orig, $maxscore) = $cons_title_ref->consense_title();
                    $sporf_ref->{'TITLE'} = $maxtit;
                    $cons_title_ref->clear();

                    push(@sporf_list, $sporf_ref);
                    $sporf_ref = {};
                }
            }
        }

        my(@sp_list) = keys(%{$sporf_ref});
        my($n) = scalar(@sp_list);
        if ($n != 0) {
            my($maxtit, $maxtit_orig, $maxscore) = $cons_title_ref->consense_title();
            $sporf_ref->{'TITLE'} = $maxtit;
            $cons_title_ref->clear();
            push(@sporf_list, $sporf_ref);
            $sporf_ref = {};
        }

        #  List ɽ orfname Ϥcheckbox  index ʤɤ
        my($start_orfnum_list) = $orfnum;
        foreach my$sporf_ref (@sporf_list) {
            foreach my$superkingdom (@Superkingdoms) {
                my(@phylum_list) = @{$species_ref->{'kingdom,phylum'}->{"$superkingdom"}};
                foreach my$phylum (@phylum_list) {
                    my(@splist) = @{$species_ref->{'kingdom,phylum,sp'}->{"$superkingdom"}->{"$phylum"}};
                    foreach my$sp (@splist) {
                        next if (!exists($sporf_ref->{"$sp"}));
                        my(@nmlist) = sort keys(%{$sporf_ref->{"$sp"}});
                        foreach my$nm (@nmlist) {
                            # SP:ORF б checkbox  index ¸
                            my($orfname) = join(':', $sp, $nm);
                            if (!exists($spname2idx_ref->{"$orfname"})) {
                                $spname2idx_ref->{"$orfname"} = [];
                            }
                            push(@{$spname2idx_ref->{"$orfname"}}, $orfnum);


                            $orfnum++;
                        }
                    }
                }
            }
        }

        #  DistMat ɽ orfname Ϥcheckbox  index ʤɤ
        my($start_orfnum_distmat) = $orfnum;
        $distmat_ref = parseDistmat();
        foreach my$orfname (@{$distmat_ref->{'Entnames'}}) {
            next if (!$orfname);

            push(@{$spname2idx_ref->{"$orfname"}}, $orfnum);
            $orfnum++;
        }

        #
        my($dirFunc) = "$ENV{'MBGD_HOME'}/database/function";
        my($func_ref) = {};
        foreach my$dbtype ('cog', 'kegg', 'tigr') {
            $func_ref->{"$dbtype"} = MBGD::FunctionCategory->new($dbtype, $dirFunc, 1);
        }

        #
        my($recog_conf_ref) = RECOG::RecogCommon::read_recog_conf();
        if ($Args{clustid} !~ /^\s*$/) {
            # display a cluster
            printClusterTitle($func_ref, $recog_conf_ref, @sporf_list);
        }
        else {
            # display clusters
        }

        #
        &print_javascr();
        if ($Args{'method'} eq 'max') {
            $clustmethod = 'maximum distance (complete linkage)';
        } elsif ($Args{'method'} eq 'min') {
            $clustmethod = 'minimum distance (single linkage)';
        } else {
            $clustmethod = 'UPGMA';
        }

        $measure = 'score'; $distance = 'similarity';
        print "<FORM NAME=\"clusterForm\" METHOD=\"POST\" action=\"/htbin/RECOG/hcluster\">";

        #
        print <<EOB;
<div id="popup_alignment" class="popup_menu">
<div style="text-align:right; "><a href="" onclick="setVisibleMenu('popup_alignment', false); return false;" >[close]</a></div>
<table bordercolor="green" cellspacing="0" border="0">
<tr>
<td class="button"><a href="" onclick="exec_alignment('clustal'); return false;">ClustalW</a></td>
<td class="button"><a href="" onclick="exec_alignment('map'); return false;">MAP</a></td>
<td class="button"><a href="" onclick="exec_alignment('mafft'); return false;">MAFFT</a></td>
</tr>
</table>
<input type="radio" name="align_seqtype" value="aaseq" checked>Protein<br>
<input type="radio" name="align_seqtype" value="ntseq">DNA
(additional bases:
upstream<input type="text" name="align_up" value="" size="5">
downstream<input type="text" name="align_down" value="" size="5">
)
<div style="text-align:right; "><a href="" onclick="changeAlignmentParameters(); return false;" >[Change Parameters]</a></div>
</div>
EOB

        #
        print <<EOB;
<div id="popup_sequence" class="popup_menu">
<div style="text-align:right; "><a href="" onclick="setVisibleMenu('popup_sequence', false); return false;" >[close]</a></div>
<table>
<tr>
<td class="button" nowrap><a href="" class="button" onclick="exec_get_sequence('aaseq'); return false;">Protein</a>
<a href="" onclick="exec_get_sequence('ntseq'); return false;">DNA</a>
(additional bases:
upstream<input type="text" name="getseq_up" value="" size="1">
downstream<input type="text" name="getseq_down" value="" size="1">
)
</td>
</tr>
</table>
</div>
EOB

        #
        print "<div id=\"popup_distmat\" class=\"popup_menu\">\n";
        print "<div style=\"text-align:right; \"><a href=\"\" onclick=\"setVisibleMenu('popup_distmat', false); return false;\" >[close]</a></div>\n";
        print "<table>\n";
        print "<tr>\n";
        print "<td class=\"button\" nowrap><a href=\"\" class=\"button\" onclick=\"exec_distmat(); return false;\">Distance Matrics</a>\n";
        print "</td>\n";
        print "<td>\n";
        print "Cutoff<input type=\"text\" name=\"cutoff\" value=\"$Args{cutoff}\" size=\"3\">\n";
        my($staPam)   = $Args{'matvalues'} eq "pam"   ? "CHECKED" : "";
        my($staScore) = $Args{'matvalues'} eq "score" ? "CHECKED" : "";
        print "<label><input type=\"radio\" name=\"matvalues\" value=\"pam\"   $staPam>PAM</label>\n";
        print "<label><input type=\"radio\" name=\"matvalues\" value=\"score\" $staScore>Score</label>\n";
        print "</td>\n";
        print "</tr>\n";
        print "</table>\n";
        print "\n";
        print "</div>\n";

        #
        my($class_tab_summary) = 'menu_tab_sel';
        my($class_tab_list) = 'menu_tab';
        my($class_tab_tree) = 'menu_tab';
        my($tabColSummary) = '#d8f0d8';     # ɽ
        my($orfVisSummary) = 'block';
        my($tabColList) = '#b0d2b0';     # ɽ
        my($orfVisList) = 'none';
        if ($Args{'display_function'} || $Args{'display_motif'}) {
            $tabColSummary = '#b0d2b0';     # ɽ
            $orfVisSummary = 'none';
            $tabColList = '#d8f0d8';     # ɽ
            $orfVisList = 'block';
        }
        elsif ($Args{'distmat'}) {
            $tabColSummary = '#b0d2b0';     # ɽ
            $orfVisSummary = 'none';
            $tabColList = '#b0d2b0';     # ɽ
            $orfVisList = 'none';
        }

        #
        print "<p>";
        print "<table border=\"0\">";
        print "<tr>";

        # Summary
        print "<td id=\"tab_summary\" align=\"center\" class=\"$class_tab_summary\">\n";
        print "[ Summary ]</td>\n";

        # List
        print "<td id=\"tab_list\" align=\"center\" class=\"$class_tab_list\">\n";
        print "[ Gene List ]</td>\n";

        # Tree
        print "<td id=\"tab_tree\" align=\"center\" class=\"$class_tab_tree\">\n";
        print "[ Clustering Tree ]</td>\n";

        #
        print "</tr>\n";
        print "</table>\n";

        #
        print "<table border>";
        print "<tr><td>";
        print "<table border=\"0\">";
        print "<tr>";

        # Compare maps
        print "<td id=\"tab_maps\" align=\"center\" class=\"button\">\n";
        print "<a>Compare maps</a>";
        print "</td>\n";

        # Multiple alignment
        print "<td id=\"tab_alignment\" align=\"center\" class=\"button\">\n";
        print "<a>Multi-align</a>";
        print "</td>\n";

        # Get sequence
        print "<td id=\"tab_sequence\" align=\"center\" class=\"button\">\n";
        print "<a>Get seq</a>";
        print "</td>\n";

        # Draw tree
        print "<td id=\"tab_clustering_tree\" align=\"center\" class=\"button\">\n";
        print "<a>Draw tree</a>";
        print "</td>\n";

        # Distance Matrix
#        print "<td id=\"tab_distmat\" align=\"center\" class=\"button\">\n";
#        print "<a>Dist-matrix</a>";
#        print "</td>\n";

        # Find homologous clusters
#        print "<td id=\"tab_homclust\" align=\"center\" class=\"button\">\n";
#        print "<a>Find homologs</a>";
#        print "</td>\n";

        # Similar phylopat
#        print "<td id=\"tab_phylopat\" align=\"center\" class=\"button\">\n";
#        print "<a>Similar phylopat</a>";
#        print "</td>\n";

        # KEGG pathway
        print "<td id=\"tab_kegg\" align=\"center\" class=\"button\">\n";
        print "<a>KEGG pathway</a>";
        print "</td>\n";

        #
        print "</tr>\n";
        print "</table>\n";
        print "</td></tr>\n";
        print "</table>\n";


        #
	# Clustering Tree
	#
        print "<div id=\"orf_tree\" style=\"display: none;\">\n";

        print "<TABLE BORDER=3 CELLPADDING=2>\n";
        print "<tr><td>\n";
        print "<b>Note:</b> The tree(s) presented here is created by $clustmethod clustering method from the incomplete distance matrix where $measure is used as $distance measure. Try ClustalW alignment for more precise phylogenetic tree. <br>\n";
        if (&checkMergedCluster(@treeRes)) {
            print "<b>Note:</b> This is a merged cluster that consists of overlapping multiple trees. ";
            print "The internal nodes marked with <FONT color=red>*</FONT> are overlapping nodes. ";
#            print "See also <A HREF=/htbin/drawClusterTree.pl?clustid=$Args{clustid}&tabid=$Args{tabid}>graphical tree output</A>.\n";
        }
        print "</td></tr>\n";

        my($orfnum_tree) = 0;
        my($prev_cluster_id) = 0;
        foreach $tree_ref (@{$tree_list_ref}) {
            if (($Args{clustid} =~ /^\s*$/) && ($prev_cluster_id != $tree_ref->{'CLUSTER_ID'})) {
                print "<tr><td>\n";
                printClusterTitle($func_ref, $recog_conf_ref, $tree_ref);
                print "</td></tr>";
            }
            print "<tr><td><pre>";
            print "Cluster $tree_ref->{'CLUSTER_ID'}<br>\n";
            printTree($tree_ref, '', 'RL', \$orfnum_tree);
            print "</pre></td></tr>\n";

            $prev_cluster_id = $tree_ref->{'CLUSTER_ID'};
        }
        print "</TABLE>\n";

        print "</div>\n";

        #
        print "<div id=\"orf_list\" style=\"display: $orfVisList;\">\n";
        print "<table border=\"3\" cellpadding=\"2\" style=\"table-layout:fixed;\">\n";

        print "<tr>\n";
        print "<td colspan=\"99\">";
        my($staDispFunc) = '';
        if ($Args{display_function}) {
            $staDispFunc = 'checked';
        }
        my($staDispMotif) = '';
        if ($Args{display_motif}) {
            $staDispMotif = 'checked';
        }
        print "<input type=\"button\" name=\"\" value=\"Redraw\" onclick=\"redraw_ortholog_cluster();\">\n";
        print "<input type=\"checkbox\" name=\"display_function\" value=\"on\" $staDispFunc>Display xref-ortholog\n";
        print ' ';
        print "<input type=\"checkbox\" name=\"display_motif\" value=\"on\" $staDispMotif>Display xref-motif\n";
        print "(cutoff <input type=\"text\" name=\"cutoff_motif\" value=\"$Args{'cutoff_motif'}\" size=\"10\">)\n";
        print "</td>\n";
        print "</tr>\n";

        $orfnum = $start_orfnum_list;
        foreach my$sporf_ref (@sporf_list) {
            my($OUT_kingdom) = '';
            my($print_kingdom) = 0;
            my($begin_kingdom) = $begin;
            foreach my$superkingdom (@Superkingdoms) {
                my($n_row_kingdom) = 0;
                my($OUT_phylum) = '';
                my($print_phylum) = 0;
                my(@phylum_list) = @{$species_ref->{'kingdom,phylum'}->{"$superkingdom"}};
                my($begin_phylum) = $begin_kingdom;

                #
                my(@orfname_kingdom);
                foreach my$phylum (@phylum_list) {
                    my($n_row_phylum) = 0;
                    my(@splist) = @{$species_ref->{'kingdom,phylum,sp'}->{"$superkingdom"}->{"$phylum"}};
                    $OUT = '';
                    my(@orfname_phylum);
                    foreach my$sp (@splist) {
                        next if (!exists($sporf_ref->{"$sp"}));

                        my(@nmlist) = sort keys(%{$sporf_ref->{"$sp"}});
                        my($n_print) = 0;
                        my($n_row_sp) = scalar(@nmlist);
                        $n_row_phylum += $n_row_sp;
                        $n_row_kingdom += $n_row_sp;

                        #
                        foreach my$nm (@nmlist) {
                            my($orfname) = "$sp:$nm";
                            my($descr) = $sporf_ref->{"$sp"}->{"$nm"};
                            if ($n_print == 0) {
                                my($genome_ref) = MBGD::Genome->get(MBGD::DB->new($main::DBNAME_MBGD), [$sp]);
                                $OUT .= "<td rowspan=\"$n_row_sp\" valign=\"top\">";
                                $OUT .= "<i>".$genome_ref->{'orgname'} ."</i>";
                                if ($genome_ref->{'strain'} ne '') {
                                    $OUT .= ' ' . $genome_ref->{'strain'};
                                }
                                $OUT .= "</td>\n"
                            }
                            else {
                                $OUT .= "<tr>\n"
                            }
                            my($staChecked) = '';
                            if ($ORF_checked{"$orfname"}) {
                                $staChecked = 'checked';
                            }
                            my($orf_idx) = join(',', @{$spname2idx_ref->{"$orfname"}});
                            $OUT .= "<td nowrap>";
                            $OUT .= "<INPUT TYPE=checkbox NAME=orfs VALUE=\"$orfname\" onclick=\"selectOneEntry(document, $orfnum, $orf_idx)\" $staChecked>";
                            $OUT .= "<a href=\"/htbin/RECOG/RECOG_gene_info_frame.pl?name=$orfname&tabid=$Args{'tabid'}\">";
                            $OUT .= "$sp:$nm";
                            $OUT .= "</a>";
                            $OUT .= "</td>\n";

                            #
                            if ($Args{display_function}) {
                                my($link_functions) = '';
                                foreach my$dbtype ('cog', 'kegg', 'tigr') {
                                    my(@id_list) = $func_ref->{"$dbtype"}->getOrigIdBySporfOne($orfname, {'fromdb' => 1});
                                    if (scalar(@id_list) != 0) {
                                        if ($link_functions ne '') {
                                            $link_functions .= "<br>\n";
                                        }
                                        $link_functions .= "$dbtype : ";
                                        my(@link_list);
                                        foreach my$id (@id_list) {
                                            push(@link_list, "<a href=\"" . $recog_conf_ref->{"URL_xref_$dbtype"} . "$id\" target=\"$id\">$id</a>");
                                        }
                                        $link_functions .= join(',', @link_list);
                                    }
                                }
                                $OUT .= "<td nowrap>$link_functions</td>\n";
                            }

                            #
                            if ($Args{display_motif}) {
                                my($link_motifs) = '';
                                my($motif_ref) = {};
                                my($sp, $name) = split(/:/, $orfname);
                                my($sql) = "select sp,name,motlib,motid from protmotif "
                                         . "where sp='$sp' and name='$name' and eval < $Args{cutoff_motif} ";
                                my($db) = MBGD::DB->new($main::DBNAME_MBGD);
                                my($sth) = $db->execute($sql);
                                while (my$ref=$sth->fetchrow_hashref()) {
                                    my($motlib) = $ref->{'motlib'};
                                    my($motid)  = $ref->{'motid'};
                                    $motif_ref->{"$motlib"}->{"$motid"} = 1;
                                }
                                foreach my$motlib (sort(keys(%{$motif_ref}))) {
                                    my($lc_motlib) = lc($motlib);
                                    if ($link_motifs ne '') {
                                        $link_motifs .= "<br>\n";
                                    }
                                    $link_motifs .= "$motlib : ";
                                    my(@link_list);
                                    foreach my$motid (sort(keys(%{$motif_ref->{"$motlib"}}))) {
                                        push(@link_list, "<a href=\"" . $recog_conf_ref->{"URL_xref_cdd"} . "$motid\" target=\"$motid\">$motid</a>");
                                    }
                                    $link_motifs .= join(',', @link_list);
                                }
                                $OUT .= "<td nowrap>$link_motifs</td>\n";
                            }

                            $OUT .= "<td>$descr</td>\n";
                            $OUT .= "</tr>\n";

                            #
                            push(@orfname_phylum, @{$spname2idx_ref->{"$orfname"}});

                            $n_print++;
                            $orfnum++;
                        }
                    }

                    if ($OUT) {
                        $OUT_phylum .= "<tr>";
                        $OUT_phylum .= "<td rowspan=\"$n_row_phylum\" valign=\"top\">$phylum";
                        $OUT_phylum .= "<INPUT TYPE=button VALUE=ON ";
                        $OUT_phylum .= "onClick=\"";
                        $OUT_phylum .= "selectEntries(document, true, " . join(',', @orfname_phylum) . ");\"";
                        $OUT_phylum .= ">";
                        $OUT_phylum .= "<INPUT TYPE=button VALUE=OFF ";
                        $OUT_phylum .= "onClick=\"";
                        $OUT_phylum .= "selectEntries(document, false, " . join(',', @orfname_phylum) . ");\">";
                        $OUT_phylum .= "</td>";

                        $OUT_phylum .= $OUT;
                        $OUT_phylum .= "</tr>\n";
                        $print_phylum++;
                    }

                    push(@orfname_kingdom, @orfname_phylum);

                    #
                    $begin_phylum = $orfnum;
                }

                if ($OUT_phylum) {
                    $OUT_kingdom .= "<tr valign=\"top\">";
                    $OUT_kingdom .= "<td colspan=\"99\" style=\"padding-left:20px; background-color:" . $main::BGCOLOR->{$superkingdom} . ";\"><span style=\"font-weight:bold; \">$superkingdom</span>";
                    $OUT_kingdom .= "<INPUT TYPE=button VALUE=ON ";
                    $OUT_kingdom .= "onClick=\"";
                    $OUT_kingdom .= "selectEntries(document, true, " . join(',', @orfname_kingdom) . ");\"";
                    $OUT_kingdom .= ">";
                    $OUT_kingdom .= "<INPUT TYPE=button VALUE=OFF ";
                    $OUT_kingdom .= "onClick=\"";
                    $OUT_kingdom .= "selectEntries(document, false, " . join(',', @orfname_kingdom) . ");\"";
                    $OUT_kingdom .= ">\n";
                    $OUT_kingdom .= "<br>\n";

                    $OUT_kingdom .= "<table width=\"100%\" border>\n";
                    $OUT_kingdom .= "<tr><th>Phylum</th>";
                    $OUT_kingdom .= "    <th>Species</th>\n";
                    $OUT_kingdom .= "    <th>Orf ID</th>\n";
                    $OUT_kingdom .= "    <th>Xref-Ortholog</th>\n" if ($Args{'display_function'});
                    $OUT_kingdom .= "    <th>Xref-Motif</th>\n" if ($Args{'display_motif'});
                    $OUT_kingdom .= "    <th>Description</th>\n";
                    $OUT_kingdom .= "</tr>\n";
                    $OUT_kingdom .= $OUT_phylum;
                    $OUT_kingdom .= "</table>\n";
                    $OUT_kingdom .= "</td>";
                    $OUT_kingdom .= "</tr>\n";

                    #
                    push(@orfname_cluster, @orfname_kingdom);

                    #
                    $print_kingdom++; 
                }

                #
                $begin_kingdom = $orfnum;
            }

            if ($OUT_kingdom ne '') {
                print "<tr><td colspan=\"99\">\n";
                if ($Args{clustid} !~ /^\s*$/) {
                    # display a cluster
#                    print "Cluster ", $sporf_ref->{'CLUSTER_ID'};
                }
                else {
                    #display clusters
                    printClusterTitle($func_ref, $recog_conf_ref, $sporf_ref);
                }
                print "<INPUT TYPE=button VALUE=ON onClick=";
                print "selectEntries(document,true,", join(',', @orfname_cluster), ")>";
                print "<INPUT TYPE=button VALUE=OFF onClick=";
                print "selectEntries(document,false,", join(',', @orfname_cluster), ")>";
                print "</td>\n";
                print "</tr>\n";


                print $OUT_kingdom;

                $begin = $orfnum;
                $OUT_kingdom = '';
                @orfname_cluster = ();
            }
            print "<tr><td colspan=\"99\"><hr size=5></td></tr>";
        }
        print "</table>\n";
        print "</div>\n";

        #
        print "<div id=\"orf_summary\" style=\"display: $orfVisSummary;\">\n";
        print "<table border=\"3\" cellpadding=\"2\" style=\"table-layout:fixed;\">\n";

        $orfnum = $start_orfnum_list;
        foreach my$sporf_ref (@sporf_list) {
            my($OUT_kingdom) = '';
            foreach my$superkingdom (@Superkingdoms) {
                my($n_row_kingdom) = 0;
                my($OUT_phylum) = '';
                my(@phylum_list) = @{$species_ref->{'kingdom,phylum'}->{"$superkingdom"}};

                #
                my(@orfname_kingdom);
                foreach my$phylum (@phylum_list) {
                    if (exists($species_ref->{'kingdom,phylum,class'}->{"$superkingdom"}->{"$phylum"})) {
                        my(@class_list) = @{$species_ref->{'kingdom,phylum,class'}->{"$superkingdom"}->{"$phylum"}};
                        my(@out_list);
                        foreach my$class (@class_list) {
                            my(@splist) = @{$species_ref->{'kingdom,phylum,class,sp'}->{"$superkingdom"}->{"$phylum"}->{"$class"}};
                            my(@disp_splist);
                            foreach my$sp (@splist) {
                                push(@disp_splist, $sp) if (exists($spec_hash{"$sp"}));
                            }
                            my($out) = build_summary_orfs($sporf_ref, @disp_splist);
                            if ($out ne '') {
                                my($out_ref) = {};
                                $out_ref->{'CLASS'} = $class;
                                $out_ref->{'OUT'}   = $out;
                                push(@out_list, $out_ref);
                            }
                        }

                        $OUT_class = '';
                        my($n_out) = scalar(@out_list);
                        my($idx_out) = 0;
                        foreach my$out_ref (@out_list) {
                            my($class) = $out_ref->{'CLASS'};
                            my($out)   = $out_ref->{'OUT'};
                            $OUT_class .= "<tr>";
                            $OUT_class .= "<td valign=\"top\" rowspan=\"$n_out\" nowrap>$phylum" if ($idx_out == 0);
                            $OUT_class .= "<td>$class</td>";
                            $OUT_class .= "<td>";
                            $OUT_class .= $out;
                            $OUT_class .= "</td>";
                            $OUT_class .= "</tr>" if ($idx_out != 0);
                            $idx_out++;
                        }

                        if ($OUT_class ne '') {
                            $OUT_phylum .= $OUT_class;
                        }
                    }
                    else {
                        my(@splist) = @{$species_ref->{'kingdom,phylum,sp'}->{"$superkingdom"}->{"$phylum"}};
                            my(@disp_splist);
                            foreach my$sp (@splist) {
                                push(@disp_splist, $sp) if (exists($spec_hash{"$sp"}));
                            }
                        $OUT = build_summary_orfs($sporf_ref, @disp_splist);
                        if ($OUT) {
                            $OUT_phylum .= "<tr>";
                            $OUT_phylum .= "<td valign=\"top\" nowrap>$phylum";
                            $OUT_phylum .= "</td>\n";
                            $OUT_phylum .= "<td colspan=\"2\" nowarap>\n";
                            $OUT_phylum .= $OUT;
                            $OUT_phylum .= "</td>\n";
                            $OUT_phylum .= "</tr>\n";
                        }
                    }
                }

                if ($OUT_phylum) {
                    $OUT_kingdom .= "<tr valign=\"top\">";
                    $OUT_kingdom .= "<td colspan=\"99\" style=\"padding-left:20px; background-color:" . $main::BGCOLOR->{$superkingdom} . ";\"><span style=\"font-weight:bold; \">$superkingdom</span>";
                    $OUT_kingdom .= "<br>\n";
                    $OUT_kingdom .= "<table width=\"100%\" border>\n";
                    $OUT_kingdom .= $OUT_phylum;
                    $OUT_kingdom .= "</table>\n";
                    $OUT_kingdom .= "</td>";
                    $OUT_kingdom .= "</tr>\n";
                }
            }

            if ($OUT_kingdom ne '') {
                if ($Args{clustid} =~ /^\s*$/) {
                    #display clusters
                    print "<tr><td colspan=\"99\">\n";
                    printClusterTitle($func_ref, $recog_conf_ref, $sporf_ref);
                    print "</td>\n";
                    print "</tr>\n";
                }
                print $OUT_kingdom;

                $OUT_kingdom = '';
                @orfname_cluster = ();
            }
            print "<tr><td colspan=\"99\"><hr size=5></td></tr>";
        }
        print "</table>\n";
        print "</div>\n";

        #
        print "<div id=\"orf_distmat\" style=\"display: $orfVisDistMat;\">\n";
        if ($Args{'distmat'}) {
            printDistmat($distmat_ref, $start_orfnum_distmat);
        }
        print "</div>\n";


        print "<hr>\n";

        #
        print "<input type=\"hidden\" name=\"clustid\" value=\"$Args{'clustid'}\">\n";

        #
        my(@cluster_list);
        if (ref($Args{'cluster'}) eq 'ARRAY') {
            @cluster_list = @{$Args{'cluster'}};
        }
        else {
            @cluster_list = $Args{'cluster'};
        }
        foreach my$cluster (@cluster_list) {
            print "<input type=\"hidden\" name=\"cluster\" value=\"$cluster\">\n";
        }

        #
        $entarg = $entnames;
        $entarg =~ s/ /,/g;

        #
        print "<INPUT TYPE=hidden NAME=drawmap VALUE=\"\">\n";
        print "<INPUT TYPE=hidden NAME=prog VALUE=clustal>\n";
        print "<INPUT TYPE=hidden NAME=mali VALUE=\"\">\n";
#	     print "[<A HREF=\"/htbin/SetParamScreen.pl?class=MalignParam\">Set parameters</A>]\n";

        print "<INPUT TYPE=hidden NAME=seqtype VALUE=\"\">\n";
        print "<INPUT TYPE=hidden NAME=up      VALUE=\"\">\n";
        print "<INPUT TYPE=hidden NAME=down    VALUE=\"\">\n";
        print "<INPUT TYPE=hidden NAME=getseq  VALUE=\"\">\n";

        print "<INPUT TYPE=hidden NAME=\"size\" VALUE=\"17,11\">\n";
        print "<INPUT TYPE=hidden NAME=\"drawtree\" VALUE=\"\">\n";

        print "<INPUT TYPE=hidden NAME=method  VALUE=\"mean\">\n";
        print "<INPUT TYPE=hidden NAME=allorfs VALUE=$entarg>\n";
        print "<INPUT TYPE=hidden NAME=distmat VALUE=\"\"><br>\n";
        print "<INPUT TYPE=hidden NAME=tabid VALUE=\"$Args{'tabid'}\"><br>\n";

        print "<div id=\"popup_homclust\" class=\"popup_menu\">\n";
        print "<INPUT TYPE=hidden NAME=homclust VALUE=\"\"><br>\n";
        print "</div>\n";

        #
        print "<div id=\"popup_phylopat\" class=\"popup_menu\">\n";
        print "<div style=\"text-align:right; \"><a href=\"\" onclick=\"setVisibleMenu('popup_phylopat', false); return false;\" >[close]</a></div>\n";
        my($mismatch) = int($::Args{'mismatch'});
        $mismatch = 0 if ($mismatch < 0);
        my($n_spec_list) = scalar(@spec_list);
        print "
<script>
function set_mismatch_percent() {
    var doc = this.document;
    var frm = doc.clusterForm;
    var max_spec = $n_spec_list;

    var percent = parseFloat(frm.mismatch_percent.value);
    var mismatch = parseInt(max_spec * percent / 100);
    if ((mismatch < 0) || (isNaN(mismatch))) {
        mismatch = 0;
    }
    else if (max_spec < mismatch) {
        mismatch = max_spec;
    }
    frm.mismatch.value = mismatch;

    return;
}
</script>
";

        print "<input type=\"text\" name=\"mismatch\" value=\"$mismatch\" size=\"3\">\n";
        print "mismatch(es)\n";
        print "(";
        print "<input type=\"text\" name=\"mismatch_percent\" value=\"\" size=\"5\">";
        print "<input type=\"button\" name=\"set_mismatch\" value=\"%\" onclick=\"set_mismatch_percent();\">";
        print ")<br />\n";
        print "<INPUT TYPE=\"hidden\" NAME=\"show_summary\" VALUE=\"occpat\">\n";
        print "<INPUT TYPE=\"hidden\" NAME=\"map_type\" VALUE=\"occpat\">\n";
        print "<INPUT TYPE=\"submit\" NAME=\"phylopat\" VALUE=\"Search\">\n";
        print "</div>\n";
        print "</FORM>\n";

        #
        printFormForRedraw(%Args);

        #
        print "<script>\n";
        print "var SAVE_distmat   = '$Args{'distmat'}';\n";
        print "var SAVE_cutoff    = document.clusterForm.cutoff.value;\n";
        print "var SAVE_matvalues = getDistmatType();\n";
        print "\n";
        print "function getDistmatType() {\n";
        print "  var type = 'score';\n";
        print "  for (var i = 0; i < document.clusterForm.matvalues.length; i++) {\n";
        print "    if (document.clusterForm.matvalues[i].checked) {\n";
        print "      type = document.clusterForm.matvalues[i].value\n";
        print "      break;\n";
        print "    }\n";
        print "  }\n";
        print "  return type\n";
        print "}\n";
        print "function changeDistmatOpt() {\n";
        print "  if (SAVE_cutoff != document.clusterForm.cutoff.value) {\n";
        print "      return true;\n";
        print "  }\n";
        print "\n";
        print "  var type = getDistmatType();\n";
        print "  if (SAVE_matvalues != type) {\n";
        print "    return true;\n";
        print "  }\n";
        print "  return false;\n";
        print "}\n";
        print "\n";
        print "</script>\n";

        &kegg_link(@entnames);
#        $WWW->page_footer;
        $WWW->end_html;
    } elsif ($cmdname eq 'mali') {
        &exec_malign($entnames);
    }

#print "</HTML>\n";
exit(0);


###############################################################################
#
sub print_javascr {
	print qq|
<SCRIPT LANGUAGE="JavaScript">
<!-------
function selectAll(document,begin,end,value) {
	for (var i = begin; i < end; i++) {
		document.clusterForm.orfs[i].checked = value;
	}
}
function toggleEntry(document,idx, args) {
    var sta = document.clusterForm.orfs[idx].checked;
    for (var ii = 1; ii < toggleEntry.arguments.length; ii++) {
        var i = toggleEntry.arguments[ii];
        if (i < document.clusterForm.orfs.length) {
            document.clusterForm.orfs[i].checked = !sta;
        }
	}
}
function selectOneEntry(document,idx, args) {
    var sta = document.clusterForm.orfs[idx].checked;
    for (var ii = 2; ii < selectOneEntry.arguments.length; ii++) {
        var i = selectOneEntry.arguments[ii];
        if (i < document.clusterForm.orfs.length) {
            document.clusterForm.orfs[i].checked = sta;
        }
	}
}
function selectEntries(document, value, args) {

	for (var ii = 2; ii < selectEntries.arguments.length; ii++) {
        var i = selectEntries.arguments[ii];
        if (i < document.clusterForm.orfs.length) {
    		document.clusterForm.orfs[i].checked = value;
        }
	}
}

function countCheckedEntries(document) {
    var n = 0;
    var hash = new Object();
	for (var i = 0; i < document.clusterForm.orfs.length; i++) {
		if (document.clusterForm.orfs[i].checked) {
            var orfname = document.clusterForm.orfs[i].value;
            if (hash[orfname] != 1) {
                hash[orfname] = 1;
                n++;
            }
        }
	}

    return n;
}

// ------>
</SCRIPT>
|;
}


###############################################################################
#
sub kegg_link {
	my(@orfnames) = @_;
	my($orfnames);
	my($on,$sp,$spname);
	my($kegg_gene_varname) = 'unclassified';
	foreach $on (@orfnames) {
		$orfnames .= ',' if ($orfnames);
		$orfnames .= "\"$on\"";
	}

    print "<div id=\"popup_kegg\" class=\"popup_menu\">\n";
    print "<div style=\"text-align:right; \"><a href=\"\" onclick=\"setVisibleMenu('popup_kegg', false); return false;\" >[close]</a></div>\n";
	print "<FORM METHOD=\"POST\" ACTION=\"http://www.genome.jp/kegg-bin/search_pathway_www\" NAME=\"keggForm\" target=\"_blank\">\n";
	print "<SELECT NAME=org_name onChange=selectOrg(document)>\n";

	@speclist = &MBGD_SpecTableGetAllSpec();
	print "<OPTION value=\"\"> Choose organism\n";
	foreach $sp (@speclist) {
		next if (! $orgnames{$sp});
		$spname = &MBGD_GetSpecShortName($sp);
		print "<OPTION value=\"$sp\"> $spname\n";
	}
	print "</SELECT><br>\n";
	print "<INPUT type=\"text\" NAME=\"$kegg_gene_varname\" readonly>\n";
	print "<INPUT TYPE=\"hidden\" NAME=warning VALUE=yes>\n";
	print "<INPUT TYPE=\"submit\" VALUE=\"Search\"> </FORM>\n";
    print "</div>\n";

	print qq|
<SCRIPT LANGUAGE="JavaScript">
<!-------
function selectOrg(document) {
	orfs = new Array($orfnames)
	if ((idx = document.keggForm.org_name.selectedIndex) >= 0) {
		selectedOrg = document.keggForm.org_name.options[idx].value
	}
	document.keggForm.$kegg_gene_varname.value = "";
	for (var i = 0; i < orfs.length; i++) {
		if (orfs[i].substr(0,3) == selectedOrg) {
			if (document.keggForm.$kegg_gene_varname.value) {
				document.keggForm.$kegg_gene_varname.value += " ";
			}
			document.keggForm.$kegg_gene_varname.value += orfs[i].substr(4);
		}
	}
}
// ------>
</SCRIPT>
|;
}

###############################################################################
#
sub readClustTree {
	my($tabid, $clustid) = @_;
	my $dbname = $DBNAME_RECOG;
#	$dbname = $ENV{'MYSQL_DBTMP'} if ($ENV{'MYSQL_DBTMP'});
	my $db = MBGD::DB->new($dbname);
    my $sql = "select tree from clusttree_$tabid where clustid='$clustid'";
	my $sth = $db->execute($sql);
	($tree) = $sth->fetchrow_array;

	return ("Cluster $clustid", split(/\n/, $tree));
}

###############################################################################
#
sub getClustOrfsFromMysql {
	my($tabid, $clust_list) = @_;
    my(%orf);

	my $dbname = $DBNAME_RECOG;
	my $db = MBGD::DB->new($dbname);

    my($tab) = "cluster_domclust_cache_$tabid";

    foreach my$clust (split(/,/, $clust_list)) {
        my($clustid, $subclustid) = split(/\./, $clust);
        my $sql = "select * from $tab where clustid='$clustid'";
        if ($subclustid ne '') {
            $sql .= " and subclustid=$subclustid";
        }

	    my $sth = $db->execute($sql);
        while (my$ref=$sth->fetchrow_hashref()) {
            my($spname) = $ref->{'spname'};
            my($clustid) = $ref->{'clustid'};
            my($subclustid) = $ref->{'subclustid'};
            if ($subclustid <= 0) {
                $subclustid = 'out';
            }
            $orf{"$spname"} = join('.', $clustid, $subclustid);
        }
    }

	return %orf;
}

###############################################################################
#
sub getClustOrfsFromTreeRes {
	my(@treeRes) = @_;

    my($clustid);
    my($clustorf_ref) = {};
	foreach $line (@treeRes) {
        if ($line =~ /^Cluster\s+(\d+)/) {
            $clustid = $1;
            if (!exists($clustorf_ref->{"$clustid"})) {
                $clustorf_ref->{"$clustid"} = [];
            }
        }
		elsif ($line =~ /[\+\*]\-\s*(\w+:[^\s\(\)]+)/) {
			push(@{$clustorf_ref->{"$clustid"}}, $1);
		}
	}

	return $clustorf_ref;
}

###############################################################################
#
sub getOrfsFromTreeRes {
	my(@treeRes) = @_;
	my(%orf);
	foreach $line (@treeRes) {
		if ($line =~ /[\+\*]\-\s*(\w+:[^\s\(\)]+)/) {
			$orf{$1} = 1;
		}
	}
	return %orf;
}

###############################################################################
#
sub exec_malign {
	my($entnames) = @_;
	my($Options);
	# entnames 顢ɥᥤֹ
	$entnames =~ s#\(\d+\)##g;

	$Options .= '-Color ' if ($Color);
	if ($Args{seqtype} eq 'ntseq') {
	    $Options .= '-Nuc ';
	    $Options .= "-up=$Args{up} "     if (0 < $Args{up});
	    $Options .= "-down=$Args{down} " if (0 < $Args{down});
    }
	if ($progname =~ /clustal|map|mafft/) {
		print qq|
<script>
function showAlignmentOverview() {
    var doc = this.document;
    var frm = doc.frm_alignmentOverview;
    frm.submit();

    return;
}
</script>
|;
		print qq{<FORM NAME="frm_alignmentOverview" ACTION="/htbin/RECOG/RECOG_seqreg_html.pl">\n};
		print qq{<INPUT TYPE="hidden" NAME="clustid" VALUE="$Args{clustid}">};
		print qq{<INPUT TYPE="hidden" NAME="displayMode" VALUE="MultAlign">};
		print qq{<INPUT TYPE="hidden" NAME="tabid" VALUE="$Args{tabid}">};

		print qq{<INPUT VALUE="Show Alignment Overview"  TYPE="button" onClick="showAlignmentOverview();"\n>};
		print "</FORM>\n";

		print "<PRE>\n";
        my($cmd) = "$WWWROOT/bin/clustal -cmd=$progname $Options $entnames";
        print STDERR "CMD :: $cmd\n" if ($main::DEBUG);
		system($cmd);
		print "</PRE>\n";
	}
	print "</HTML>\n";
	exit;
}

### OBSOLETE FUNCTIONS
sub exec_multigenome {
	my($input);
	my($cmd);
	if (ref $Args{'cluster'}) {
		$input = 'cluster=' . join('&cluster=', @{$Args{'cluster'}});
	} else {
		$input = "cluster=$Args{'cluster'}";
	}
	$ENV{'CONTENT_LENGTH'} = length($input);

	$cmd = "$WWWROOT/htbin/MBGD_genome_cluster.pl";

	exec("$cmd <<EOF
$input
EOF");
	## exit
}

###############################################################################
#
sub checkMergedCluster {
	my(@treeRes) = @_;
	my($flag);
	foreach $l (@treeRes) {
		if ($l =~ /^--/) {
			$flag =1;
			last;
		}
	}
	return $flag;
}

###############################################################################
#
sub parseDistmat {
    my($distmat_ref) = {};

    my(@Entnames);
    $distmat_ref->{'Entnames'} = \@Entnames;

    my(@orfnum);
    $distmat_ref->{'orfnum'} = \@orfnum;

    #
    foreach $_ (@treeRes) {
        if (/[\+\*]\-[ ]+(\w[\w:\.\-]+) *(.*)$/) {	# for domclust
            push(@Entnames, $1);
            $ORFfound{$1} = 1;
            $orfnum[$clid]++;
        }
        elsif (/\| +([0-9\.-]+)/) {
            $dist = $1;
            if ($cutoff && (($Args{matvalues} eq 'pam' && $dist > $cutoff)
                            || ($Args{matvalues} eq 'score' && $dist < $cutoff))) {
                if ($orfnum[$clid]) {
                    push(@Entnames, '');
                    $clid++;
                }
            }
        }
        elsif (/^$/) {
            if ($orfnum[$clid]) {
                push(@Entnames, '');
                $clid++;
            }
        }
    }

    #
    foreach $_ (@distRes) {
        next if (/^\s*#/);

        ($n1,$n2,$from1,$to1,$from2,$to2,$pam,$score) = split;
        if ($Args{matvalues} eq 'score') {
            $Dist{$n1,$n2} = $Dist{$n2,$n1} = $score;
        } else {
            $Dist{$n1,$n2} = $Dist{$n2,$n1} = $pam;
        }
    }

    foreach $ent (keys %ORF) {
        if (! $ORFfound{$ent}) {
            push(@Entnames, $ent);
            push(@Entnames, '');
            $orfnum[$clid]++;
            $clid++;
        }
    }

    return $distmat_ref;
}

###############################################################################
#
sub printDistmat {
    my($distmat_ref) = shift;
    my($begin) = shift;
    my($html) = '';
    my($orfnum) = $begin;
    my(@Entnames) = @{$distmat_ref->{'Entnames'}};
    my(@orfnum)   = @{$distmat_ref->{'orfnum'}};

    $clid = 0;
    $html .= "<TABLE BORDER=\"3\" CELLPADDING=\"2\">\n";


#    $html .= "<TR>";
#    $html .= "<TR><TD ROWSPAN=\"$orfnum[$clid]\">";
#    $html .= "<FONT size=\"-1\">";

    my(@entid_list) = ();
    my($html_distmat) = '';
    $flag = 1;
    foreach $n1 (@Entnames, '') {
        if ($n1) {
            push(@entid_list, @{$spname2idx_ref->{"$n1"}});
            if (! $flag) {
                $html_distmat .= "<TR>";
            }
            else {
                $flag = 0;
            }
            ($sp,$ent) = split(/:/, $n1);
            my($staChecked) = '';
            if ($ORF_checked{"$sp:$ent"}) {
                $staChecked = 'checked';
            }
            $html_distmat .= "<TH align=\"left\" nowrap>";

            my($orf_idx) = join(',', @{$spname2idx_ref->{"$sp:$ent"}});
            $html_distmat .= "<INPUT TYPE=\"checkbox\" NAME=\"orfs\" VALUE=\"$n1\" onClick=\"selectOneEntry(document, $orfnum, $orf_idx);\" $staChecked>";
            $orfnum++;
            $html_distmat .= "<A HREF=\"/htbin/RECOG/RECOG_gene_info_frame.pl?spec=$sp&name=$ent&tabid=$Args{'tabid'}\">$n1</A>";
            $html_distmat .= "</TH>";
            $begin++;
            foreach $n2 (@Entnames) {
                $html_distmat .= "<TD align=\"right\"";
                if (! $n2) {
                    $html_distmat .= ">";
                }
                elsif ( defined $Dist{$n1,$n2} &&
                        ( ($Args{matvalues} eq 'pam'
                           &&  (! $cutoff || $Dist{$n1,$n2} <= $cutoff)) ||
                          ($Args{matvalues} eq 'score'
                           && $Dist{$n1,$n2} >= $cutoff) ) ) {
                    $html_distmat .= " bgcolor=#50a050>";
                    $html_distmat .= "<FONT color=\"#ffffff\" size=\"-1\">";
                    $html_distmat .= $Dist{$n1,$n2};
                    $html_distmat .= "</FONT>";
                } else {
                    $html_distmat .= ">";
                    $html_distmat .= $Dist{$n1,$n2};
                }
                $html_distmat .= "</td>";
            }
            $html_distmat .= "</TR>\n";
        }
        else {
            if ($orfnum[$clid]) {
                $html .= "<TR></TR>";
                $html .= "<TR><TD ROWSPAN=\"$orfnum[$clid]\">";
                $html .= "<FONT size=\"-1\">";

                my($ids) = join(',', @entid_list);
                $html .= "<INPUT TYPE=\"button\" VALUE=\"ON\"  onClick=\"selectEntries(document, true,  $ids)\">";
                $html .= "<INPUT TYPE=\"button\" VALUE=\"OFF\" onClick=\"selectEntries(document, false, $ids)\">";

                $html .= "</FONT>";
                $html .= "</TD>\n";
                $html .= $html_distmat;

                $flag = 1;

                @entid_list = ();
                $html_distmat = '';

            }
            $clid++;
        }
    }

    $html .= "</TABLE>\n";

    print $html;

    return;
}

###############################################################################
#
sub getNode {
    my($tree_ref) = shift;
    my($hand_ref) = shift;
    my($pos) = shift;

    my($curr_ref) = $tree_ref;

    for(my$i = 0; $i < $pos; $i++) {
        my($hand) = $hand_ref->[$i];
        if ($hand =~ /L/i) {
            if (!exists($curr_ref->{'L'})) {
                $curr_ref->{'L'} = {};
            }
            $curr_ref = $curr_ref->{'L'};
        }
        else {
            if (!exists($curr_ref->{'R'})) {
                $curr_ref->{'R'} = {};
            }
            $curr_ref = $curr_ref->{'R'};
        }
    }

    return $curr_ref;
}

###############################################################################
#
sub parseLeaf {
    my($sp_orf_descr) = shift;
    my($ref) = {};

   ($ref->{'sp'}, $ref->{'name'}, $ref->{'descr'}) = ($sp_orf_descr =~ /(\S+)\:(\S+)\s+(\S+)/);

    return $ref;
}

###############################################################################
#
sub printTree {
    my($tree_ref) = shift;
    my($head) = shift;
    my($phand) = shift;
    my($orfnum_ref) = shift;

    my($db) = MBGD::DB->new($ENV{'MYSQL_DB'});

    #
    if (exists($tree_ref->{'SELF'})) {
        my($orfname) = $tree_ref->{'SELF'};
        $orfname =~ s#\(\d+\)$##;
        my($gene_ref) = MBGD::Gene->get($db, [$orfname]);
        my($staChecked) = '';
        if ($ORF_checked{"$orfname"}) {
            $staChecked = 'checked';
        }
        my($orf_idx) = join(',', @{$spname2idx_ref->{"$orfname"}});
        print "+- " . "<input type=\"checkbox\" name=\"orfs\" value=\"$orfname\" onclick=\"selectOneEntry(document, ${$orfnum_ref}, $orf_idx)\" $staChecked><a href=\"/htbin/RECOG/RECOG_gene_info_frame.pl?name=$tree_ref->{'SELF'}&tabid=$Args{'tabid'}\">" . $tree_ref->{'SELF'} . '</a>';
        print ' ' . $gene_ref->{'descr'};
        ${$orfnum_ref}++;
        return;
    }

    #
    if (ref($tree_ref->{'R'})) {
        my($head_new) = $head;
        if ($phand =~ /R/i) {
            $head_new .= '  ';
        }
        else {
            $head_new .= '| ';
        }
        printTree($tree_ref->{'R'}, $head_new, 'R', $orfnum_ref);
    }
    else {
        print $head;
        if ($phand =~ /R/i) {
            print '  ';
        }
        else {
            print '| ';
        }

        my($orfname) = $tree_ref->{'R'};
        $orfname =~ s#\(\d+\)$##;
        my($gene_ref) = MBGD::Gene->get($db, [$orfname]);
        my($staChecked) = '';
        if ($ORF_checked{"$orfname"}) {
            $staChecked = 'checked';
        }
        my($orf_idx) = join(',', @{$spname2idx_ref->{"$orfname"}});
        print $tree_ref->{'PAT_R'} , '- ';
	if ($tree_ref->{'R'} =~ /cluster (\d+)/) {
		my($clustid)=$1;
       		print "<A HREF=\"/htbin/RECOG/hcluster?prog=hcluster&clustid=$clustid&tabid=$Args{'tabid'}\">$tree_ref->{'R'}</a>\n";
	} else {
       		print "<input type=\"checkbox\" name=\"orfs\" value=\"$orfname\" onclick=\"selectOneEntry(document, ${$orfnum_ref}, $orf_idx)\" $staChecked>";
        	print "<A HREF=\"/htbin/RECOG/RECOG_gene_info_frame.pl?name=$orfname&tabid=$Args{'tabid'}\">$tree_ref->{'R'}</a>";
        	print " [$tree_ref->{'SC_R'}]";
        	print " $gene_ref->{'descr'}\n";
	}
        ${$orfnum_ref}++;
    }

    my($orf_list_ref) = [];
    getOrfsByNode($tree_ref, $orf_list_ref);
    my(@id_list) = ();
    foreach my$orf (@{$orf_list_ref}) {
        my($o) = ($orf =~ /^([^\(]+)/);
        push(@id_list, @{$spname2idx_ref->{"$o"}});
    }
    my($orf_ids) = join(',', @id_list);
    print $head, "<span style=\"text-decoration: none; cursor: pointer\" onclick=\"toggleEntry(document, $orf_ids); return false;\">+</span>-| " . $tree_ref->{'DIST'} . "\n";

    if (ref($tree_ref->{'L'})) {
        my($head_new) = $head;
        if ($phand =~ /L/i) {
            $head_new .= '  ';
        }
        else {
            $head_new .= '| ';
        }
        printTree($tree_ref->{'L'}, $head_new, 'L', $orfnum_ref);
    }
    else {
    print $head;
        if ($phand =~ /L/i) {
            print '  ';
        }
        else {
            print '| ';
        }

        my($orfname) = $tree_ref->{'L'};
        $orfname =~ s#\(\d+\)$##;
        my($gene_ref) = MBGD::Gene->get($db ,[$orfname]);
        my($staChecked) = '';
        if ($ORF_checked{"$orfname"}) {
            $staChecked = 'checked';
        }
        my($orf_idx) = join(',', @{$spname2idx_ref->{"$orfname"}});
        print $tree_ref->{'PAT_L'}, '- ';
	if ($tree_ref->{'L'} =~ /cluster (\d+)/) {
		my($clustid)=$1;
       		print "<A HREF=\"/htbin/RECOG/hcluster?prog=hcluster&clustid=$clustid&tabid=$Args{'tabid'}\">$tree_ref->{'L'}</a>\n";
	} else {
	        print "<input type=\"checkbox\" name=\"orfs\" value=\"$orfname\" onclick=\"selectOneEntry(document, ${$orfnum_ref}, $orf_idx)\" $staChecked>";
       		print "<A HREF=\"/htbin/RECOG/RECOG_gene_info_frame.pl?name=$orfname&tabid=$Args{'tabid'}\">$tree_ref->{'L'}</a>";
       		print " [$tree_ref->{'SC_L'}]";
        	print " $gene_ref->{'descr'}\n";
	}
        ${$orfnum_ref}++;

    }

    return;
}

###############################################################################
#
sub parseTree {
    my($tree_res_ref) = shift;

    #
    my($tree_ref) = {};
    my($hand_ref) = [];

    #
    foreach my$line (@{$tree_res_ref}) {
        $line =~ s#[\r\n]*$##;

        if ($line =~ /^([\+\*])\-\s/) {
            #
            my($sporf) = ($line =~ /[\+\*]\-\s+(\S+)/);
            $tree_ref->{'SELF'} = $sporf;
            last;
        }
        elsif ($line =~ /([\+\*])\-/) {
            my($pat) = $1;
            my($pos) = index($line, $pat) / 2 - 1;
	    my($sporf, $subclust, $dist);

	    if ($line =~ /(cluster\s+\d+)/) {
		$sporf = $1;
	    } else {
            	($sporf) = ($line =~ /[\+\*]\-\s+(\S+)/);
	        ($subclust) = ($line =~ /\[([IOo]O?\d*)\]/);
       	    	($dist) = ($line =~ /\-\|\s([\d\.]+)/);
	    }


            if ($hand_ref->[$pos] eq '') {
                $hand_ref->[$pos] = 'R';
            }

            my($n) = scalar(@{$hand_ref});
            for(my$i = $pos + 1; $i < $n; $i++) {
                my($c) = substr($line, 2 + $i * 2, 1);
                $hand_ref->[$i] = 'R';
                if ($c eq '|') {
                    $hand_ref->[$i] = 'L';
                }
            }

            if (defined($dist)) {
                my($node_ref) = getNode($tree_ref, $hand_ref, $pos + 1);
                $node_ref->{'DIST'} = $dist;
            }
            if (0 <= $pos) {
                if (defined($sporf)) {
                    my($node_ref) = getNode($tree_ref, $hand_ref, $pos);
                    $node_ref->{"$hand_ref->[$pos]"} = $sporf;
                    $node_ref->{"SC_$hand_ref->[$pos]"} = $subclust;
                    $node_ref->{"PAT_$hand_ref->[$pos]"} = $pat;
                }
            }
        }
    }

    return $tree_ref;
}

###############################################################################
#
sub parseMultiTree {
    my($tree_res_ref) = shift;
    my($tree_list_ref) = [];

    my($clusterId);
    my(@tree) = ();

    foreach my$line (@{$tree_res_ref}) {
        if ($line =~ /Cluster\s+(\d+)/) {
            my($wkClusterId) = $1;
            if (scalar(@tree) != 0) {
                my($ref) = parseTree(\@tree);
                $ref->{'CLUSTER_ID'} = $clusterId;
                push(@{$tree_list_ref}, $ref);
                @tree = ();
            }
            $clusterId = $wkClusterId;
        }
        elsif ($line =~ /^\-+$/) {
            if (scalar(@tree) != 0) {
                my($ref) = parseTree(\@tree);
                $ref->{'CLUSTER_ID'} = $clusterId;
                push(@{$tree_list_ref}, $ref);
                @tree = ();
            }
        }

        push(@tree, $line);
    }

    if (scalar(@tree) != 0) {
        my($ref) = parseTree(\@tree);
        $ref->{'CLUSTER_ID'} = $clusterId;
        push(@{$tree_list_ref}, $ref);
    }

    return $tree_list_ref;
}

###############################################################################
#
sub getOrfsByNode {
    my($node_ref) = shift;
    my($orf_list_ref) = shift;

    foreach my$rl ('R', 'L') {
        if (ref($node_ref->{"$rl"})) {
            getOrfsByNode($node_ref->{"$rl"}, $orf_list_ref);
        }
        else {
            push(@{$orf_list_ref}, $node_ref->{"$rl"});
        }
    }
    
    return $orf_list_ref;
}

###############################################################################
#
sub printClusterTitle {
    my($func_ref) = shift;
    my($recog_conf_ref) = shift;
    my($sporf_ref) = shift;

    #
    my($dbname) = $DBNAME_RECOG;
    my($db) = MBGD::DB->new($dbname);

    #
    print "<table width=\"100%\" border>\n";
    print "<tr><th>Cluster</th>\n";
    print "    <td>$sporf_ref->{'CLUSTER_ID'}</td>\n";
    print "</tr>\n";
    print "<tr><th>Title</th>\n";
    print "    <td>$sporf_ref->{'TITLE'}</td>\n";
    print "    </tr>\n";

    my($tabid) = $Args{'tabid'};
    my($tabname) = 'clustxref_' . $tabid;
    my($clustid) = $sporf_ref->{'CLUSTER_ID'};
    foreach my$dbType ('cog', 'kegg', 'tigr') {
        print "<tr><th>Xref-" . uc($dbType) . "</th>\n";
        print "    <td>\n";

        my($sql) = "select * from $tabname "
                 . "where clustid=$clustid and xref_db='$dbType' "
                 . "order by n_xref desc, xref_id ";
        my($sth) = $db->execute($sql);
        while (my$ref=$sth->fetchrow_hashref()) {
            my($xrefid) = $ref->{'xref_id'};
            my($n_xref) = $ref->{'n_xref'};
            my($t_xref) = $ref->{'total_xref'};
            my($url) = $recog_conf_ref->{"URL_xref_$dbType"} . $xrefid;
            print "    <a href=\"$url\" target=\"$xrefid\">$xrefid($n_xref/$t_xref)</a>\n";
        }
        print "    </td>\n";
        print "    </tr>\n";
    }

    # mapspec
    my($tabname) = $main::TBL_DOMTAXMAPIDX;
    if ($db->exist_table($tabname)) {
        my($sql) = "select * from $tabname where dumpid='$tabid' or clustid='$tabid'";
        my($sth) = $db->execute($sql);
        if ($sth->rows() != 0) {
            print "<tr><th>Map Spec</th>\n";
            print "    <td>\n";
            while (my$ref=$sth->fetchrow_hashref()) {
                my($mapspecid) = $ref->{'mapspecid'};
                my($mapspec) = $ref->{'mapspec'};
                print qq{<a href="/htbin/RECOG/view_taxmap.cgi?mapspecid=$mapspecid&clustid=$clustid">};
                print qq{$mapspec};
                print qq{</a> \n};
            }
            print "    </td>\n";
            print "    </tr>\n";
        }
    }

    print "\n";
    print "</table>\n";

    return;
}

###############################################################################
sub printFormForRedraw {
    my(%args) = @_;

    print "<form name=\"form_redraw\" method=\"post\" action=\"$ENV{'SCRIPT_NAME'}\" >\n";

    foreach my$k (sort(keys(%args))) {
        my($v) = $args{"$k"};
        my($refType) = ref($v);
        if (!$refType) {
            print "<input type=\"hidden\" name=\"$k\" value=\"$v\">\n";
        }
        elsif ($refType =~ /array/i) {
            foreach my$v0 (@{$v}) {
                print "<input type=\"hidden\" name=\"$k\" value=\"$v0\">\n";
            }
        }
    }
    print "</form>\n";
    print "<script>\n";
    print "function redraw_ortholog_cluster() {\n";
    print "  var doc = this.document;\n";
    print "\n";
    print "  doc.form_redraw.display_function.value = '';\n";
    print "  if (doc.clusterForm.display_function.checked) {\n";
    print "    doc.form_redraw.display_function.value = 'on';\n";
    print "  }\n";
    print "  doc.form_redraw.display_motif.value = '';\n";
    print "  if (doc.clusterForm.display_motif.checked) {\n";
    print "    doc.form_redraw.display_motif.value = 'on';\n";
    print "  }\n";
    print "  doc.form_redraw.cutoff_motif.value = doc.clusterForm.cutoff_motif.value;\n";
    print "doc.form_redraw.submit();\n";
    print "\n";
    print "}\n";
    print "</script>\n";

    return;
}

###############################################################################
sub build_summary_orfs {
    my($sporf_ref) = shift;
    my(@splist) = @_;

    my($OUT) = '';
    foreach my$sp (@splist) {
        my(@nmlist) = sort keys(%{$sporf_ref->{"$sp"}});

        $OUT .= " " if ($OUT ne '');
        $OUT .= "[";
        $OUT .= "<span ";
        $OUT .= "id=\"sp_$sp\" ";
        if (scalar(@nmlist) != 0) {
            $OUT .= "style=\"font-weight:bold; \" ";
            $OUT .= "onclick=\"disp_orfs(event, 'nm_list_$sp');\" ";
        }
        else {
            $OUT .= "style=\"color:gray; \" ";
        }
        $OUT .= ">";
        $OUT .= "$sp:" . scalar(@nmlist);
        $OUT .= "</span>";
        if (scalar(@nmlist) != 0) {
            $OUT .= "<div ";
            $OUT .= "id=\"nm_list_$sp\" ";
            $OUT .= "class=\"popup_menu\" ";
            $OUT .= "onmouseout=\"hide_orfs(event, 'nm_list_$sp');\" ";
            $OUT .= ">";
            foreach my$nm (@nmlist) {
                my($orfname) = "$sp:$nm";
                $OUT .= "<a href=\"/htbin/RECOG/RECOG_gene_info_frame.pl?name=$orfname&tabid=$Args{'tabid'}\" onclick=\"\hide_orfs(event, 'nm_list_$sp');\">";
                $OUT .= $orfname;
                $OUT .= "</a>";
                $OUT .= "<br>";
            }
            $OUT .= "</div>";
        }
        $OUT .= "]\n";
    }

    return $OUT;
}

###############################################################################
sub upd_tabid {
    my($tabid) = shift;

    if (($tabid =~ /^default$/i) && ($Args{'annotsp'} !~ /^\s*$/)) {
        my($tax) = MBGD::Taxonomy->new();
        my($sta) = $tax->is_default_spec($Args{'annotsp'});
        if (!$sta) {
            # default ʪ˴ޤޤʤ ===> addspec ơ֥򸡺
            $tabid = 'addspec';
        }
    }

    return $tabid;
}

###############################################################################
sub get_clust_addspec {
    my($uid) = shift;
    my($tabid) = shift;
    my($clustid) = shift;
    my($sp) = shift;

    my($clust_addspec_ref) = {};
    my($dbname) = $main::DBNAME_RECOG;
    my($db) = MBGD::DB->new($dbname);

    my($tab) = "cluster_domclust_cache_$tabid";
    my($sql) = "select * from $tab where sp='$sp' and clustid=$clustid";
    my($sth) = $db->execute($sql);
    while (my$ref=$sth->fetchrow_hashref()) {
        my($name) = $ref->{'name'};
        $clust_addspec_ref->{"$sp"}->{"$name"} = $ref;
    }

    return $clust_addspec_ref;
}

###############################################################################
sub exec_getseq {
    my($progname) = shift;
    my($opt) = shift;
    my(%orf_clust) = @_;

    #
    my(@entname_list) = keys(%orf_clust);
    my(%entname_hash);
    foreach my$entname (@entname_list) {
        $entname =~ s#\(\d+\)##;
        $entname_hash{"$entname"} = 1;
    }

    my($input) = join(' ', keys(%entname_hash));
    my($cmd) = "$WWWROOT/htbin/$progname $opt $input";
    my($res) = '';
    foreach my$line (`$cmd`) {
        if ($line =~ /^>\s*(\S+)/) {
            my($spname) = $1;
            my($clustid) = $orf_clust{"$spname"};

            $res .= ">$spname";
            $res .= " [cluster $clustid]" if ($clustid ne '');
            $res .= "\n";
            next;
        }
        $res .= $line;
    }

    return $res;
}

###############################################################################
1;#
###############################################################################
