# Path: stripstream/pddl/logic/predicates.py
# class Predicate(Head):
#     pass
#     """
#   Predicate P which extends :class:`.NamedHead`.
#   """
# 
# Path: stripstream/pddl/objects.py
# class Constant(Object):
#     pass
#     """
#   PDDL constant which extends :class:`.Object`.
#   """
# 
# Path: stripstream/pddl/operators.py
# class STRIPSAxiom(Axiom, STRIPS):
#     """
#     STRIPS axiom class which extends :class:`.Axiom` by assuming
#     ``condition`` is a conjunction of literals.
# 
#     .. code:: python
# 
#       BLOCK, POSE = EasyType(), EasyType()
#       AtPose = EasyPredicate(BLOCK, POSE)
#       CollisionFree = EasyPredicate(POSE, POSE)
#       Safe = EasyPredicate(BLOCK, POSE)
#       B2 = EasyParameter(BLOCK)
#       P1, P2 = EasyParameter(POSE), EasyParameter(POSE)
# 
#       x = Axiom(conditions=[AtPose(B2, P2), CollisionFree(P1, P2)],
#                 effects=[Safe(B2, P1)])
#     """
# 
#     def __init__(self, conditions, effects):
#         """
#         :param conditions: a list of :class:`.Atom` or :class:`.Not`
#         :param effects: a list of :class:`.Atom` or :class:`.Not`
#         """
#         if len(effects) != 1:
#             raise NotImplementedError(
#                 'Currently only support a single effect: %s' % effects)
#         if not all(is_literal(c) for c in conditions):
#             raise ValueError(
#                 'Conditions must all be literals: %s' % conditions)
#         if not all(is_literal(e) for e in effects):
#             raise ValueError('Effects must all be literals: %s' % effects)
#         self.conditions, self.effects = conditions, effects
#         self.free_parameters = list(set(flatten(
#             c.get_parameters() for c in conditions)) - set(effects[0].get_parameters()))
#         super(STRIPSAxiom, self).__init__(
#             effects[0], Exists(self.free_parameters, And(*conditions)))
# 
# Path: stripstream/fts/variable.py
# class VariableType(Type):
# class FreeParameter(SSParameter):
# class Variable(object):
# class VariableSet(object):
# class VariableMember(object):
#     def __init__(self, name=None, domain=None):
#     def __call__(self, value):
#     def get_value(self, const):
#     def param(self, name):
# def get_value(const):
#     def __init__(self, name, type=None):
# def var_name(var):
# def var_args(var):
# def split_var(var):
#     def __init__(self, name, dtype, args=[]):
#     def __repr__(self):
#     def __init__(self, name):
#     def __getitem__(self, var):
#     def __call__(self, *args):
#     def __repr__(self):
#     def __init__(self, temp, var):
#     def __eq__(self, other):
#     def __ne__(self, other):
#     def __hash__(self):
#     def __repr__(self):
# def is_parameter(v):
# def is_constant(v):
# def expand_variables(vars):
# def make_var_constants(var, var_map):
# X = VariableSet('x')
# U = VariableSet('u')


from stripstream.pddl.logic.predicates import Predicate
from stripstream.pddl.objects import Constant
from stripstream.pddl.operators import STRIPSAxiom
from stripstream.fts.variable import FreeParameter, VarMember, Par

def create_axiom(con_form, var_names, params, inputs, var_map, axiom_map):
    key = (con_form, tuple(var_names), tuple(params), tuple(inputs))
    if key not in axiom_map:
        conditions = []
        for name, nested in zip(var_names, params):
            if name is not None:
                conditions.append(var_map[name].predicate(*nested))
        con_params = [nested[-1] for nested in params]
        conditions.append(con_form.predicate(*con_params))

        DerPred = Predicate('_der_%s' % len(axiom_map), [
                            par.type for par in inputs])
        effect = DerPred(*inputs)
        axiom_map[key] = STRIPSAxiom(conditions, [effect])
    return axiom_map[key].effects[0]


def get_derived(con, var_map, axiom_map, constants):

    param_map = {}
    num_params = [0]

    def get_item(item, dtype):
        if isinstance(item, FreeParameter) or isinstance(item, VarMember):
            if item not in param_map:
                num_params[0] += 1
                param_map[item] = Par('%s' % num_params[0], dtype)
            return param_map[item]
        num_params[0] += 1

