use strict;
use warnings;
use Getopt::Long;
use FindBin;

BEGIN 
{
    my $dir = $FindBin::Bin;
    push(@INC, "$dir");
}

use Modules::Shape;
use Modules::DAFS;

# --- command line --- #
my $mode="DAFS"; #alignment mode : (shape, DAFS, Profile) #kari  
## --- common option --- #
my $opthelp=0;
my $infile;  #~.coverage.txt
my @infiles; #~.coverage.txt for Profile Align mode
my $outfile; #~.mat
my $tmpdir = "/tmp";
my $alpha=1.0;
my $maxgap=-1;
my $CovThreshold=20; #coverage threshold 
my $LenThreshold=-1; #Gene Length threshold 
my $bothendzero=0;

my $cut=0; #secret : trimming $cut nt both of CoveragesVector
## --- --- ##

## --- DAFS mode option --- ##
my $beta=-3.0;
my $weight_ss=4.0; 
my $weight_shape=1.0; 
my $align_th=0;
my $Seq_Align_model="ProbCons";
my @otherDAFSoptions=();

my $align_mix_geometric=0; #secret :
my $weight=0; #secret : option in making similarity, weight is weight for secondary structure to shape similarity 
my $sim_model = "cos"; #secret : (cos, alignprob_cos, alignprob)
my $cosgap_model = "gap_fill"; #secret : (gap_fill, gap_free) 
## --- --- ##

## --- Profile Align mode option --- ##
my @sampleNames = ();
## --- --- ##
#--- ---#

GetOptions(
    ## --- mode select --- ##
    'mode=s' => \$mode,
    ## --- common option --- #
    'help' => \$opthelp,
    'in=s' => \@infiles,
    'tmp=s' => \$tmpdir,
    'out=s' => \$outfile,
    'alpha=f' => \$alpha,
    'max-gap=i' => \$maxgap,
    'cov=i' => \$CovThreshold,
    'len=i' => \$LenThreshold,
    'non-both-end-zero' => \$bothendzero,
    'cut=i' => \$cut,
    ## --- DAFS mode option --- ##
    'beta=f' => \$beta,
    'weight-ss=f'=> \$weight_ss,
    'weight-shape=f'=> \$weight_shape,
    'align-th=f' => $align_th,
    'seq-align-model=s' => \$Seq_Align_model,
    'other=s' => \@otherDAFSoptions,
    'weight=f'=> \$weight,
    'align-mix-geometric' => \$align_mix_geometric,
    'sim-model=s' => \$sim_model, 
    'cosgap-model=s' => \$cosgap_model,
    ## --- Profile Align mode option --- ##
    'sample-name=s' => \@sampleNames,
    );

