#!/usr/bin/env python

import os
from TriAnnot.TriAnnotTask import *
from TriAnnot.TriAnnotConfig import *


class FuncAnnot (TriAnnotTask):

    def __init__(self):
        # Raise an error if the user try to use FuncAnnot itself instead of one of the valid subclass
        if self.__class__.__name__ == 'FuncAnnot':
            raise RuntimeError("FuncAnnot is not a valid task type ! Please use one of the following task type instead: %s" % self.getValidSubClassesNames())

        # Attributes
        self.numberOfSequenceToAnnotate = None
        self.preExecutionTreatmentsCompleted = False


    def getValidSubClassesNames(self):
        validClasseslist = []
        for subClass in self.__class__.__subclasses__():
            validClasseslist.append(subClass.__name__)
        return ', '.join(validClasseslist)


    def needToLaunchSubProcesses(self):
        if self.runner.jobType == 'execution':
            if self.numberOfSequenceToAnnotate > 1:
                return True
            else:
                return False
        else:
            return False


    def preExecutionTreatments(self):
        raise NotImplementedError('No preExecutionTreatments method implemented for class <%s>' % (self.__class__.__name__))


    def _analyzeSequenceFile(self):
        # Initializations
        self.numberOfSequenceToAnnotate = 0

        # Open the protein sequence file
        try:
            proteinSequenceFile = open(os.path.join(self.mainExecDir, TriAnnotConfig.TRIANNOT_CONF['DIRNAME']['sequence_files'], self.sequence), 'r')
        except IOError, KeyError:
            self.needToAbortPipeline = True
            self.abortPipelineReason = "Could not open/read the input sequence file for %s %s" % (self.__class__.__name__, self.getDescriptionString())

        # Count the number of sequence
        for line in proteinSequenceFile:
            if line.startswith('>'):
                self.numberOfSequenceToAnnotate += 1

        # Close file
        proteinSequenceFile.close()


    def createAbortFileForSubTriAnnot(self):
        # Initialization
        abortFileDirectoryPath = os.path.join(self.mainExecDir, self.getTaskExecDirName())
        abortFilePath = os.path.join(abortFileDirectoryPath, 'TriAnnot_abort')
        abortFileObject = None

        # Early errors might happened before the task execution directory creation so we might need to wait a little bit
        for i in range(1,3):
            if not os.path.isdir(abortFileDirectoryPath):
                sleep(2)
                continue
            else:
                break

        # Abort file creation attempt
        try:
            abortFileObject = open(abortFilePath, 'w')
            abortFileObject.write("kill=yes")
        except IOError:
            self.logger.error("Could not create TriAnnot_abort file")
        finally:
            if abortFileObject is not None:
                abortFileObject.close()
                self.logger.debug("Abort file created: %s" % (abortFilePath))


    def abort(self, killOnAbort = False):
        # The abort process is different when you are on a sub TriAnnot Pipeline or not
        if self.parameters['isSubAnnotation'] == 'no' and self.runner.jobType == 'execution':
            # We have to abort the sub TriAnnot Pipeline instance by creating a TriAnnot_abort file in the good execution directory
            if killOnAbort:
                self.logger.info("%s is a complex module that executes sub annotation tasks with a sub TriAnnot instance." % (self.__class__.__name__))
                self.logger.info("Stopping the sub instance with a well placed TriAnnot_abort file..")

                # Generate a TriAnnot_abort to abort the execution of the sub TriAnnot instance
                self.createAbortFileForSubTriAnnot()
            else:
                self.logger.info("%s is a complex module that executes sub annotation tasks with a sub TriAnnot instance." % (self.__class__.__name__))
                self.logger.info("To stop this sub instance you will have to manually create a TriAnnot_abort file in the %s execution directory (i.e. the main execution directory of the sub instance)" % (self.__class__.__name__))
                self.logger.info("In addition you will also need to kill every processes/jobs generated by the sub TriAnnot Pipeline itself")
        else:
            # We have to kill any task/process spawned by the sub triAnnot instance
            # The standard abort method (from the parent class) will do just fine if killOnAbort is given as parameter
            super(FuncAnnot, self).abort(killOnAbort)