# Path: stripstream/pddl/logic/predicates.py
# class Predicate(Head):
#     pass
#     """
#   Predicate P which extends :class:`.NamedHead`.
#   """
# 
# Path: stripstream/pddl/objects.py
# class Constant(Object):
#     pass
#     """
#   PDDL constant which extends :class:`.Object`.
#   """
# 
# Path: stripstream/pddl/operators.py
# class STRIPSAxiom(Axiom, STRIPS):
#     """
#     STRIPS axiom class which extends :class:`.Axiom` by assuming
#     ``condition`` is a conjunction of literals.
# 
#     .. code:: python
# 
#       BLOCK, POSE = EasyType(), EasyType()
#       AtPose = EasyPredicate(BLOCK, POSE)
#       CollisionFree = EasyPredicate(POSE, POSE)
#       Safe = EasyPredicate(BLOCK, POSE)
#       B2 = EasyParameter(BLOCK)
#       P1, P2 = EasyParameter(POSE), EasyParameter(POSE)
# 
#       x = Axiom(conditions=[AtPose(B2, P2), CollisionFree(P1, P2)],
#                 effects=[Safe(B2, P1)])
#     """
# 
#     def __init__(self, conditions, effects):
#         """
#         :param conditions: a list of :class:`.Atom` or :class:`.Not`
#         :param effects: a list of :class:`.Atom` or :class:`.Not`
#         """
#         if len(effects) != 1:
#             raise NotImplementedError(
#                 'Currently only support a single effect: %s' % effects)
#         if not all(is_literal(c) for c in conditions):
#             raise ValueError(
#                 'Conditions must all be literals: %s' % conditions)
#         if not all(is_literal(e) for e in effects):
#             raise ValueError('Effects must all be literals: %s' % effects)
#         self.conditions, self.effects = conditions, effects
#         self.free_parameters = list(set(flatten(
#             c.get_parameters() for c in conditions)) - set(effects[0].get_parameters()))
#         super(STRIPSAxiom, self).__init__(
#             effects[0], Exists(self.free_parameters, And(*conditions)))
# 
# Path: stripstream/fts/variable.py
# class VariableType(Type):
# class FreeParameter(SSParameter):
# class Variable(object):
# class VariableSet(object):
# class VariableMember(object):
#     def __init__(self, name=None, domain=None):
#     def __call__(self, value):
#     def get_value(self, const):
#     def param(self, name):
# def get_value(const):
#     def __init__(self, name, type=None):
# def var_name(var):
# def var_args(var):
# def split_var(var):
#     def __init__(self, name, dtype, args=[]):
#     def __repr__(self):
#     def __init__(self, name):
#     def __getitem__(self, var):
#     def __call__(self, *args):
#     def __repr__(self):
#     def __init__(self, temp, var):
#     def __eq__(self, other):
#     def __ne__(self, other):
#     def __hash__(self):
#     def __repr__(self):
# def is_parameter(v):
# def is_constant(v):
# def expand_variables(vars):
# def make_var_constants(var, var_map):
# X = VariableSet('x')
# U = VariableSet('u')


# Path: stripstream/fts/derived.py
from stripstream.pddl.logic.predicates import Predicate
from stripstream.pddl.objects import Constant
from stripstream.pddl.operators import STRIPSAxiom
from stripstream.fts.variable import FreeParameter, VarMember, Par


def create_axiom(con_form, var_names, params, inputs, var_map, axiom_map):
    key = (con_form, tuple(var_names), tuple(params), tuple(inputs))
    if key not in axiom_map:
        conditions = []
        for name, nested in zip(var_names, params):
            if name is not None:
                conditions.append(var_map[name].predicate(*nested))
        con_params = [nested[-1] for nested in params]
        conditions.append(con_form.predicate(*con_params))

        DerPred = Predicate('_der_%s' % len(axiom_map), [
                            par.type for par in inputs])
        effect = DerPred(*inputs)
        axiom_map[key] = STRIPSAxiom(conditions, [effect])
    return axiom_map[key].effects[0]


def get_derived(con, var_map, axiom_map, constants):

    param_map = {}
    num_params = [0]

    def get_item(item, dtype):
        if isinstance(item, FreeParameter) or isinstance(item, VarMember):
            if item not in param_map:
                num_params[0] += 1
                param_map[item] = Par('%s' % num_params[0], dtype)
            return param_map[item]
        num_params[0] += 1

        return Par('%s' % num_params[0], dtype)