"""
One of the really important features of |jedi| is to have an option to
understand code like this::

    def foo(bar):
        bar. # completion here
    foo(1)

There's no doubt wheter bar is an ``int`` or not, but if there's also a call
like ``foo('str')``, what would happen? Well, we'll just show both. Because
that's what a human would expect.

It works as follows:

- |Jedi| sees a param
- search for function calls named ``foo``
- execute these calls and check the input. This work with a ``ParamListener``.
"""

from jedi._compatibility import unicode
from jedi.parser import representation as pr
from jedi import settings
from jedi.evaluate import helpers
from jedi.evaluate.cache import memoize_default
from jedi.evaluate import imports

# This is something like the sys.path, but only for searching params. It means
# that this is the order in which Jedi searches params.
search_param_modules = ['.']


class ParamListener(object):
    """
    This listener is used to get the params for a function.
    """
    def __init__(self):
        self.param_possibilities = []

    def execute(self, params):
        self.param_possibilities.append(params)


@memoize_default([], evaluator_is_first_arg=True)
def search_params(evaluator, param):
    """
    A dynamic search for param values. If you try to complete a type:

    >>> def func(foo):
    ...     foo
    >>> func(1)
    >>> func("")

    It is not known what the type ``foo`` without analysing the whole code. You
    have to look for all calls to ``func`` to find out what ``foo`` possibly
    is.
    """
    if not settings.dynamic_params:
        return []
    from jedi.evaluate import representation as er

    def get_params_for_module(module):
        """
        Returns the values of a param, or an empty array.
        """
        @memoize_default([], evaluator_is_first_arg=True)
        def get_posibilities(evaluator, module, func_name):
            try:
                names = module.used_names[func_name]
            except KeyError:
                return []

            for name in names:
                stmt = name.get_definition()
                if not isinstance(stmt, pr.ExprStmt):
                    continue
                try:
                    trailer = name.parent.children[1]
                except IndexError:
                    continue
                else:
                    types = evaluator.goto_definition(name)

                    # TODO why not a direct comparison? functions seem to be
                    # decorated in types and not in compare...
                    c = [getattr(escope, 'base_func', None) or escope.base
                         for escope in types
                         if escope.isinstance(er.Function, er.Class)]
                    if compare in c:
                        # Only if we have the correct function we execute
                        # it, otherwise just ignore it.
                        evaluator.eval_trailer(types, trailer)


                # TODO REMOVE
                continue
                calls = helpers.scan_statement_for_calls(stmt, func_name)
                for c in calls:
                    # no execution means that params cannot be set
                    call_path = list(c.generate_call_path())
                    pos = c.start_pos
                    scope = stmt.parent

                    # This whole stuff is just to not execute certain parts
                    # (speed improvement), basically we could just call
                    # ``eval_call_path`` on the call_path and it would also
                    # work.
                    def listRightIndex(lst, value):
                        return len(lst) - lst[-1::-1].index(value) - 1

                    # Need to take right index, because there could be a
                    # func usage before.
                    call_path_simple = [unicode(d) if isinstance(d, pr.Name)
                                        else d for d in call_path]
                    i = listRightIndex(call_path_simple, func_name)
                    before, after = call_path[:i], call_path[i + 1:]
                    if not after and not call_path_simple.index(func_name) != i:
                        continue
                    scopes = [scope]
                    if before:
                        scopes = evaluator.eval_call_path(iter(before), c.parent, pos)
                        pos = None
                    for scope in scopes:
                        # Not resolving decorators is a speed hack:
                        # By ignoring them, we get the function that is
                        # probably called really fast. If it's not called, it
                        # doesn't matter. But this is a way to get potential
                        # candidates for calling that function really quick!
                        s = evaluator.find_types(scope, func_name, position=pos,
                                                 search_global=not before,
                                                 resolve_decorator=False)

                        c = [getattr(escope, 'base_func', None) or escope.base
                             for escope in s
                             if escope.isinstance(er.Function, er.Class)]
                        if compare in c:
                            # only if we have the correct function we execute
                            # it, otherwise just ignore it.
                            evaluator.follow_path(iter(after), s, scope)
            return listener.param_possibilities

        result = []
        for params in get_posibilities(evaluator, module, func_name):
            for p in params:
                if str(p) == str(param.get_name()):
                    result += p.parent.eval(evaluator)
        return result

    func = param.get_parent_until(pr.Function)
    current_module = param.get_parent_until()
    func_name = unicode(func.name)
    compare = func
    if func_name == '__init__':
        cls = func.get_parent_scope()
        if isinstance(cls, pr.Class):
            func_name = unicode(cls.name)
            compare = cls

    # add the listener
    listener = ParamListener()
    func.listeners.add(listener)

    try:
        result = []
        # This is like backtracking: Get the first possible result.
        for mod in imports.get_modules_containing_name([current_module], func_name):
            result = get_params_for_module(mod)
            if result:
                break
    finally:
        # cleanup: remove the listener; important: should not stick.
        func.listeners.remove(listener)

    return result

@@ -2221,48 +2221,231 @@
     
-try:%0A                    trailer = name.
+parent = name.parent%0A                if pr.is_node(parent, 'trailer'):%0A                    parent = parent.parent%0A%0A                trailer = None%0A                if pr.is_node(parent, 'power'):%0A                    for t in 
 pare
@@ -2457,17 +2457,19 @@
 ildren%5B1
-%5D
+:%5D:
 %0A       
@@ -2481,75 +2481,257 @@
     
-except IndexError:%0A                    continue%0A                els
+        if t == '**':%0A                            break%0A                        if t.start_pos %3E name.start_pos and t.children%5B0%5D == '(':%0A                            trailer = t%0A                            break%0A                if trailer is not Non
 e:%0A 

Fix issues with buggy trailers in dynamic params.