#!/usr/bin/perl
package Mecom;
our $VERSION = 0.03;
# -----------------------------------------------------------------------------
# Molecular Evolution of Protein Complexes Contact Interfaces
# -----------------------------------------------------------------------------
# @Authors:  Hctor Valverde <hvalverde@uma.es> and Juan Carlos Aledo
# @Date:     May-2013
# @Location: Depto. Biologa Molecular y Bioqumica
#            Facultad de Ciencias. Universidad de Mlaga
#
# Copyright 2013 Hector Valverde and Juan Carlos Aledo.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of either: the GNU General Public License as published
# by the Free Software Foundation; or the Artistic License.
#
# See http://dev.perl.org/licenses/ for more information.
# -----------------------------------------------------------------------------

#                                   #---#                                    #

# -----------------------------------------------------------------------------
# Loading modules                                                      Chap.  1
# -----------------------------------------------------------------------------
use Molevol::Complex;
use Getopt::Long;
use Data::Dumper;
if($ENV{PAMLDIR} eq ""){
    die("\nThe environment variable 'PAMLDIR' is unset.
MECOM can't find the PAML software. Try
\nexport PAMLDIR='path/to/PAML/bin'\n\nand try again.\n")
    }
# -----------------------------------------------------------------------------
#                                                                            1.

#                                   #---#                                    #

# -----------------------------------------------------------------------------
# Variable initialization                                              Chap.  2
# -----------------------------------------------------------------------------
# Required:
    my $pdb;            #or    # 1a. A valid path to pdb file or
    my $contact_file;          # 1b. A valid contact file
    my $chain_alignment;       # 2. The chain/s alignment/s
    my $chain;                 # 3. Chain or chains to analyze
# Optional:
    my $pth;                   # 1. Proximity threshold (Angstroms)
    my $sth;                   # 2. Exposition threshold (ASA fraction)
    my $th_margin;             # 3. Exposition threshold margin
    my $spec_chains;           # 4. Chains to contact with
    my $informat;              # 5. Alignment format
    my $oformat;               # 6. Output format for sub-alignments
    my $gc;                    # 7. Genetic code
    my $ocontact = "data.str"; # 8. Contact output data file
    my $help;                  # 9. Help boolean
    my $report;                # 10. HTML report
    
GetOptions (                  # Getting options from command line                  
    "pdb=s"              => \$pdb,                  # --pdb
    "alignment=s"        => \$chain_alignment,      # --alignment
    "proximityth=f"      => \$pth,                  # --proximityth
    "exposureth=f"       => \$sth,                  # --exposureth
    "chain=s"            => \$chain,                # --chain
    "exposuretherror=f"  => \$th_margin,            # --exposuretherror
    "contactfile=s"      => \$contact_file,         # --contactfile
    "contactwith=s"      => \$spec_chains,          # --contactwith
    "informat=s"         => \$informat,             # --informat
    "oformat=s"          => \$oformat,              # --oformat
    "gc=i"               => \$gc,                   # --gc
    "ocontact=s"         => \$ocontact,             # --ocontact
    "help"               => \$help,                 # --help
    "report=s"           => \$report                # --report
);
# -----------------------------------------------------------------------------
#                                                                            2.

#                                   #---#                                    #

# -----------------------------------------------------------------------------
# HELP                                                                Chap.  3
# -----------------------------------------------------------------------------
if($help){
    print "HELP\n";
    exit;
}
# -----------------------------------------------------------------------------
#                                                                            3.

#                                   #---#                                    #

# -----------------------------------------------------------------------------
# Run program for multiple chains                                     Chap.  4
# -----------------------------------------------------------------------------
    # Welcome
    system("clear");
    print "\n---------------------------------------\n";
    print "\t RUNNING MECOM v$VERSION\n";
    print " Hector Valverde and Juan Carlos Aledo\n";
    print " \tUniversity of Malaga\n";
    print "\t     May, 2013\n";
    print "---------------------------------------\n\n";
    print "NOTICE: This distribution is an alpha version.\n";
    print "Unexpected errors could be dumped. Contact with\n";
    print "authors anonymously from http://mecom.hval.es/\n\n";
    print "Type 'mecom --help' on the command line to get\n";
    print "a summarized manual.\n\n";
    
my @chains = split(/ /,$chain);
# 1. Create the objects
my @objs_list = ();
if($#chains > 1){
    
    # The respective alignment files (also separated by commas)
    my @alignments = split(/ /,$chain_alignment);
    # Chains and align files number must be equal
    if($#chains != $#alignments){
        die("Invalid number of MSA files for specified input chains\n")
    }
    
    for (my $i=0;$i<scalar(@chains);$i++){
        
        #print $alignments[$i]."\n";
        my $new_obj = Molevol::Complex->new(
                                    pdb         => $pdb,
                                    contactfile => $contact_file,
                                    alignment   => $alignments[$i],
                                    chain       => $chains[$i],
                                    pth         => $pth,
                                    sth         => $sth,
                                    sthmargin   => $th_margin,
                                    contactwith => $spec_chains,
                                    informat    => $informat,
                                    oformat     => $oformat,
                                    gc          => $gc,
                                    ocontact    => $chains[$i].".tmp.str"
                                    );
        
        # Insert into the object list
        push(@objs_list, $new_obj);
        
    }
    
    print "1. Running structural calcs\n";
    # Run structural calcs
    for my $obj (@objs_list){
        
        # Run structural calcs
        print("Running structural calcs for chain: ".$obj->get_chain."\n");
        $obj->run_struct;
        
    }
    
    # If $ocontact does not exists, create it
    if(!-e $ocontact){
        # Concatenate structural data into a single file
        open CAT, ">>".$ocontact;
        for my $obj (@objs_list){
            
            open FILE, $obj->get_ocontact;
            while(<FILE>){
                print CAT $_;
            }
            unlink($obj->get_ocontact);
            $obj->set_ocontact($ocontact);
            
        }
        close CAT;
    }
    
    print "1. Running structural calcs\n";
    # Create the codon list
    for my $obj (@objs_list){
        
        $obj->run_filtering;
        
    }
    
    print "2. Filtering\n";
    # Create the sub-alignments
    for my $obj (@objs_list){
        
        $obj->run_subalign;
        
    }
    
    print "3. Building subalignments\n";
    # Concatenate sub-alignments
    # For each category within firs alignment
    my %merged_alns;
    for my $category (keys %{$objs_list[0]->get_subalns}){
        
        print "\t".$category."\n";
        # @extalns is an array with Bio::SimpleAlign objects
        my @extalns;
        for my $obj (@objs_list){
            push (@extalns, ${$obj->get_subalns}{$category});
        }
        
        # Merged alignments within the same category
        $merged_alns{$category} = Molevol::Complex->cat_aln(@extalns);
        
    }
    
    print "4. Sub-alignments concatenation\n";
    # Create a new object with the concatenated alignments
    my $coe = Molevol::Complex->new(
                                    pdb         => $pdb,
                                    contactfile => $contact_file,
                                    alignment   => $chain_alignment,
                                    chain       => $chain,
                                    pth         => $pth,
                                    sth         => $sth,
                                    sthmargin   => $th_margin,
                                    contactwith => $spec_chains,
                                    informat    => $informat,
                                    oformat     => $oformat,
                                    gc          => $gc,
                                    ocontact    => $ocontact,
                                    report      => $report
                                    );
    
    
    # Set the subalignment for the new object
    $coe->set_subalns(%merged_alns);
    
    print "5. Running evolutive calcs\n";
    # Yang
    $coe->run_yang;
    
    print "5. Running statistics\n";
    # Stats
    $coe->run_stats1;
    
    print "6. Writting HTML report\n";
    $coe->run_report;
    
    # open?
    print "Do you want to open the generated report? [Y/n]: ";
    my $userinput =  <STDIN>;
    chomp ($userinput);
    if($userinput =~ /y/i || $userinput =~ /yes/i || $userinput eq ""){
        system("open ".$coe->get_report);
    }
    
}


else{
# -----------------------------------------------------------------------------
#                                                                            4.

#                                   #---#                                    #

# -----------------------------------------------------------------------------
# Run program for a single chain                                      Chap.  5
# -----------------------------------------------------------------------------
# New object
my $coe = Molevol::Complex->new(
                                    pdb         => $pdb,
                                    contactfile => $contact_file,
                                    alignment   => $chain_alignment,
                                    chain       => $chain,
                                    pth         => $pth,
                                    sth         => $sth,
                                    sthmargin   => $th_margin,
                                    contactwith => $spec_chains,
                                    informat    => $informat,
                                    oformat     => $oformat,
                                    gc          => $gc,
                                    ocontact    => $ocontact,
                                    report      => $report
                                    );

    
    # Run calcs
    print "1. Running structural calcs\n";
    # Structural data
    $coe->run_struct;
    print "2. Filtering\n";
    # Filtering
    $coe->run_filtering;
    print "3. Building sub-alignments\n";
    # Sub-alignments
    $coe->run_subalign;
    print "4. Running evolutive analysis\n";
    # Yang
    $coe->run_yang;
    print "5. Running statistics\n";
    # Stats
    $coe->run_stats1;
    
    print "6. Writting HTML report\n";
    # Report
    $coe->run_report;
    
    # open?
    print "Do you want to open the generated report? [Y/n]: ";
    my $userinput =  "y";
    chomp ($userinput);
    if($userinput =~ /y/i || $userinput =~ /yes/i || $userinput eq ""){
        system("open ".$coe->get_report);
    }

}
    
    print "---------------------------------------\n";
    print "\t\tEND\n\n";
# -----------------------------------------------------------------------------
#                                                                            5.

#                                   #---#                                    #


1;

__END__

=head1 NAME

Mecom - Molecular Evolution for protein COMplexes

=head1 VERSION

Version 0.03

=head1 SYNOPSIS

MECOM is a Perl program which implements a work flow to analyze the evolutive
behaviour of different regions within a protein structure.

=head1 Support

This program, documentation, user manual and usage examples are available at:

    http://mecom.hval.es/

You can find documentation for this module with the UNIX man command.

    man mecom


=head1 License and copyright

Copyright 2013 Hector Valverde and Juan Carlos Aledo.

This program is free software; you can redistribute it and/or modify it
under the terms of either: the GNU General Public License as published
by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.

=cut


