#!/usr/bin/perl
use strict;
use DirHandle;
use FileHandle;
use MBGD;
use MBGD::WWW;
use MBGD::Taxonomy;
use RECOG::DomClustCommon;
require "MBGD_commonPath.pl";

#$main::DEBUG = 1;

###############################################################################
#
sub getDataBySql {
    my($db) = shift;
    my($tab) = shift;
    my($tab_str) = shift;
    my($opt) = shift;
    my(%Args) = @_;
    my(@out);

    #
#if (0) {
    foreach my$t (split(/,/, $tab)) {
        ($t) = ($t =~ /(\S+)/);
        next if ($t =~ /\./);
        if (! $db->exist_table($t)) {
            # this table doesn't exist.
            return @out;
        }
    }
#}

    #
    my($refRes) = $db->select_fetch($tab_str, $opt);

    if ($Args{'count'}) {
        return $refRes->{'ROWS'};
    }

    my(@name) = @{$refRes->{'NAME'}};
    if (! $Args{'no_header'}) {
        push(@out, join("\t", @name));
    }
    foreach my$ref (@{$refRes->{'INFO'}}) {
        my(@d);
        foreach my$n (@name) {
            push(@d, $ref->{"$n"});
        }
        push(@out, join("\t", @d));
    }
    return @out;
}

###############################################################################
#
sub printDataBySql {
    my($db) = shift;
    my($tab) = shift;
    my($opt) = shift;
    my(%Args) = @_;

    #
    foreach my$t (split(/,/, $tab)) {
        ($t) = ($t =~ /(\S+)/);
        next if ($t =~ /\./);
        if (! $db->exist_table($t)) {
            # this table does not exist.
            return;
        }
    }

    my($sql) = "select ";
    if ($Args{'count'}) {
        $sql .= "count(*) ";
    }
    elsif ($opt->{'columns'}) {
        $sql .= $opt->{'columns'} . " ";
    }
    else {
        $sql .= "* ";
    }

    $sql .= "from $tab ";
    if ($opt->{'where'}) {
        $sql .= "where " . $opt->{'where'} . " ";
    }
    if ($opt->{'group'}) {
        $sql .= "group by " . $opt->{'group'} . " ";
    }
    if ($opt->{'order'}) {
        $sql .= "order by " . $opt->{'order'} . " ";
    }

    my($sth) = $db->execute($sql);
    my(@name) = @{$sth->{'NAME'}};
    if (! $Args{'no_header'}) {
        print join("\t", @name), "\n";
    }
    while(my$ref=$sth->fetchrow_hashref()) {
        my(@d);
        foreach my$n (@name) {
            push(@d, $ref->{"$n"});
        }
        print join("\t", @d), "\n";
    }

    return;
}

