#!/usr/bin/perl -s
use strict;
use MBGD;
use MBGD::WWW;
use RECOG::DomClustCommon;
use RECOG::CoreAlignerUtil;

#$main::DEBUG = 1;

###############################################################################
#
$main::MIN_NBR_WIN = 10;
$main::MAX_NBR_WIN = 30;
#
$main::MIN_CONS_RATIO = 0.0;
$main::MAX_CONS_RATIO = 1.0;
#
$main::MIN_NBR_CONS_RATIO = 0.0;
$main::MAX_NBR_CONS_RATIO = 1.0;
#
$main::MIN_MIN_SPCOV = 0;
$main::MAX_MIN_SPCOV = 1;
#
$main::MIN_SPCOV_REG_CUT =  5;
$main::MAX_SPCOV_REG_CUT = 50;
#
$main::MIN_RATIO = 0.0;
$main::MAX_RATIO = 1.0;



###############################################################################
#
sub printError {
    my($msg) = shift;

    print "Content-type: text/plain\n";
    print "\n";

    print "#STATUS=", $CoreAlignerUtil::STA_STRerror, "\n";
    print "#STATUS2=$msg\n";

    return;
}

###############################################################################
#
sub checkArgsForCoreAligner {
    my($refFormOpt) = shift;
    my($key);

    if (exists($refFormOpt->{'CORE_TAB_ID'})) {
        # [$B<B9TCf$N2r@O$N>uBVLd$$9g$o$;(B]
        # $B$b$7$/$O(B
        # [$B4{B8$N2r@O7k2L$N<hF@(B]
    }
#    elsif (exists($refFormOpt->{'CLUST_TAB_ID'}) && exists($refFormOpt->{'REF_SPEC'})) {
    elsif (exists($refFormOpt->{'CLUST_TAB_ID'})) {
        # [$B?75,2r@OMW5a(B]
        # $B$b$7$/$O(B
        # [$B<B9TCf$N2r@O$N>uBVLd$$9g$o$;(B]$B!J(BCORE_TAB_ID $B$r;XDj$7$J$$%1!<%9!K(B
    }
    else {
        # $B2r@O>r7o$,ITB-(B
#        my($msg) = "Require some analysis options. :: CORE_TAB_ID or (CLUST_TAB_ID + REF_SPEC)";
        my($msg) = "Require some analysis options. :: CORE_TAB_ID or CLUST_TAB_ID";
#        printError($msg);
        my($eid) = $CoreAlignerUtil::ERRNO_NG_OPTIONS;
        my($emsg) = $CoreAlignerUtil::ERRMSG{"$eid"};
        printErrMsgExit($eid, $emsg);
    }

    #
    $key = 'NBR_WIN';
    &checkValRange($refFormOpt, $key, $main::MIN_NBR_WIN, $main::MAX_NBR_WIN);

    $key = 'CONS_RATIO';
    &checkValRangeRatio($refFormOpt, $key);

    $key = 'NBR_CONS_RATIO';
    &checkValRangeRatio($refFormOpt, $key);

    $key = 'MIN_SPCOV';
    &checkValRange($refFormOpt, $key, $main::MIN_MIN_SPCOV, $main::MAX_MIN_SPCOV);

    $key = 'SPCOV_REG_CUT';
    &checkValRange($refFormOpt, $key, $main::MIN_SPCOV_REG_CUT, $main::MAX_SPCOV_REG_CUT);

    $key = 'SPCOV_SPRATIO';
    &checkValRangeRatio($refFormOpt, $key);

    $key = 'OTHER_OPTIONS';
    if (exists($refFormOpt->{"$key"})) {
        $refFormOpt->{"$key"} =~ s#[\"\'\;\<\>]##g;    # $BIT@5$H;W$o$l$kJ8;z$r=|5n(B
#        print STDERR "DBG :: OK ($key)\n" if ($main::DEBUG);
    }

    return;
}

