# Path: sofia/step/step.py
# class Step(object):
#     """
#     A step that can be calculated from resources and other steps. Primarily concerned with execution of the step. Not
#     concerned with attributes etc...
#     """
#     
#     IN = []
#     OUT = []
#     PARAMS = []
# 
#     def consume_input(self, input):
#         """
#         Make a copy of the input for the run function and consume the input to free up the queue for more input. If all
#         input is consumed, there is no need to overload this function. Input is provided as lists. To copy and consume
#         input the following commands can be run:
# 
#         1. To consume all the input
#         >>> copy['entity'] = input['entity'][:]
#         >>> del input['entity'][:]
# 
#         2. To consume one item from the input (and pass it to run as a single item - not a list)
#         >>> copy['entity'] = input['entity'].pop()
# 
#         3. To use an item but not consume it
#         >>> copy['entity'] = input['entity'][0]
# 
#         :param input: input arguments
#         :return: copy of the input arguments
#         """
#         copy = {}
#         for key in input:
#             copy[key] = input[key][:]
#             del input[key][:]
#         return copy
# 
#     def run(self, **kwargs):
#         """
#         Run this step
# 
#         Assumes dependencies are already resolved. This function must be overridden when implementing new steps.
# 
#         :param kwargs: arguments defined in class IN variable
#         :return: output of running the step
#         """
#         return
#         yield  # allows the generator to return nothing
# 
#     def finalise(self):
#         """
#         Finalise the step. This function is a generator for the output entities that can only be produced when it is
#         known that the input stream has ended (eg. an output file).
#         :return:
#         """
#         return
#         yield  # allows the generator to return nothing
# 
#     @classmethod
#     def get_in_resolvers(cls):
#         return {}
# 
#     @classmethod
#     def get_out_resolvers(cls):
#         return {}
#     
#     def __str__(self):
#         """ Return the name of the step based on it's resources and
#         arguments. """
#         return self.name
# 
#     def __eq__(self, other):
#         return self.name == other.name
# 
#     def __hash__(self):
#         return hash(str(self))
# 
#     def get_user_warnings(self):
#         """ Called at the end to gather warnings for the user related to execution of the step.
# 
#         :return: set of warnings
#         """
#         return frozenset()


from lhc.binf.genomic_coordinate import GenomicPosition
from sofia.step import Step

class GetUpstreamORFs(Step):
    """
    Get the ORFs in the upstream region.
    """

    IN = ['upstream_sequence', 'genetic_code']
    OUT = ['upstream_orfs']

    def consume_input(self, input):
        copy = {
            'genetic_code': input['genetic_code'][0],
            'upstream_sequence': input['upstream_sequence'][:]
        }
        del input['upstream_sequence'][:]
        return copy

    def run(self, upstream_sequence, genetic_code):
        for sequence in upstream_sequence:
            stops = genetic_code.get_codons('*')
            res = []
            for i in range(len(sequence)):
                if not sequence[i:i + 3] == 'atg':
                    continue
                for j in range(i, len(sequence), 3):
                    if sequence[j:j + 3] in stops:
                        res.append(sequence[i:j + 3])
            yield res



# Path: sofia/step/step.py
# class Step(object):
#     """
#     A step that can be calculated from resources and other steps. Primarily concerned with execution of the step. Not
#     concerned with attributes etc...
#     """
#     
#     IN = []
#     OUT = []
#     PARAMS = []
# 
#     def consume_input(self, input):
#         """
#         Make a copy of the input for the run function and consume the input to free up the queue for more input. If all
#         input is consumed, there is no need to overload this function. Input is provided as lists. To copy and consume
#         input the following commands can be run:
# 
#         1. To consume all the input
#         >>> copy['entity'] = input['entity'][:]
#         >>> del input['entity'][:]
# 
#         2. To consume one item from the input (and pass it to run as a single item - not a list)
#         >>> copy['entity'] = input['entity'].pop()
# 
#         3. To use an item but not consume it
#         >>> copy['entity'] = input['entity'][0]
# 
#         :param input: input arguments
#         :return: copy of the input arguments
#         """
#         copy = {}
#         for key in input:
#             copy[key] = input[key][:]
#             del input[key][:]
#         return copy
# 
#     def run(self, **kwargs):
#         """
#         Run this step
# 
#         Assumes dependencies are already resolved. This function must be overridden when implementing new steps.
# 
#         :param kwargs: arguments defined in class IN variable
#         :return: output of running the step
#         """
#         return
#         yield  # allows the generator to return nothing
# 
#     def finalise(self):
#         """
#         Finalise the step. This function is a generator for the output entities that can only be produced when it is
#         known that the input stream has ended (eg. an output file).
#         :return:
#         """
#         return
#         yield  # allows the generator to return nothing
# 
#     @classmethod
#     def get_in_resolvers(cls):
#         return {}
# 
#     @classmethod
#     def get_out_resolvers(cls):
#         return {}
#     
#     def __str__(self):
#         """ Return the name of the step based on it's resources and
#         arguments. """
#         return self.name
# 
#     def __eq__(self, other):
#         return self.name == other.name
# 
#     def __hash__(self):
#         return hash(str(self))
# 
#     def get_user_warnings(self):
#         """ Called at the end to gather warnings for the user related to execution of the step.
# 
#         :return: set of warnings
#         """
#         return frozenset()


# Path: templates/genomics/steps/upstream_region.py
from lhc.binf.genomic_coordinate import GenomicPosition
from sofia.step import Step


class GetUpstreamORFs(Step):
    """
    Get the ORFs in the upstream region.
    """

    IN = ['upstream_sequence', 'genetic_code']
    OUT = ['upstream_orfs']

    def consume_input(self, input):
        copy = {
            'genetic_code': input['genetic_code'][0],
            'upstream_sequence': input['upstream_sequence'][:]
        }
        del input['upstream_sequence'][:]
        return copy

    def run(self, upstream_sequence, genetic_code):
        for sequence in upstream_sequence:
            stops = genetic_code.get_codons('*')
            res = []
            for i in range(len(sequence)):
                if not sequence[i:i + 3] == 'atg':
                    continue
                for j in range(i, len(sequence), 3):
                    if sequence[j:j + 3] in stops:
                        res.append(sequence[i:j + 3])
            yield res



class GetNumberOfUpstreamORFs(Step):