"""
File takes the output of compare_miso script (miso_vs_miso.miso_bf
    takes the gff3 gene lookup table generated by gff_make_annotation.py script
Outputs the event statistics along with the gene name
Format: {event_name}\t{chrom}\t{strand}\t{bayes}\t{diff}\t{isoforms}
"""

import argparse
from collections import defaultdict
import splicing_event as process_miso
import pdb

HEADER = "#event_name\tchrom\tstrand\tbayes\tdiff\tsample1_posterior_mean\tsample2_posterior_mean"

def parse_gene_lookup(filename):
    """
    Return dictionary of lookup file in the form
    {chrom:strand:splicesite : gene} 
    """
    lookup = defaultdict(list)
    with open(filename, 'r') as lookup_table:
        # check if this file has the right number of dimensions for a lookup
        # table
        for line in lookup_table:
            chrom, strand, ss, gene = line.split()
            if gene in lookup[":".join([chrom, strand, ss])]:
                pass
            else:
                lookup[":".join([chrom, strand, ss])].append(gene)
    return lookup


def load_miso_bf(miso_bf_file_name):
    miso_events = {}
    header = None
    with open(miso_bf_file_name, 'r') as miso_bf_file:
        for line in miso_bf_file:
            if header:
                splicing_event = process_miso.MisoEvent(line, header)
                if not splicing_event.name() in miso_events:
                    miso_events[splicing_event.name()] = splicing_event
                else:
                    raise ValueError(
                        "Two instances of miso event {m}", m=str(splicing_event))
            else:
                header = line.rstrip().split()
                if not 'event_name' in header:
                    raise ValueError("{firstline} is not an appropriate "
                                     "header for this file", firstline=header)
    return miso_events


def add_gene_names(ss_to_gene, event_dict):
    """ Takes the gene lookup table and event dictionary
    Returns the dictionary of splicing event objects with gene name"""
    for splicing_event in event_dict.values():
        for coord in splicing_event.get_full_coords():
            gene = ss_to_gene[coord][0] if coord in ss_to_gene else None
            splicing_event.add_gene(gene)
    return event_dict


def filter_event_dictionary(event_dict, outfile_name, cutoff_bayes):
    """If miso compare object passes the filter then print it"""
    with open(outfile_name, 'w') as outfile:
        outfile.write("{header}\n".format(header=HEADER))
        for splicing_event in event_dict.values():
            if splicing_event.passes_bayes_filter(cutoff_bayes) and splicing_event.has_negative_diff():
                outfile.write("{m}\n".format(m=str(splicing_event)))
            else:
                pass
    return None


def print_event_dict(event_dict, outfile_name):
    """If miso compare object passes the filter then print it"""
    with open(outfile_name, 'w') as outfile:
        outfile.write("{header}\n".format(header=HEADER))
        for splicing_event in event_dict.values():
            outfile.write("{m}\n".format(m=str(splicing_event)))
    return None


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('-g', '--gene_infile',
                        help="gff3 gene lookup table for miso annotations")
    parser.add_argument('-c', '--compare_miso',
                        help="output file from compare_miso script: miso_vs_miso.miso_.bf")
    parser.add_argument('-o', '--outfile',
                        help="output file")
    args = parser.parse_args()

    cutoff_bayes = 100.0
    # pdb.set_trace()
    gene_lookup_table = parse_gene_lookup(args.gene_infile)
    event_dict = load_miso_bf(args.compare_miso)
    event_dict_with_gene = add_gene_names(gene_lookup_table, event_dict)

    print_event_dict(event_dict_with_gene, args.outfile)

    filter_event_dictionary(event_dict_with_gene,
                            args.outfile.replace('.miso_bf', '_b' + str(cutoff_bayes) + '.miso_bf'), 
                            cutoff_bayes)


if __name__ == '__main__':
    main()