sub checkValRangeRatio {
	my($refFormOpt, $key) = @_;
	&checkValRange($refFormOpt, $key, $main::MIN_RATIO, $main::MAX_RATIO);
}
sub checkValRange {
    my($refFormOpt, $key, $min, $max) = @_;
    if (exists($refFormOpt->{"$key"})) {
	my($val) = $refFormOpt->{$key};

    	if (($val < $min) || ($max < $val)) {
            my($msg) = "Out of range [$min <= $key <= $max]";
#            printError($msg);
            my($eid) = $CoreAlignerUtil::ERRNO_NG_OPTIONS;
            my($emsg) = $CoreAlignerUtil::ERRMSG{"$eid"};
            printErrMsgExit($eid, $emsg);
        }
        print STDERR "DBG :: OK ($key)\n" if ($main::DEBUG);
    }
}

###############################################################################
#
sub printResult {
    my($refSta) = shift;
    my($coreTabId) = $refSta->{'core_tab_id'};

    my($refOpt) = CoreAlignerUtil::parseCoreCmdOpts($refSta->{'cmd'});
    my($species) = $refOpt->{'SPECIES'};

    print "Content-type: text/plain\n";
    print "\n";

    print "#STATUS=finished\n";
    print "#SPECIES=$species\n";

    CoreAlignerUtil::printCoreAlignerResult($coreTabId);

    return;
}