###############################################################################
#
sub getData {
    my(%Args) = @_;
    my(@out);

    #
    my($table) = $Args{'table'};

    #
    my($args);
    if ($Args{'species'}) {
        $args = $Args{'species'};
    } elsif ($Args{'id'}) {
        $args = "id=$Args{'id'}";
    } elsif ($Args{'key'}) {
        $args = $Args{'key'};
    }

    #
    my($opt) = {};
    if ($Args{'keyfields'}) {
        $opt->{keys} = $Args{'keyfields'};
    }

    #
    if ($Args{'count'}) {
        $opt->{count} = 1;
    }

    #
    if ($Args{'fields'}) {
        $opt->{columns} = $opt->{fields} = $Args{'fields'};
    }

    #
    if ($Args{'limit'}) {
        $opt->{limit} = $Args{'limit'};
    }

    #
    if ($Args{'order'}) {
        $opt->{order} = $Args{'order'};
    }

    #
    if ($Args{'no_header'}) {
        $opt->{no_header} = $Args{'no_header'};
    }

    #
    if ($table =~ /^geneseq$/i) {
        @out = MBGD->get_sequence($table, $args, $opt);
    }
    elsif ($table =~ /^proteinseq$/i) {
        @out = MBGD->get_sequence($table, $args, $opt);
    }
    elsif ($table =~ /^genome$/i) {
        my($db) = new MBGD::DB();

        my($table_str) = "(genome left join chromosome on genome.sp=chromosome.sp) left join dnaseq on chromosome.seq=dnaseq.id";
        if (! $Args{'fields'}) {
            $opt->{'columns'} = "genome.*, sum(dnaseq.length) as total_length";
        }
        else {
            my(@f) = split(',', $Args{'fields'});
            $opt->{'columns'} = '';
            foreach my$f (@f) {
                $opt->{'columns'} .= ',' if ($opt->{'columns'} ne '');
                $opt->{'columns'} .= "genome.$f";
            }
        }

        if ($args) {
            $opt->{'where'} .= " and " if ($opt->{'where'} ne '');
            $opt->{'where'} .= "genome.sp in(";
            foreach my$sp (split(/,/, $args)) {
                $opt->{'where'} .= "'$sp',";
            }
            $opt->{'where'} .= "'')";
        }
        $opt->{'group'} = "genome.sp";
        $opt->{'order'} = "genome.spid";

        @out = getDataBySql($db, $table, $table_str, $opt, %Args);
    }
    elsif ($table =~ /^chromosome$/i) {
        my($db) = new MBGD::DB();

        my($table_str) = "chromosome left join dnaseq on chromosome.seq=dnaseq.id";
        $opt->{'columns'} = $Args{'fields'};
        if (! $Args{'fields'}) {
            $opt->{'columns'} = "chromosome.*, dnaseq.length";
        }
#        $opt->{'where'} = "chromosome.seq=dnaseq.id";
        $opt->{'where'} = "1";
        if ($args) {
            $opt->{'where'} .= " and chromosome.sp in(";
            foreach my$sp (split(/,/, $args)) {
                $opt->{'where'} .= "'$sp',";
            }
            $opt->{'where'} .= "'')";
        }

        @out = getDataBySql($db, $table, $table_str, $opt, %Args);
    }
    elsif ($table =~ /^contig$/i) {
        my($db) = new MBGD::DB();

        $table = "contig";
        $opt->{'columns'} = $Args{'fields'};
        if (! $Args{'fields'}) {
            $opt->{'columns'} = "contig.*, seq_length as length";
        }
        $opt->{'where'} = "1";
        if ($args) {
            $opt->{'where'} .= " and contig.sp in(";
            foreach my$sp (split(/,/, $args)) {
                $opt->{'where'} .= "'$sp',";
            }
            $opt->{'where'} .= "'')";
        }

        @out = getDataBySql($db, $table, $table, $opt, %Args);
    }
    elsif ($table =~ /^mapview$/i) {
        my($db) = new MBGD::DB();

        $table = "mapview";
        $opt->{'columns'} = $Args{'fields'};
        if (! $Args{'fields'}) {
            $opt->{'columns'} = "";
        }
        $opt->{'where'} = "1";
        if ($args) {
            $opt->{'where'} .= " and mapview.sp in(";
            foreach my$sp (split(/,/, $args)) {
                $opt->{'where'} .= "'$sp',";
            }
            $opt->{'where'} .= "'')";
        }

        @out = getDataBySql($db, $table, $table, $opt, %Args);
    }
    elsif ($table =~ /^region$/i) {
        my($db) = new MBGD::DB();
        my($sp)   = $Args{'key'};
        my($chr)  = $Args{'chr'};
        my($from) = $Args{'from'};
        my($to)   = $Args{'to'};

        $table = "gene,chromosome";

        if ($Args{'fields'}) {
            my(@f);
            foreach my$c (split(/,/, $Args{'fields'})) {
                push(@f, "gene.$c");
            }
            $opt->{'columns'} = join(",", @f);
        }
        else {
            $opt->{'columns'} = "gene.*";
        }

        $opt->{'where'} = 'gene.chrid=chromosome.id';

        #
        $opt->{'where'} .= " and " if ($opt->{'where'} ne '');
        $opt->{'where'} .= "gene.sp='$sp'";

        #
        $chr = 1 if (! $chr);
        $opt->{'where'} .= " and " if ($opt->{'where'} ne '');
        $opt->{'where'} .= "chromosome.seqno=$chr";

        #
        if ($from) {
            $opt->{'where'} .= " and " if ($opt->{'where'} ne '');
            $opt->{'where'} .= " gene.to1 >= $from ";
        }

        #
        if ($to) {
            $opt->{'where'} .= " and " if ($opt->{'where'} ne '');
            $opt->{'where'} .= " gene.from1 <= $to ";
        }

        @out = getDataBySql($db, $table, $table, $opt, %Args);
    }
    elsif ($table =~ /^genename$/i) {
        $table = 'gene';
        $opt->{'keys'} = "gene";
        @out = MBGD->get_texttab($table, $args, $opt);
    }
    elsif ($table =~ /^domain$/i) {
        # $B%/%i%9%?!<%F!<%V%k!J(Bcluster_*$B!K$N(B $MBGD_HOME/schema $B$OB8:_$7$J$$(B
        # $B$h$C$F(B SQL $B$rD>@\<B9T$78!:w7k2L$rF@$k(B
        my($dbname) = $main::DBNAME_RECOG;
        my($db) = new MBGD::DB($dbname);
        if ($Args{'tabid'}) {
            $table = 'cluster_domclust_cache_' . $Args{'tabid'};
        }
        else {
            $table = 'cluster_all';
        }

        #
        $opt->{'where'} = '';
        foreach my$k (split(/,/, $Args{'key'})) {
            my($sp, $name, $dom) = split(/:/, $k);
            $opt->{'where'} .= " or " if ($opt->{'where'} ne '');
            $opt->{'where'} .= "(sp='$sp' and name='$name'";
            $opt->{'where'} .= " and dom='$dom'" if ($dom);
            $opt->{'where'} .= ")";
        }

        @out = getDataBySql($db, $table, $table, $opt, %Args);
    }
    elsif ($table =~ /^gene$/i) {
        if (($Args{'key'} =~ /^\s*$/) && ($Args{'limit'} =~ /^\s*$/)) {
            $Args{'limit'} = $opt->{'limit'} = "10000";
        }
        @out = MBGD->get_texttab($table, $args, $opt);
    }
    elsif ($table =~ /^taxonomy$/i) {
        my($fileTaxonomy) = "$ENV{'MBGD_HOME'}/database/tax";
        my(@statTax) = stat($fileTaxonomy);
        my($sec, $min, $hour, $mday, $mon, $year) = localtime($statTax[9]);
        $year += 1900;
        $mon++;

        push(@out, sprintf("#VERSION\t%04d%02d%02d", $year, $mon, $mday));
        my($fh) = new FileHandle("$fileTaxonomy");
        my($line);
        while($line = $fh->getline()) {
            $line =~ s#[\r\n]*$##;
            push(@out, $line);
        }
        $fh->close();
    }
    elsif ($table =~ /^taball$/i) {
        my($file_taball) = "$ENV{'MBGD_HOME'}/database/taball.domclust";
        my(@stat_taball) = stat($file_taball);
        my($sec, $min, $hour, $mday, $mon, $year) = localtime($stat_taball[9]);
        $year += 1900;
        $mon++;

#        push(@out, sprintf("#VERSION\t%04d%02d%02d", $year, $mon, $mday));
        my($fh) = new FileHandle("$file_taball");
        my($line);
        while($line = $fh->getline()) {
            $line =~ s#[\r\n]*$##;
            push(@out, $line);
        }
        $fh->close();
    }
    elsif ($table =~ /^category$/i) {
        my($dbname) = $main::DBNAME_FUNC;
        my($db) = new MBGD::DB($dbname);

        #
        $opt->{'where'} = '';
        if ($Args{'dbname'}) {
            $Args{'dbname'} =~ s#'#\\'#g;
            $opt->{'where'} .= " and " if ($opt->{'where'} ne '');
            $opt->{'where'} .= " dbname='$Args{'dbname'}'";
        }

        @out = getDataBySql($db, $table, $table, $opt, %Args);
    }
    elsif ($table =~ /^category_color$/i) {
        my($dbname) = $main::DBNAME_FUNC;
        my($db) = new MBGD::DB($dbname);
        $table = "category_color";

        #
        $opt->{'where'} = '';
        if ($Args{'dbname'}) {
            $Args{'dbname'} =~ s#'#\\'#g;
            $opt->{'where'} .= " and " if ($opt->{'where'} ne '');
            $opt->{'where'} .= " dbname='$Args{'dbname'}'";
        }

        @out = getDataBySql($db, $table, $table, $opt, %Args);
    }
    elsif ($table =~ /^gene_category$/i) {
        my($dbname) = $main::DBNAME_FUNC;
        my($db) = new MBGD::DB($dbname);
#        $table = "gene_category gc, category c";
        $table = "gene_category gc";

        #
        $opt->{'where'} = '';
        foreach my$k (split(/,/, $Args{'key'})) {
            my($sp, $name) = split(/:/, $k);
            $sp =~ s#'#\\'#g;
            $name =~ s#'#\\'#g;
            $opt->{'where'} .= " or " if ($opt->{'where'} ne '');
            $opt->{'where'} .= "(gc.sp='$sp'";
            $opt->{'where'} .= " and gc.name='$name'" if ($name);
            $opt->{'where'} .= ")";
        }
#        if ($opt->{'where'} ne '') {
#            $opt->{'where'} = "gc.dbname=c.dbname and gc.level=c.level and ($opt->{'where'})";
#        }
        if ($Args{'dbname'}) {
            $Args{'dbname'} =~ s#'#\\'#g;
            $opt->{'where'} .= " and " if ($opt->{'where'} ne '');
            $opt->{'where'} .= " gc.dbname='$Args{'dbname'}'";
        }

        if (($Args{'key'} =~ /^\s*$/) && ($Args{'limit'} =~ /^\s*$/)) {
            $Args{'limit'} = $opt->{'limit'} = "10000";
        }

        @out = getDataBySql($db, $table, $table, $opt, %Args);
    }
    elsif ($table =~ /^gene_keyword$/i) {
        if ($Args{'fields'}) {
            my(@f);
            foreach my$c (split(/,/, $Args{'fields'})) {
                next if ($c =~ /clustid$/);
                push(@f, "g.$c");
            }
            $opt->{'columns'} = join(",", @f);
        }
        else {
            $opt->{'columns'} = "g.*";
        }

        my($db) = new MBGD::DB($main::DBNAME_MBGD);
        $table = 'gene g';
        $opt->{'where'} = '';

        # $B%/%i%9%?%j%s%0%F!<%V%k<1JL;R$+$i@8J*<o$r<hF@(B
        my($clustTabId);
        my($refSpec) = [];
        my($refOpt);
        if ($Args{'clust_tab_id'} =~ /\d+\_\d+/i) {
            # $B%/%i%9%?!<%F!<%V%k(B
            $clustTabId = $Args{'clust_tab_id'};
            my($dbRecog) = new MBGD::DB($main::DBNAME_RECOG);
            ($refSpec, $refOpt) = idtoOpt($dbRecog, $clustTabId);
        }

        #
        my(%spHash, @spList);
#        foreach my$sp (split(/,/, $Args{'key'}), @{$refSpec}) {
        foreach my$sp (split(/,/, $args)) {
            next if ($sp =~ /^\s*$/);
            $spHash{"'$sp'"} = 1;
        }

        @spList = sort(keys(%spHash));
        if (scalar(@spList) != 0) {
            $opt->{'where'} .= "g.sp in(" . join(',', @spList) . ")";
        }

        # descr/name/gene
        my($whereWord) = '';
        for(my$i = 1; ; $i++) {
            if (!exists($Args{"field$i"}) || !exists($Args{"keyword$i"})) {
                last;
            }

            if ($whereWord ne '') {
                my($andor) = 'and';
                if ($Args{"fcond$i"} =~ /^or$/i) {
                    $andor = 'or';
                }
                $whereWord .= " $andor ";
            }

            my($whereField) = '';

            #
            my($f) = $Args{"field$i"};   $f =~ s#\W##g;
            my($w) = $Args{"keyword$i"};    $w =~ s#\'#\\'#g;

            #
            my($op);
            if ($w =~ /[%_]/ && $w !~ /\\[%_]/) {
                $op = 'like';
            }
            elsif ($w =~ /\[[^\]]+\]/ ||
                   $w =~ /^\^/ ||
                   $w =~ /\$$/ ||
                   $w =~ /\*/) {
                $op = 'regexp';
            }
            else {
                $op = '=';
            }

            my(@fieldList);
            if ($f =~ /^orf$/i) {
                $whereField .= ' or ' if ($whereField ne '');
                $whereField .= "g.name $op '$w'";
            }
            elsif ($f =~ /^gene$/i) {
                $whereField .= ' or ' if ($whereField ne '');
                $whereField .= "g.gene $op '$w'";
            }
            elsif ($f =~ /^descr$/i) {
                my($mode) = '';
                if ($w =~ /[\+\-\*\~\"]/) {
                    $mode = 'in boolean mode';
                }
                $whereField .= ' or ' if ($whereField ne '');
                $whereField .= "match(g.descr) Against('" . $w . "' $mode)";
            }
            else {
                my($mode) = '';
                if ($w =~ /[\+\-\*\~\"]/) {
                    $mode = 'in boolean mode';
                    $whereField .= "match(g.name, g.gene, g.descr) Against('" . $w . "' $mode)";
                }
            }

            $whereWord .= "($whereField)" if ($whereField ne '');
        }

        if ($whereWord ne '') {
            if ($opt->{'where'} ne '') {
                $opt->{'where'} .= " and ";
            }
            $opt->{'where'} .= "($whereWord)";

            #
            if ($clustTabId) {
                $opt->{'columns'} = "c.clustid,c.subclustid,c.dom," . $opt->{'columns'};
                $table .= sprintf(",%s.cluster_domclust_cache_%s c", $main::DBNAME_RECOG,
                                                                     $clustTabId);
                $opt->{'where'} .= " and " if ($opt->{'where'} ne '');
                $opt->{'where'} .= "c.sp=g.sp and c.name=g.name";
            }
        }

        if ($opt->{'where'} =~ /^\s*$/) {
            $Args{'limit'} = $opt->{'limit'} = "10000";
        }
        @out = getDataBySql($db, $table, $table, $opt, %Args);
    }
    elsif ($table =~ /^download_species$/i) {
        if (($Args{'key'} !~ /^gm\d{5}$/) ||
            (! -e "$ENV{'MBGD_HOME'}/species/$Args{'key'}")) {
            my($dh) = new DirHandle("$ENV{'MBGD_HOME'}/species");
            @out = ('#spid list');
            if ($dh) {
                foreach my$f (sort($dh->read())) {
                    next if ($f !~ /^gm\d{5}$/);
                    push(@out, $f);
                }
            }
        }
        else {
            print "content-type: application/x-gzip\n";
            print "Content-Disposition: attachment; filename=\"$Args{'key'}.tar.gz\"\n";
            print "\n";

            my($cmd) = "cd $ENV{'MBGD_HOME'}/species/;"
                     . "$main::CMD_tar cvfz - ./$Args{'key'}/gm";
            system("$cmd");
            return;
#@out=("$cmd");
        }
    }
    elsif ($table =~ /^taxonomy_rank$/i) {
		if (! $Args{'no_header'}) {
			push(@out, join("\t", 'rank', 'value'));
		}

        my($tax) = new MBGD::Taxonomy();
        my($refRank) = $tax->getRank();
        foreach my$rank (sort({$refRank->{"$a"} <=> $refRank->{"$b"}} keys(%{$refRank}))) {
            my($rv) = $refRank->{"$rank"};
            push(@out, join("\t", $rank, $rv));
        }

    }
    elsif ($table =~ /^homology$/i) {
        my($db) = new MBGD::DB();
        $table = "homology";
        if ($args) {
            my($where_sp) = '';
            foreach my$sp (split(/,/, $args)) {
                next if ($sp =~ /[^0-9A-Z\-\_]/i);

                $where_sp .= ',' if ($where_sp ne '');
                $where_sp .= "'$sp'";
            }
            $opt->{'where'} = " sp1 in(" . $where_sp . ")"
                            . " and "
                            . " sp2 in(" . $where_sp . ")";
        }

        if ($Args{'gzip'}) {
            print "content-type: application/x-gzip\n";
            print "Content-Disposition: attachment; filename=\"homology.gz\"\n";
            print "\n";

            open(FH_GZIP, "|$main::CMD_gzip -c") || die("ERROR :: gzip");
            select(FH_GZIP);
        }
        else {
            print "content-type: text/plain\n";
            print "\n";
        }

        printDataBySql($db, $table, $opt, %Args);

        if ($Args{'gzip'}) {
            close(FH_GZIP);
        }

        return;
    }
    elsif ($table =~ /^attribute$/i) {
        my($db) = new MBGD::DB();
        $table = 'attribute';
        $opt->{'where'} = '';
        if ($Args{'category'}) {
            $opt->{'where'} .= ' and ' if ($opt->{'where'} ne '');
            $opt->{'where'} .= "category='$Args{'category'}'";
        }
        if ($Args{'name'}) {
            $opt->{'where'} .= ' and ' if ($opt->{'where'} ne '');
            $opt->{'where'} .= "name='$Args{'name'}'";
        }
        $opt->{'order'} = 'category, name';

        @out = getDataBySql($db, $table, $table, $opt, %Args);
    }
    elsif ($table =~ /^cluster_tables_idx$/i) {
        my($db) = MBGD::DB->new($main::DBNAME_RECOG);
        $table = 'cluster_tables_idx';
        $opt->{'where'} = "clusterID='$Args{'clusterID'}'";

        @out = getDataBySql($db, $table, $table, $opt, %Args);
    }
    elsif ($table =~ /base_cluster/) {
        get_base_cluster($Args{'base_cluster_id'});
        exit(0);
    }
    else {
        @out = MBGD->get_texttab($table, $args, $opt);
    }

    # $B7k2L$N=PNO(B
    if ($Args{'gzip'}) {
        print "content-type: application/x-gzip\n";
        print "\n";

        open(FH_GZIP, "|$main::CMD_gzip -c");
        print FH_GZIP join("\n", @out), "\n";
        close(FH_GZIP);
    }
    else {
        print "content-type: text/plain\n";
        print "\n";
        print join("\n", @out), "\n";
    }
}

###############################################################################
#
sub get_base_cluster {
    my($base_cluster_id) = shift;

    my($dir) = "$ENV{'MBGD_HOME'}/MBGD.tmp";
    my($file_base_cluster) = "$dir/tmp_dom_res_$base_cluster_id.o11";

    print "content-type: text/plain\n";
    print "\n";
    if (-e $file_base_cluster) {
        my($db) = MBGD::DB->new($main::DBNAME_RECOG);
        my($tab) = 'cluster_tables_idx';
        my($sql) = "select * from $tab where clusterID=?";
        my($sth) = $db->prepare($sql);
        $sth->execute($base_cluster_id);
        my($ref) = $sth->fetchrow_hashref();

        #
        foreach my$key ('cmd', 'clusterID', 'cdate') {
            print '#', $key, "\t", $ref->{"$key"},  "\n";
        }
        my($key) = 'spec';
        $ref->{"$key"} = ($ref->{'cmd'} =~ /\-SPEC\=([^\s\|]+)/);

        print '#START_DATA', "\n";

        #
        my($cmd) = "/bin/cat $file_base_cluster";
        system("$cmd");
    }

    return;
}

###############################################################################
if ($0 eq __FILE__) {
    my($www) = new MBGD::WWW;
    my(%Args) = $www->cgiGetArgs;

    foreach my$k (keys(%Args)) {
        my($v) = $Args{$k};
    }

    if ($Args{'table'} =~ /^genome$/i) {
        my($now) = scalar(localtime(time()));
        print STDERR "LOG :: START getData(genome) :: $now\n";
    }

    getData(%Args);

    if ($Args{'table'} =~ /^genome$/i) {
        my($now) = scalar(localtime(time()));
        print STDERR "LOG :: FINISH getData(genome) :: $now\n";
    }
}

1;#