if($opthelp){&printhelp; exit(1);}
if($mode ne "Profile" && $#infiles != -1){$infile = shift @infiles;}
&CommondLineErrorCheck;
&printThresholdInfo;
# --- --- #
    
# --- main --- #
if($mode eq "shape")
{
    my $RunMode = 
	new Shape $infile, $outfile, $alpha, $maxgap, $CovThreshold, 
	$LenThreshold, $bothendzero, $cut;  
    $RunMode->RunShapeMode();
}
elsif($mode eq "Profile")
{
    my $RunMode = 
	new Profile \@infiles, \@sampleNames, $outfile, $alpha, $maxgap, 
	$CovThreshold, $LenThreshold, $bothendzero, $cut;    
    $RunMode->RunProfileMode();
}
elsif($mode eq "DAFS")
{
    my $RunMode = 
	new DAFS $infile, $outfile, $tmpdir, $alpha, $maxgap, $CovThreshold, 
	$LenThreshold, $bothendzero, $cut, $beta, $weight_ss, $weight_shape,
	$align_th, $Seq_Align_model, \@otherDAFSoptions, $align_mix_geometric,
	$weight, $sim_model, $cosgap_model;  
    $RunMode->RunDAFSMode();
}
print "\nSHARAKU done ...\n";
# --- --- #

# --- sub functions --- #

sub printhelp
{
    print "\nSHARAKU : SHape Aligner of non-coding RNA developed by Keio University\n";
    print "version 1.00\n\n";
    print "usage :\n";
    print"   shape mode   : perl SHARAKU.pl -mode shape -in INFILE -out OUTFILE [other Options]\n";
    print"   DAFS mode    : perl SHARAKU.pl -mode DAFS -in INFILE -out OUTFILE [other Options]\n\n";
#    print"   Profile mode : perl SHARAKU.pl -mode Profile -in 1st_INFILE -sample-name 1st_sample_name -in 2nd_INFILE -sample-name 2nd_sample_name\n";
#    print "                                  [other infiles or sample_names] -out OUTFILE [other Options]\n\n";
    print "Options : \n";
    print "  -mode <STRING>   : Alignment mode for SHARAKU (possible values=shape, DAFS, default=DAFS)\n";
    print "  -in   FILE       : input Seq and Coverage File (for Shape mode, named input file as <genes>.Coverage.txt)\n";
    print "  -out  FILE       : output distance matrix File  \n";
    print "  -tmp  DIR        : tmp directry (defalut = /tmp) \n";
    print "\n";

    print "Options for SHARAKU (for all mode) :\n";
    print "  -alpha <FLOAT>      : The ratio of allowed gaps against the length of the longer sequence  (default = 1.0, 0 <= alpha <= 1.0)\n";
    print "  -max-gap <INT>      : The max number of gaps for Sharaku (default = -1)\n";
    print "  -cov  <INT>         : Minimum threshold of max coverage of gene (default = 20) \n";                        
    print "  -len  <INT>         : Lenght Threshold (defalut = undefined)\n";
    print "                        If you use this option, genes which have exon lenght less than <INT> are used.\n";
    print "  -non-both-end-zero  : Treat the gap scores for both ends as end Coverage (default = off)\n";
    #print "  -cut <INT>      : trimming <INT> nt both of CoveragesVector (default = 0)\n\n";
    print "\n";

    print "Options for DAFS mode:\n";
    print "  -beta <FLOAT>             : The concentrate parameter for partition function of SHARAKU (default = -3.0, beta <= 0)\n";
    print "  -weight-ss <FLOAT>        : Weight of the expected accuracy score for secondary structures (default = 4.0, 0 <= weight-ss)\n";
    print "  -weight-shape <FLOAT>     : Percentage of alignment of read mapping profile in matching probabilities (default = 1.0, 0 <= weight-shape <= 1)\n";
    print "  -align-th <FLOAT>         : Threshold for matching probabilities (default = 0, 0 <= align-th <= 1.0)\n";
    print "  -seq-align-model <STRING> : Sequence alignment model for calcualating matching probablities\n";
    print "                              (possible values=CONTRAlign, ProbCons, default=ProbCons)\n\n"; 
    #print "  -align-mix-geometric      : ~~~~~ (default = off)\n\n";
    #print "  -weight <FLOAT> : weight for secondary structure to shape similarity in making similarity\n";
    #print "  Other Options of DAFS :\n";
    #print "    -other <STRING> : ex. <STRING>=\"--max-iter=<INT> --ipknot\"\n";
    #print "    if you want to see other Options of DAFS, please check by `dafs --help` \n\n";

    #print "Options for Profile mode:\n";
    #print "  -sample-name <STRING> : sample-name correspond to input file\n\n";
}

sub CommondLineErrorCheck
{    
    # --- mode check --- #
    if($mode ne "shape" && $mode ne "DAFS" && $mode ne "Profile")
    {
	print "SHARAKU mode select error!!\n";
	print "  please input SHARAKU mode : -mode <STRING> : STRING=shape or DAFS or Profile\n";
	exit(1);
    }
    print "\nSHARAKU mode : $mode\n\n";

    # --- infiles check --- #
    if($mode eq "shape" || $mode eq "DAFS")
    {
	if(!defined($infile))
	{
	    print "input File error!!\n";
	    print "  please input infile : -in FILE\n"; exit(1);
	}
	elsif(!-e $infile)
	{
	    print "input File error!!\n";
	    print "  Can't open infile : $infile\n"; exit(1);
	}
	print "input file : $infile\n";
    }
    elsif($mode eq "Profile")
    {
	if($#infiles != $#sampleNames)
	{
	    print "Profile mode : input Files and sample-names error!!\n";
	    print "  Num of input Files and sample-names are different\n";
	    exit(1);
	}
	elsif($#infiles == 0 && $#sampleNames == 0)
	{
	    print "Profile mode : input Files and sample-names error!!\n";
	    print "  Num of input Files and sample-names are different\n";
	    exit(1);
	}

	print "input files and sample-names :\n";
	for(my $i=0; $i<=$#infiles; $i++)
	{
	    my $num=$i+1;
	    if(!-e $infiles[$i])
	    {
		print "Profile mode : input Files error!!\n";
		print "  Can't open ${num}th infile : $infiles[$i]\n"; exit(1);
	    }

	    print "  ${num}th : input coverage file : $infiles[$i]\n";
	    print "  ${num}th : input sample-name   : $sampleNames[$i]\n";
	}
	print "\n";
    }

    # --- outfile check --- #
    if(!defined($outfile))
    {
	print "output File error!!\n";
	print "  please input outfile : -out FILE\n"; 
	exit(1);
    }

    open(TEST,"> $outfile") or die print "output File error!!\n  Can't open outfile : $outfile\n";
    close(TEST);
    #elsif(!-e $outfile)
    #{
#	print "output File error!!\n";
#	print "  Can't open outfile : $outfile\n"; exit(1);
#    }
    print "output file : $outfile\n";

    # --- parameter check --- #
    if($alpha < 0 || $alpha > 1){print "please input alpha with range of 0..1 : -alpha <FLOAT>\n"; exit(1);}
    if($CovThreshold <= 0){print "please input Max Coverage Threshold > 0 : -cov <INT>\n"; exit(1);}

    if($mode eq "DAFS")
    {
	if($beta > 0){print "please input beta <= 0 : -beta <FLOAT>\n"; exit(1);}
	if($weight_ss < 0){print "please input weight-ss >= 0 : -weigth-ss <FLOAT>\n"; exit(1);}
	if($weight_shape > 1 || $weight_shape < 0 ){print "please input weight-shape with range of 0..1 : -weight-shape <FLOAT>\n"; exit(1);}
	if($align_th < 0 || $align_th > 1){print "please input align-th with range of 0..1 : -align-th <FLOAT>\n"; exit(1);}
	if($Seq_Align_model ne "CONTRAlign" && $Seq_Align_model ne "ProbCons"){print "please input Sequence Alignment model for calcualating matching probablities : -seq-align-model ProbCons or CONTRAlign\n"; exit(1);}
	if (!-d "$tmpdir"){mkdir "$tmpdir" || die "can't make directory $tmpdir : please input other directory for tmp directory : -tmp DIR $!";}
    }
}

sub printThresholdInfo
{
    print "\n";
    print "Max_Coverage_Threshold = $CovThreshold : ";
    print "only input regions(or Genes) that have more than $CovThreshold as MaxCoverage \n";
    if($LenThreshold > 0)
    {
	print "Gene_Length_Threshold  = $LenThreshold : ";
	print "only input regions(or Genes) that have less than $LenThreshold as sum of exons Length \n";
    }
    print "\n";
}
# --- --- #