###############################################################################
#
sub CoreAligner {
    my($refFormOpt) = @_;

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

    #
    CoreAlignerUtil::createCoreIndexTable($dbRecog);

    #
    my($coreTabId);
    my($refSta);
    if (exists($refFormOpt->{'CORE_TAB_ID'})) {
        $coreTabId = $refFormOpt->{'CORE_TAB_ID'};
        $refSta = CoreAlignerUtil::getCoreStatus($dbRecog, $coreTabId);
        if (!$refSta) {
            # $B2r@O7k2L$,B8:_$7$J$$(B
            my($msg) = "Unknown CORE_TAB_ID :: [$refFormOpt->{'CORE_TAB_ID'}]";
#            printError($msg);
            my($eid) = $CoreAlignerUtil::ERRNO_NO_CLUST_TAB;
            my($emsg) = $CoreAlignerUtil::ERRMSG{"$eid"};
            printErrMsgExit($eid, $emsg, $refFormOpt->{'CORE_TAB_ID'});
        }
    }
    else {
        # $B2r@O>r7o$+$i(B coreTabId $B$r:n@.(B
        my($clustTabId) = $refFormOpt->{'CLUST_TAB_ID'};
        my($refTabSpec) = CoreAlignerUtil::getSpeciesByClusterTabId($dbRecog, $clustTabId);
        if (!defined($refTabSpec)) {
            my($msg) = "Can not found Cluster-Table-Id [$clustTabId]";
#            printError($msg);
            my($eid) = $CoreAlignerUtil::ERRNO_NO_CLUST_TAB;
            my($emsg) = $CoreAlignerUtil::ERRMSG{"$eid"};
            printErrMsgExit($eid, $emsg, $clustTabId);
        }
        my($refSpOrder) = [ split(/,/, $refTabSpec->{'SPECIES'}) ];

        #
        my($refOpt) = {};
        $refOpt->{'-CLUST_TAB_ID'}   = $clustTabId;
        $refOpt->{'-SPECIES'}        = $refTabSpec->{'SPECIES'};
        $refOpt->{'-refsp'}          = $refFormOpt->{'REF_SPEC'};
        $refOpt->{'-NBR_WIN'}        = $refFormOpt->{'NBR_WIN'};
        $refOpt->{'-CONS_RATIO'}     = $refFormOpt->{'CONS_RATIO'};
        $refOpt->{'-NBR_CONS_RATIO'} = $refFormOpt->{'NBR_CONS_RATIO'};
        $refOpt->{'-MIN_SPCOV'}      = $refFormOpt->{'MIN_SPCOV'};
        $refOpt->{'-SPCOV_REG_CUT'}  = $refFormOpt->{'SPCOV_REG_CUT'};
        $refOpt->{'-SPCOV_SPRATIO'}  = $refFormOpt->{'SPCOV_SPRATIO'};
        $refOpt->{'-OTHER_OPTIONS'}  = $refFormOpt->{'OTHER_OPTIONS'};
        $refOpt->{'-OutGroup'}       = $refTabSpec->{'OUT_GROUP'};
        $refOpt->{'-out_species'}    = $refTabSpec->{'SPECIES'};
        $refOpt->{'-SpGrp'}          = $refFormOpt->{'SP_GROUP'};

        $coreTabId = CoreAlignerUtil::getCoreAlignerTabId($dbRecog, $refOpt);

        $refSta = CoreAlignerUtil::getCoreStatus($dbRecog, $coreTabId);
    }

    #
    if (!$refSta) {
        # $B2r@OL$<B9T(B ==> CoreTabId $B$r:NHV(B + CoreAligner $B$r<B9T(B + $B?JD=I=<((B

        # Core$B9=B$2r@O$NA0=`Hw(B
        my($dirBase) = sprintf("%s/work", $ENV{'MBGD_HOME'});
        my($refOpt) = {};
        $refOpt->{'CLUST_TAB_ID'} = $refFormOpt->{'CORE_TAB_ID'};
        my($refCoreOpt) = CoreAlignerUtil::setupCoreAligner($dirBase, $refFormOpt);

        # $B?75,:NHV$5$l$?(B CORE_TAB_ID
        $coreTabId = $refCoreOpt->{'CORE_TAB_ID'};

        # fork() $BA0$K(B MySQL $B$H$N%3%M%/%7%g%s$r@ZCG(B
        $dbRecog->disconnect();

        # CoreAligner $B$r<B9T(B + $B?JD=I=<((B
        my($pid) = fork();
        if ($pid) {
            # $B;R%W%m%;%9$G(B CoreAligner $B$r<B9T(B ==> $B$7$P$i$/(B sleep()
            sleep(1);

            # $B?F%W%m%;%9$K$*$$$F(B MySQL $B$H:F@\B3(B
            my($dbRecog) = MBGD::DB->new($dbname);

            # $B99?7$5$l$?>pJs$r<hF@(B
            $refSta = CoreAlignerUtil::getCoreStatus($dbRecog, $coreTabId);

            # $B$3$N$"$H$G?JD=I=<((B
        }
        elsif (defined($pid)) {
            close(STDIN);
            close(STDOUT);
##            close(STDERR);

            # $B;R%W%m%;%9$K$*$$$F(B MySQL $B$H:F@\B3(B
            my($dbRecog) = MBGD::DB->new($dbname);

            # CoreAligner $B$N<B9T!J(BMySQL $B$N%9%F!<%?%9$r(B '$B<B9TCf(B' $B$KJQ99!K(B
            CoreAlignerUtil::execCoreAligner($dbRecog, $refCoreOpt);

            #
            my($fileCoreResult)   = sprintf("%s/core_result", $refCoreOpt->{'DIR_WORK'});
            CoreAlignerUtil::writeCoreAlignerResult($refCoreOpt->{'alignout'},
                                              $refCoreOpt->{'core_clustout'},
                                              $fileCoreResult);

            # CoreAligner $B$N2r@O7k2L$r(B MySQL $B$KEPO?(B
            my($fileCore)  = sprintf("%s/", $refCoreOpt->{'DIR_WORK'});
            CoreAlignerUtil::insertCoreFile($dbRecog,
                                         $refCoreOpt->{'CORE_TAB_ID'},
                                         $fileCoreResult);

            # MySQL $B$N%9%F!<%?%9$r(B '$B2r@O=*N;(B' $B$KJQ99(B
            CoreAlignerUtil::updateCoreStatus($dbRecog,
                                           $refCoreOpt->{'CORE_TAB_ID'},
                                           $CoreAlignerUtil::STA_finished);

            # $B:n6H%G%#%l%/%H%j$N:o=|(B
            File::Path::rmtree("$refCoreOpt->{'DIR_WORK'}");

            exit(0);
        }
        else {
            # fork() $B$G%(%i!<(B
            my($msg) = "System Internal Error :: Can not fork() :: $!";
#            printError($msg);
            my($eid) = $CoreAlignerUtil::ERRNO_FORK;
            my($emsg) = $CoreAlignerUtil::ERRMSG{"$eid"};
            printErrMsgExit($eid, $emsg, $coreTabId);
        }
    }
    elsif ($refSta->{'status'} == $CoreAlignerUtil::STA_finished) {
        # CoreAligner $B2r@O$,@5>o=*N;$7$F$$$k(B ===> $B2r@O7k2L$r=PNO(B
        print "Content-type: text/plain\n";
        print "\n";
        CoreAlignerUtil::printCoreAlignerResultHeader($refSta);
        CoreAlignerUtil::printCoreAlignerResult($dbRecog, $coreTabId);
        exit(0);
    }
    if ($refSta->{'status'} == $CoreAlignerUtil::STA_error) {
        # CoreAligner $B2r@O$,0[>o=*N;$7$F$$$k(B ==> $B%(%i!<%a%C%;!<%8$r=PNO(B
        my($msg) = "System Internal Error :: $refSta->{'core_tab_id'} :: CoreAligner status = $refSta->{'status'}";
#        printError($msg);
        my($eid) = $CoreAlignerUtil::ERRNO_SERVER_INTERNAL;
        my($emsg) = $CoreAlignerUtil::ERRMSG{"$eid"};
        printErrMsgExit($eid, $emsg, $refSta->{'core_tab_id'});
    }
    elsif ($CoreAlignerUtil::STA_waiting <= $refSta->{'status'}) {
        # CoreAligner $B$r<B9TCf(B ==> $B$3$N$"$H$G?JD=I=<((B
    }
    else {
        # status $B$,0[>oCM(B ==> $B%(%i!<%a%C%;!<%8$r=PNO(B
        my($msg) = "System Internal Error :: $refSta->{'core_tab_id'} :: CoreAligner status = $refSta->{'status'}";
#        printError($msg);
        my($eid) = $CoreAlignerUtil::ERRNO_SERVER_INTERNAL;
        my($emsg) = $CoreAlignerUtil::ERRMSG{"$eid"};
        printErrMsgExit($eid, $emsg, $refSta->{'core_tab_id'});
    }

    # $B?JD=I=<((B
    print "Content-type: text/plain\n";
    print "\n";
    CoreAlignerUtil::printCoreAlignerResultHeader($refSta);

    return;
}

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

    my(%args)  = $www->cgiGetArgs();

    if ($main::TAB_ID) {
        $args{'SRC_CLUST_TAB_ID'} = $main::TAB_ID;
    }
    if ($main::MODE) {
        $args{'mode_cluster'} = $main::MODE;
    }

    #
    my(%optHash) = ('CORE_TAB_ID'    => '',
                    'CLUST_TAB_ID'   => '',
                    'REF_SPEC'       => '',
                    'NBR_WIN'        => 20,
                    'CONS_RATIO'     =>  0.5,
                    'NBR_CONS_RATIO' => '',
                    'SP_GROUP'       => '',
                    'MIN_SPCOV'      =>  0.5,
                    'SPCOV_REG_CUT'  => 20,
                    'SPCOV_SPRATIO'  => 0,
                    'OTHER_OPTIONS'  => '',
                    );
    my($refFormOpt) = {};
    foreach my$key (keys(%optHash)) {
        if ((!exists($args{"$key"})) ||
            ($args{"$key"} =~ /^\s*$/)) {
            if ($optHash{"$key"} ne '') {
                $args{"$key"} = $optHash{"$key"};
            }
            else {
                next;
            }
        }

        my($v) = $args{"$key"};
        $v =~ s#[^A-Z0-9_\.\-\:\,\=]##gi;     # $BIT@5$JJ8;z$r=|5n(B
        $refFormOpt->{"$key"} = $v;
        print STDERR "DBG :: set $key << $v\n" if ($main::DEBUG);
    }


    # $B2r@O>r7o$,$=$m$C$F$$$k$+!)!J$=$m$C$F$$$J$$>l9g(B exit $B$9$k!K(B
    checkArgsForCoreAligner($refFormOpt);

    #
    CoreAligner($refFormOpt);
}

1;
