# Path: pyani/pyani_jobs.py
# class Job(object):
# 
#     """Individual job to be run, with list of dependencies."""
# 
#     def __init__(self, name: str, command: str, queue: Optional[str] = None) -> None:
#         """Instantiate a Job object.
# 
#         :param name:           String describing the job (uniquely)
#         :param command:        String, the valid shell command to run the job
#         :param queue:          String, the SGE queue under which the job shall run
#         """
#         self.name = name  # Unique name for the job
#         self.queue = queue  # The SGE queue to run the job under
#         self.command = command  # Command line to run for this job
#         self.script = command
#         self.scriptPath = None  # type: Optional[Any]
#         self.dependencies = []  # type: List[Any]
#         self.submitted = False  # type: bool
#         self.finished = False  # type: int
# 
#     def add_dependency(self, job) -> None:
#         """Add passed job to the dependency list for this Job.
# 
#         :param job:  Job to be added to the Job's dependency list
# 
#         This Job should not execute until all dependent jobs are completed.
#         """
#         self.dependencies.append(job)
# 
#     def remove_dependency(self, job) -> None:
#         """Remove passed job from this Job's dependency list.
# 
#         :param job:     Job to be removed from the Job's dependency list
#         """
#         self.dependencies.remove(job)
# 
#     def wait(self, interval: float = SGE_WAIT) -> None:
#         """Wait until the job finishes, and poll SGE on its status.
# 
#         :param interval:  float, number of seconds to wait before polling SGE
#         """
#         while not self.finished:
#             time.sleep(interval)
#             interval = min(2.0 * interval, 60)
#             self.finished = os.system(f"qstat -j {self.name} > /dev/null")


import multiprocessing
import subprocess
import sys
from logging import Logger
from typing import List, Optional
from .pyani_jobs import Job
    jobgraph, workers: Optional[int] = None, logger: Optional[Logger] = None
) -> int:
    """Create and run pools of jobs based on the passed jobgraph.

    :param jobgraph:  list of jobs, which may have dependencies.
    :param workers:  int, number of workers to use with multiprocessing
    :param logger: a logger module logger (optional)

    The strategy here is to loop over each job in the list of jobs (jobgraph),
    and create/populate a series of Sets of commands, to be run in
    reverse order with multiprocessing_run as asynchronous pools.
    """
    cmdsets = []  # type: List
    for job in jobgraph:
        cmdsets = populate_cmdsets(job, cmdsets, depth=1)

    # Put command sets in reverse order, and submit to multiprocessing_run
    cmdsets.reverse()
    cumretval = 0
    for cmdset in cmdsets:
        if logger:  # Try to be informative, if the logger module is being used
            logger.info("Command pool now running:")
            for cmd in cmdset:
                logger.info(cmd)
        cumretval += multiprocessing_run(cmdset, workers)
        if logger:  # Try to be informative, if the logger module is being used
            logger.info("Command pool done.")
    return cumretval



# Path: pyani/pyani_jobs.py
# class Job(object):
# 
#     """Individual job to be run, with list of dependencies."""
# 
#     def __init__(self, name: str, command: str, queue: Optional[str] = None) -> None:
#         """Instantiate a Job object.
# 
#         :param name:           String describing the job (uniquely)
#         :param command:        String, the valid shell command to run the job
#         :param queue:          String, the SGE queue under which the job shall run
#         """
#         self.name = name  # Unique name for the job
#         self.queue = queue  # The SGE queue to run the job under
#         self.command = command  # Command line to run for this job
#         self.script = command
#         self.scriptPath = None  # type: Optional[Any]
#         self.dependencies = []  # type: List[Any]
#         self.submitted = False  # type: bool
#         self.finished = False  # type: int
# 
#     def add_dependency(self, job) -> None:
#         """Add passed job to the dependency list for this Job.
# 
#         :param job:  Job to be added to the Job's dependency list
# 
#         This Job should not execute until all dependent jobs are completed.
#         """
#         self.dependencies.append(job)
# 
#     def remove_dependency(self, job) -> None:
#         """Remove passed job from this Job's dependency list.
# 
#         :param job:     Job to be removed from the Job's dependency list
#         """
#         self.dependencies.remove(job)
# 
#     def wait(self, interval: float = SGE_WAIT) -> None:
#         """Wait until the job finishes, and poll SGE on its status.
# 
#         :param interval:  float, number of seconds to wait before polling SGE
#         """
#         while not self.finished:
#             time.sleep(interval)
#             interval = min(2.0 * interval, 60)
#             self.finished = os.system(f"qstat -j {self.name} > /dev/null")


# Path: pyani/run_multiprocessing.py
import multiprocessing
import subprocess
import sys
from logging import Logger
from typing import List, Optional
from .pyani_jobs import Job

    jobgraph, workers: Optional[int] = None, logger: Optional[Logger] = None
) -> int:
    """Create and run pools of jobs based on the passed jobgraph.

    :param jobgraph:  list of jobs, which may have dependencies.
    :param workers:  int, number of workers to use with multiprocessing
    :param logger: a logger module logger (optional)

    The strategy here is to loop over each job in the list of jobs (jobgraph),
    and create/populate a series of Sets of commands, to be run in
    reverse order with multiprocessing_run as asynchronous pools.
    """
    cmdsets = []  # type: List
    for job in jobgraph:
        cmdsets = populate_cmdsets(job, cmdsets, depth=1)

    # Put command sets in reverse order, and submit to multiprocessing_run
    cmdsets.reverse()
    cumretval = 0
    for cmdset in cmdsets:
        if logger:  # Try to be informative, if the logger module is being used
            logger.info("Command pool now running:")
            for cmd in cmdset:
                logger.info(cmd)
        cumretval += multiprocessing_run(cmdset, workers)
        if logger:  # Try to be informative, if the logger module is being used
            logger.info("Command pool done.")
    return cumretval



def populate_cmdsets(job: Job, cmdsets: List, depth: int) -> List: