""" This module contains all classes used to model intrinsics behavior.  """

from pythran.conversion import to_ast
from pythran.range import UNKNOWN_RANGE

import ast
import sys

if sys.version_info[0] > 2:
    ast3_arguments = ast.arguments

    def make_ast_arguments(*args):
        return ast3_arguments(args[0], args[1], [], [], args[2], args[3])
    ast.arguments = make_ast_arguments


class NewMem(ast.AST):

    """ Class to represent new location for aliasing. """


class UpdateEffect(object):
    pass


class ReadEffect(object):
    pass


class ReadOnceEffect(ReadEffect):
    pass


class Intrinsic(object):

    """
    Model any Method/Function.

    Its member variables are:

    - argument_effects that describes the effect of the function on its
      argument (either UpdateEffect, ReadEffect or ReadOnceEffect)
    - global_effects that describes wether the function has side effects
    - return_alias that describes the aliasing between the return value
      and the parameters. The lambda returns an ast expression, generally
      depending on the node arguments (see dict.setdefault)
    - args that describes the name and default value of each arg, using the
      same representation as ast.FunctionDef, i.e. ast.arguments
    """

    def __init__(self, **kwargs):
        self.argument_effects = kwargs.get('argument_effects',
                                           (UpdateEffect(),) * 11)
        self.global_effects = kwargs.get('global_effects', False)
        self.return_alias = kwargs.get('return_alias', lambda x: {NewMem()})
        self.return_type = kwargs.get('return_type', None)
        self.args = ast.arguments([ast.Name(n, ast.Param())
                                   for n in kwargs.get('args', [])],
                                  None, None,
                                  map(to_ast, kwargs.get('defaults', [])))
        self.return_range = kwargs.get("return_range",
                                       lambda call: UNKNOWN_RANGE)
        self.return_range_content = kwargs.get("return_ange_content",
                                               lambda c: UNKNOWN_RANGE)

    def isliteral(self):
        return False

    def isfunction(self):
        return False

    def isstaticfunction(self):
        return False

    def ismethod(self):
        return False

    def isattribute(self):
        return False

    def isconst(self):
        return not any(
            isinstance(x, UpdateEffect) for x in self.argument_effects
            ) and not self.global_effects

    def isreadonce(self, n):
        return isinstance(self.argument_effects[n], ReadOnceEffect)

    def combiner(self, s, node):
        pass


class FunctionIntr(Intrinsic):
    def __init__(self, **kwargs):
        kwargs.setdefault('combiners', ())
        super(FunctionIntr, self).__init__(**kwargs)
        self.combiners = kwargs['combiners']