# Path: graftm/deduplicator.py
# class Deduplicator:
#     r"""Deduplicates sequences"""
#     
#     def deduplicate(self, aligned_sequence_objects):
#         r"""Sort the given aligned_sequence objects into an array of arrays,
#         where input sequences are grouped iff they have the same sequence
#         
#         Parameters
#         ----------
#         aligned_sequence_objects: array of Sequence objects
#             input sequences
#             
#         Returns
#         -------
#         Array of arrays of Sequence objects"""
#         
#         sequence_to_groups = {}
#         for s in aligned_sequence_objects:
#             try:
#                 sequence_to_groups[s.seq].append(s)
#             except KeyError:
#                 sequence_to_groups[s.seq] = [s]
#         return list(sequence_to_groups.values())
#     
#     def lca_taxonomy(self, deduplicated_sequences, taxonomy_hash):
#         r'''Given a set of deduplicated sequences and a taxonomy hash,
#         return the respective LCAs of taxonomy
#         
#         Parameters
#         ----------
#         deduplicated_sequences: Array of arrays of Sequence objects
#             as output from deduplicate()
#         taxonomy_hash: dictionary 
#             of sequence names to taxonomy array (i.e. array of str)
#         
#         Returns
#         -------
#         Array of taxonomy LCAs'''
#         
#         to_return = []
#         for dup_group in deduplicated_sequences:
#             lca = taxonomy_hash[dup_group[0].name]
#             for s in dup_group[1:]:
#                 for i, tax in enumerate(taxonomy_hash[s.name]):
#                     if i >= len(lca) or tax != lca[i]:
#                         lca = lca[:i]
#                         break
#                 if len(lca) > len(taxonomy_hash[s.name]):
#                     lca = lca[:len(taxonomy_hash[s.name])]
#             to_return.append(lca)
#         return to_return
# 
# Path: graftm/sequence_io.py
# class SequenceIO:
#     # Stolen from https://github.com/lh3/readfq/blob/master/readfq.py
#     def each(self, fp): # this is a generator function
#         last = None # this is a buffer keeping the last unprocessed line
#         while True: # mimic closure; is it a bad idea?
#             if not last: # the first record or a record following a fastq
#                 for l in fp: # search for the start of the next record
#                     if l[0] in '>@': # fasta/q header line
#                         last = l[:-1] # save this line
#                         break
#             if not last: break
#             name, seqs, last = last[1:].partition(" ")[0], [], None
#             for l in fp: # read the sequence
#                 if l[0] in '@+>':
#                     last = l[:-1]
#                     break
#                 seqs.append(l[:-1])
#             if not last or last[0] != '+': # this is a fasta record
#                 yield name, ''.join(seqs), None # yield a fasta record
#                 if not last: break
#             else: # this is a fastq record
#                 seq, leng, seqs = ''.join(seqs), 0, []
#                 for l in fp: # read the quality
#                     seqs.append(l[:-1])
#                     leng += len(l) - 1
#                     if leng >= len(seq): # have read enough quality
#                         last = None
#                         yield name, seq, ''.join(seqs); # yield a fastq record
#                         break
#                 if last: # reach EOF before reading enough quality
#                     yield name, seq, None # yield a fasta record instead
#                     break
# 
#     def each_sequence(self, fp):
#         '''Like each except iterate over Sequence objects'''
#         for name, seq, _ in self.each(fp):
#             yield Sequence(name, seq)
# 
#     def read_fasta_file(self, path_to_fasta_file):
#         seqs = []
#         with open(path_to_fasta_file) as f:
#             for name, seq, _ in self.each(f):
#                 seqs.append(Sequence(name, seq))
#         return seqs
# 
#     def write_fasta_file(self, sequence_objects, path_to_fasta_file):
#         with open(path_to_fasta_file,'w') as f:
#             self.write_fasta(sequence_objects, f)
# 
#     def write_fasta(self, sequence_objects, io):
#         for s in sequence_objects:
#             io.write(">")
#             io.write(s.name)
#             io.write("\n")
#             io.write(s.seq)
#             io.write("\n")
# 
# Path: graftm/orfm.py
# class OrfM:
#     def __init__(self, **kwargs):
#         self.min_orf_length = kwargs.pop('min_orf_length',96)
#         self.restrict_read_length = kwargs.pop('restrict_read_length',None)
#         if len(kwargs) > 0:
#             raise Exception("Unexpected arguments detected: %s" % kwargs)
#         
#     def command_line(self, input_path=None):
#         '''Return a string to run OrfM with, assuming sequences are incoming on
#         stdin and printed to stdout
#         
#         Parameters
#         ----------
#         input_path: str
#             path to the input path, or None for STDIN being the input
#         '''
#         
#         if self.min_orf_length:
#             orfm_arg_l = " -m %d" % self.min_orf_length
#         else:
#             orfm_arg_l = ''
#         
#         if self.restrict_read_length:
#             orfm_arg_l = " -l %d" % self.restrict_read_length
#             
#         cmd = 'orfm %s ' % orfm_arg_l
#         if input_path:
#             cmd += input_path
#         logging.debug("OrfM command chunk: %s" % cmd)
#         return cmd
#     
#     @staticmethod
#     def regular_expression():
#         '''Return a compiled regular expression matching the OrfM output defline
#         with the originalName, startPosition, frameNumber, orfNumber being
#         the contents of the regular expression'''
#         return re.compile('^(\S+)_(\d+)_(\d)_(\d+)')


