#!/usr/bin/env python3
"""Template demo for Parallel Python (sum of primes via pp.Template).

Website: https://www.parallelpython.com
License: Apache-2.0 (see LICENSE and NOTICE)

Creates a reusable Template and submits multiple jobs from it, showing how
the function / depfuncs / modules are fixed and only the arguments vary.

Usage: python sum_primes_functor.py [ncpus]
"""

import math
import sys

import pp


def isprime(n):
    """Return True if *n* is prime, False otherwise."""
    if not isinstance(n, int):
        raise TypeError("argument passed to is_prime is not of 'int' type")
    if n < 2:
        return False
    if n == 2:
        return True
    limit = int(math.ceil(math.sqrt(n)))
    i = 2
    while i <= limit:
        if n % i == 0:
            return False
        i += 1
    return True


def sum_primes(n):
    """Calculate the sum of all primes below the given integer *n*."""
    return sum(x for x in range(2, n) if isprime(x))


def main():
    print("Usage: python sum_primes_functor.py [ncpus]")
    print("    [ncpus] - the number of workers to run in parallel,")
    print("    if omitted it will be set to the number of processors in the system")

    # tuple of all parallel python servers to connect with
    # ppservers = ("*",)          # auto-discover
    # ppservers = ("10.0.0.1",)  # static IP
    ppservers = ()

    if len(sys.argv) > 1:
        ncpus = int(sys.argv[1])
        job_server = pp.Server(ncpus, ppservers=ppservers)
    else:
        job_server = pp.Server(ppservers=ppservers)

    print("Starting pp with", job_server.get_ncpus(), "workers")

    # A Template fixes the function, depfuncs and modules; only the
    # arguments change on each .submit().
    fn = pp.Template(job_server, sum_primes, (isprime,), ("math",))

    # Single job using the template
    job1 = fn.submit(100)
    result = job1()
    print("Sum of primes below 100 is", result)

    # Submit 8 more jobs and retrieve the results
    inputs = (100000, 100100, 100200, 100300, 100400, 100500, 100600, 100700)
    jobs = [(value, fn.submit(value)) for value in inputs]

    for value, job in jobs:
        print("Sum of primes below", value, "is", job())

    job_server.print_stats()
    job_server.wait()
    job_server.destroy()


if __name__ == "__main__":
    main()
