import operator

from ..node import NodeVisitor
from ..parser import parse


class Compiler(NodeVisitor):
    """Compiler backend that evaluates conditional expressions
    to give static output"""

    def compile(self, tree, expr_data, data_cls_getter=None, **kwargs):
        """Compile a raw AST into a form with conditional expressions
        evaluated.

        tree - The root node of the wptmanifest AST to compile

        expr_data - A dictionary of key / value pairs to use when
                    evaluating conditional expressions

        data_cls_getter - A function taking two parameters; the previous
                          output node and the current ast node and returning
                          the class of the output node to use for the current
                          ast node
        """

        self._kwargs = kwargs
        self.expr_data = expr_data

        if data_cls_getter is None:
            self.data_cls_getter = lambda x, y: ManifestItem
        else:
            self.data_cls_getter = data_cls_getter

        self.output_node = None
        self.visit(tree)
        return self.output_node

    def visit_DataNode(self, node):
        output_parent = self.output_node
        if self.output_node is None:
            assert node.parent is None
            self.output_node = self.data_cls_getter(None, None)(None, **self._kwargs)
        else:
            self.output_node = self.data_cls_getter(self.output_node, node)(node.data)

        for child in node.children:
            self.visit(child)

        if output_parent is not None:
            output_parent.append(self.output_node)
            self.output_node = self.output_node.parent

    def visit_KeyValueNode(self, node):
        key_name = node.data
        key_value = None
        for child in node.children:
            value = self.visit(child)
            if value is not None:
                key_value = value
                break
        if key_value is not None:
            self.output_node.set(key_name, key_value)

    def visit_ValueNode(self, node):
        return node.data

    def visit_AtomNode(self, node):
        return node.data

    def visit_ListNode(self, node):
        return [self.visit(child) for child in node.children]

    def visit_ConditionalNode(self, node):
        assert len(node.children) == 2
        if self.visit(node.children[0]):
            return self.visit(node.children[1])

    def visit_StringNode(self, node):
        value = node.data
        for child in node.children:
            value = self.visit(child)(value)
        return value

    def visit_NumberNode(self, node):
        if "." in node.data:
            return float(node.data)
        else:
            return int(node.data)

    def visit_VariableNode(self, node):
        value = self.expr_data[node.data]
        for child in node.children:
            value = self.visit(child)(value)
        return value

    def visit_IndexNode(self, node):
        assert len(node.children) == 1
        index = self.visit(node.children[0])
        return lambda x: x[index]

    def visit_UnaryExpressionNode(self, node):
        assert len(node.children) == 2
        operator = self.visit(node.children[0])
        operand = self.visit(node.children[1])

        return operator(operand)

    def visit_BinaryExpressionNode(self, node):
        assert len(node.children) == 3
        operator = self.visit(node.children[0])
        operand_0 = self.visit(node.children[1])
        operand_1 = self.visit(node.children[2])

        return operator(operand_0, operand_1)

    def visit_UnaryOperatorNode(self, node):
        return {"not": operator.not_}[node.data]

    def visit_BinaryOperatorNode(self, node):
        return {"and": operator.and_,
                "or": operator.or_,
                "==": operator.eq,
                "!=": operator.ne}[node.data]


class ManifestItem(object):
    def __init__(self, name, **kwargs):
        self.parent = None
        self.name = name
        self.children = []
        self._data = {}

    def __repr__(self):
        return "<ManifestItem %s>" % (self.name)

    def __str__(self):
        rv = [repr(self)]
        for item in self.children:
            rv.extend("  %s" % line for line in str(item).split("\n"))
        return "\n".join(rv)

    @property
    def is_empty(self):
        if self._data:
            return False
        return all(child.is_empty for child in self.children)

    @property
    def root(self):
        node = self
        while node.parent is not None:
            node = node.parent
        return node

    def has_key(self, key):
        for node in [self, self.root]:
            if key in node._data:
                return True
        return False

    def get(self, key):
        for node in [self, self.root]:
            if key in node._data:
                return node._data[key]
        raise KeyError

    def set(self, name, value):
        self._data[name] = value

    def remove(self):
        if self.parent:
            self.parent._remove_child(self)

    def _remove_child(self, child):
        self.children.remove(child)
        child.parent = None

    def iterchildren(self, name=None):
        for item in self.children:
            if item.name == name or name is None:
                yield item

    def _flatten(self):
        rv = {}
        for node in [self, self.root]:
            for name, value in node._data.items():
                if name not in rv:
                    rv[name] = value
        return rv

    def items(self):
        for item in self._flatten().items():
            yield item

    def keys(self):
        for item in self._flatten().keys():
            yield item

    def values(self):
        for item in self._flatten().values():
            yield item

    def append(self, child):
        child.parent = self
        self.children.append(child)
        return child


def compile_ast(ast, expr_data, data_cls_getter=None, **kwargs):
    return Compiler().compile(ast,
                              expr_data,
                              data_cls_getter=data_cls_getter,
                              **kwargs)


def compile(stream, expr_data, data_cls_getter=None, **kwargs):
    return compile_ast(parse(stream),
                       expr_data,
                       data_cls_getter=data_cls_getter,
                       **kwargs)