from graftm.deduplicator import Deduplicator
from graftm.sequence_io import SequenceIO
from graftm.orfm import OrfM
import logging
import os

class Clusterer:

    def __init__(self):
        self.clust = Deduplicator()
        self.seqio = SequenceIO()
        self.seq_library = {}


# Path: graftm/deduplicator.py
# class Deduplicator:
#     r"""Deduplicates sequences"""
#     
#     def deduplicate(self, aligned_sequence_objects):
#         r"""Sort the given aligned_sequence objects into an array of arrays,
#         where input sequences are grouped iff they have the same sequence
#         
#         Parameters
#         ----------
#         aligned_sequence_objects: array of Sequence objects
#             input sequences
#             
#         Returns
#         -------
#         Array of arrays of Sequence objects"""
#         
#         sequence_to_groups = {}
#         for s in aligned_sequence_objects:
#             try:
#                 sequence_to_groups[s.seq].append(s)
#             except KeyError:
#                 sequence_to_groups[s.seq] = [s]
#         return list(sequence_to_groups.values())
#     
#     def lca_taxonomy(self, deduplicated_sequences, taxonomy_hash):
#         r'''Given a set of deduplicated sequences and a taxonomy hash,
#         return the respective LCAs of taxonomy
#         
#         Parameters
#         ----------
#         deduplicated_sequences: Array of arrays of Sequence objects
#             as output from deduplicate()
#         taxonomy_hash: dictionary 
#             of sequence names to taxonomy array (i.e. array of str)
#         
#         Returns
#         -------
#         Array of taxonomy LCAs'''
#         
#         to_return = []
#         for dup_group in deduplicated_sequences:
#             lca = taxonomy_hash[dup_group[0].name]
#             for s in dup_group[1:]:
#                 for i, tax in enumerate(taxonomy_hash[s.name]):
#                     if i >= len(lca) or tax != lca[i]:
#                         lca = lca[:i]
#                         break
#                 if len(lca) > len(taxonomy_hash[s.name]):
#                     lca = lca[:len(taxonomy_hash[s.name])]
#             to_return.append(lca)
#         return to_return
# 
# Path: graftm/sequence_io.py
# class SequenceIO:
#     # Stolen from https://github.com/lh3/readfq/blob/master/readfq.py
#     def each(self, fp): # this is a generator function
#         last = None # this is a buffer keeping the last unprocessed line
#         while True: # mimic closure; is it a bad idea?
#             if not last: # the first record or a record following a fastq
#                 for l in fp: # search for the start of the next record
#                     if l[0] in '>@': # fasta/q header line
#                         last = l[:-1] # save this line
#                         break
#             if not last: break
#             name, seqs, last = last[1:].partition(" ")[0], [], None
#             for l in fp: # read the sequence
#                 if l[0] in '@+>':
#                     last = l[:-1]
#                     break
#                 seqs.append(l[:-1])
#             if not last or last[0] != '+': # this is a fasta record
#                 yield name, ''.join(seqs), None # yield a fasta record
#                 if not last: break
#             else: # this is a fastq record
#                 seq, leng, seqs = ''.join(seqs), 0, []
#                 for l in fp: # read the quality
#                     seqs.append(l[:-1])
#                     leng += len(l) - 1
#                     if leng >= len(seq): # have read enough quality
#                         last = None
#                         yield name, seq, ''.join(seqs); # yield a fastq record
#                         break
#                 if last: # reach EOF before reading enough quality
#                     yield name, seq, None # yield a fasta record instead
#                     break
# 
#     def each_sequence(self, fp):
#         '''Like each except iterate over Sequence objects'''
#         for name, seq, _ in self.each(fp):
#             yield Sequence(name, seq)
# 
#     def read_fasta_file(self, path_to_fasta_file):
#         seqs = []
#         with open(path_to_fasta_file) as f:
#             for name, seq, _ in self.each(f):
#                 seqs.append(Sequence(name, seq))
#         return seqs
# 
#     def write_fasta_file(self, sequence_objects, path_to_fasta_file):
#         with open(path_to_fasta_file,'w') as f:
#             self.write_fasta(sequence_objects, f)
# 
#     def write_fasta(self, sequence_objects, io):
#         for s in sequence_objects:
#             io.write(">")
#             io.write(s.name)
#             io.write("\n")
#             io.write(s.seq)
#             io.write("\n")
# 
# Path: graftm/orfm.py
# class OrfM:
#     def __init__(self, **kwargs):
#         self.min_orf_length = kwargs.pop('min_orf_length',96)
#         self.restrict_read_length = kwargs.pop('restrict_read_length',None)
#         if len(kwargs) > 0:
#             raise Exception("Unexpected arguments detected: %s" % kwargs)
#         
#     def command_line(self, input_path=None):
#         '''Return a string to run OrfM with, assuming sequences are incoming on
#         stdin and printed to stdout
#         
#         Parameters
#         ----------
#         input_path: str
#             path to the input path, or None for STDIN being the input
#         '''
#         
#         if self.min_orf_length:
#             orfm_arg_l = " -m %d" % self.min_orf_length
#         else:
#             orfm_arg_l = ''
#         
#         if self.restrict_read_length:
#             orfm_arg_l = " -l %d" % self.restrict_read_length
#             
#         cmd = 'orfm %s ' % orfm_arg_l
#         if input_path:
#             cmd += input_path
#         logging.debug("OrfM command chunk: %s" % cmd)
#         return cmd
#     
#     @staticmethod
#     def regular_expression():
#         '''Return a compiled regular expression matching the OrfM output defline
#         with the originalName, startPosition, frameNumber, orfNumber being
#         the contents of the regular expression'''
#         return re.compile('^(\S+)_(\d+)_(\d)_(\d+)')


# Path: graftm/clusterer.py
from graftm.deduplicator import Deduplicator
from graftm.sequence_io import SequenceIO
from graftm.orfm import OrfM
import logging
import os


class Clusterer:

    def __init__(self):
        self.clust = Deduplicator()
        self.seqio = SequenceIO()
        self.seq_library = {}


        self.orfm_regex = OrfM.regular_expression()