# -*- coding: utf-8 -*-
from __future__ import division, print_function, with_statement

from threading import Timer

from metaopt.core.returnspec import ReturnSpec
from metaopt.invoker.multiprocess import MultiProcessInvoker
from metaopt.invoker.pluggable import PluggableInvoker
from metaopt.optimizer.saes import SAESOptimizer
from metaopt.util.stoppable import StoppedException


def custom_optimize(f, invoker, param_spec=None, return_spec=None,
                    timeout=None, optimizer=SAESOptimizer()):
    """
    Optimizes the given objective function using the specified invoker.

    :param f: Objective function
    :param invoker: Invoker
    :param timeout: Available time for optimization (in seconds)
    :param optimizer: Optimizer
    """

    invoker.f = f

    try:
        invoker.param_spec = param_spec or f.param_spec
    except AttributeError:
        raise NoParamSpecError()

    try:
        invoker.return_spec = return_spec or f.return_spec
    except AttributeError:
        invoker.return_spec = ReturnSpec(f)

    if timeout is not None:
        Timer(timeout, invoker.stop).start()

    result = optimizer.optimize(invoker=invoker, function=f,
                                param_spec=invoker.param_spec,
                                return_spec=invoker.return_spec)

    try:
        invoker.stop()
    except StoppedException:
        pass

    return tuple(result)


def optimize(f, param_spec=None, return_spec=None, timeout=None, plugins=[],
             optimizer=SAESOptimizer()):
    """
    Optimizes the given objective function.

    :param f: Objective function
    :param timeout: Available time for optimization (in seconds)
    :param plugins: List of plugins
    :param optimizer: Optimizer

    """

    invoker = PluggableInvoker(invoker=MultiProcessInvoker(), plugins=plugins)

    return custom_optimize(f, invoker=invoker, param_spec=param_spec,
                           return_spec=return_spec, timeout=timeout,
                           optimizer=optimizer)


class NoParamSpecError(Exception):
    """The error that occurs when no ParamSpec object is provided"""
    pass

@@ -1074,16 +1074,24 @@
 %0A       
+ timer =
  Timer(t
@@ -1111,16 +1111,30 @@
 er.stop)
+%0A        timer
 .start()
@@ -1400,16 +1400,112 @@
   pass%0A%0A
+    if timeout is not None:%0A        timer.cancel()%0A%0A    if result is None:%0A        return None%0A%0A
     retu

Fix some bugs and misbevhaviour in custom_optimize()