class Buffer:
    def __init__(self, embs, tokens, alignments):
        self.embs = embs
        self.tokens = tokens
        if alignments is not None:
            for token, al in zip(tokens, alignments):
                token.nodes = al

    def __repr__(self):
        buf = [item.word for item in self.tokens]
        return '<%s %s>' % (
            self.__class__.__name__, buf)

    def size(self):
        return len(self.tokens)

    def reorder(self, deps, N):
        order = deps.postorder(N)
        if order is not None:
            self.tokens = order

    def isEmpty(self):
        return self.tokens == []

    def consume(self):
        return self.tokens.pop(0)

    def peek(self, index = 0):
        if len(self.tokens) > index:
            return self.tokens[index]
        return None

    def next(self):
        return self.tokens[1]

    def words(self, K, start = 0):
        ret = []
        for item in self.tokens[start:(K+start)]:
            ret.append(self.embs.words.get(item.word))
        for i in range(len(ret), K):
            ret.append(self.embs.words.get("<NULL>"))
        assert(len(ret) == K)
        return ret

    def pos(self, K, start = 0):
        ret = []
        for item in self.tokens[start:(K+start)]:
            ret.append(self.embs.pos.get(item.pos))
        for i in range(len(self.tokens), K):
            ret.append(self.embs.pos.get("<NULLPOS>"))
        assert(len(ret) == K)
        return ret

    def nes(self, K, start = 0):
        ret = []
        for item in self.tokens[start:(K+start)]:
            ret.extend(self.embs.nes.get(item.ne))
        for i in range(len(self.tokens), K):
            ret.extend(self.embs.nes.get("<NULLNE>"))
        return ret

    def  __eq__(self, other):
        return other is not None and self.tokens == other.tokens class Stack:
    def __init__(self, embs):
        root = Node(True)
        self.embs = embs
        self.nodes = [root]
        self.relations = Relations()

    def __repr__(self):
        stack = []
        for item in self.nodes:
            if item.isRoot:
                stack.append("ROOT")
            else:
                stack.append(item.concept)
        return '<%s %s %s>' % (self.__class__.__name__, stack, self.relations)

    def isEmpty(self):
        return len(self.nodes) == 1

    def push(self, n):
        assert(isinstance(n, Node))
        self.nodes.append(n)

    def pop(self, k = 0):
        if k == 0:
            return self.nodes.pop()
        k = len(self.nodes) - 1 - k
        return self.nodes.pop(k)

    def top(self):
        return self.nodes[len(self.nodes) - 1]

    def get(self, K):
        if len(self.nodes) - 1 - K < 0:
            return None
        try:
            return self.nodes[len(self.nodes) - 1 - K]
        except IndexError:
            return None

    def root(self):
        return self.nodes[0]

    def size(self):
        return len(self.nodes)

    def concepts(self, K, start = 0):
        origK = K
        ret = []
        if start < 0:
            for i in range(start, 0):
                ret.append(self.embs.words.get("<NULL>"))
                K-= 1
            start = 0

        nodes = [n for n in self.nodes[::-1][start:(K+start)]]
        for item in nodes:
            if item.isRoot:
                ret.append(self.embs.words.get("<TOP>"))
            elif item.isConst:
                ret.append(self.embs.words.get(item.constant))
            else:
                ret.append(self.embs.words.get(item.concept))

        for i in range(len(ret), origK):
            ret.append(self.embs.words.get("<NULL>"))
        return ret

    def words(self, K, start = 0):
        origK = K
        ret = []
        if start < 0:
            for i in range(start, 0):
                ret.append(self.embs.words.get("<NULL>"))
                K -= 1
            start = 0

        nodes = [n for n in self.nodes[::-1][start:(K+start)]]
        for item in nodes:
            if item.isRoot:
                ret.append(self.embs.words.get("<TOP>"))
            else:
                ret.append(self.embs.words.get(item.token.word))
        for i in range(len(ret), origK):
            ret.append(self.embs.words.get("<NULL>"))
        return ret

    def pos(self, K, start = 0):
        origK = K
        ret = []
        if start < 0:
            for i in range(start, 0):
                ret.append(self.embs.pos.get("<NULLPOS>"))
                K -= 1
            start = 0

        nodes = [n for n in self.nodes[::-1][start:(K+start)]]
        for item in nodes:
            if item.isRoot:
                ret.append(self.embs.pos.get("<TOP>"))
            else:
                ret.append(self.embs.pos.get(item.token.pos))
        for i in range(len(ret), origK):
            ret.append(self.embs.pos.get("<NULLPOS>"))
        assert(len(ret) == origK)
        return ret

    def nes(self, K, start = 0):
        origK = K
        ret = []
        if start < 0:
            for i in range(start, 0):
                ret.extend(self.embs.nes.get("<NULLNE>"))
                K -= 1
            start = 0

        nodes = [n for n in self.nodes[::-1][start:(K+start)]]
        for item in nodes:
            if item.isRoot:
                ret.extend(self.embs.nes.get("<TOP>"))
            else:
                ret.extend(self.embs.nes.get(item.token.ne))
        for i in range(len(ret)/self.embs.nes.dim, origK):
            ret.extend(self.embs.nes.get("<NULLNE>"))
        return ret

    def  __eq__(self, other):
        return other is not None and self.nodes == other.nodes and self.relations == other.relations class Node:
    def __init__(self, token, var = None, concept = None, isConst = None):
        assert (type(token) == bool and token == True) or (var is not None and isConst is not None)
        if type(token) == bool and token == True: # special case for top node, use token as boolean flag
            self.isRoot = True
            self.token = None
            self.isConst = None
            self.constant = None
            self.concept = None
            self.var = None
        else:
            self.isRoot = False
            self.token = token
            if isConst:
                self.isConst = True
                self.constant = var
                self.var = None
            else:
                self.isConst = False
                self.var = var
                self.constant = None

            if concept == None:
                self.concept = None
            else:
                self.concept = concept.encode('utf-8').strip()

    def __eq__(self, other):
        return str(self) == str(other)

    def __ne__(self, other):
        return not(self == other)

    def __hash__(self):
        return hash((self.__repr__()))

    def __repr__(self):
        if self.isRoot:
            return '<%s %s>' % (
            self.__class__.__name__, "TOP")    
        else:
            if self.isConst:
                return '<%s %s %s %s>' % (
                    self.__class__.__name__, "const", self.constant, self.concept)
            else:
                return '<%s %s %s>' % (
                    self.__class__.__name__, self.var, self.concept)
                
    def variable(self):
        if self.isRoot:
            return "TOP"
        elif self.isConst:
            return self.constant
        else:
            return self.var

    def amrconcept(self):
        if self.isRoot:
            return ""
        elif self.isConst:
            return ""
        else:
            return self.concept class Rules:

    def __init__(self, labels):
        self.args_rules = []
        self.args_rules.append({})
        self.args_rules.append({})
        self.args_rules.append({})
        self.args_rules.append({})
        self.args_rules.append({})
        self.args_rules.append({})
        self.labels = labels

        self.rels_rules = {}

        for line in open("resources/args_rules.txt"):
            self._add(line, "args")

        for line in open("resources/rels_rules.txt"):
            self._add(line, "rels")

    def _add(self, line, type):        
        if type == "args":
            fields = line.split(",")
            for i in range(1,len(fields)):
                self.args_rules[i - 1][fields[0].strip()] = int(fields[i].strip())
        else:
            rel,constr = line.split("\t")
            self.rels_rules[rel] = {}
            for c in constr.split(","):
                fields = c.split("=")
                if len(fields) < 2:
                    self.rels_rules[rel][c.strip()] = "true"
                else:
                    self.rels_rules[rel][fields[0].strip()] = re.compile(fields[1].strip())

    def check(self, node1, node2):
        assert(isinstance(node1, Node) and isinstance(node2, Node))
        if node1.isConst:
            return [0]*len(self.labels)
        if node2.isRoot:
            return [0]*len(self.labels)

        legals = [-1]*len(self.labels)
        for i, rel in enumerate(self.labels):
            if rel.startswith(":ARG"):
                if rel.endswith("-of"):
                    if re.match(r'.*-[0-9][0-9]*', node2.concept) is None:
                        legals[i] = 0
                    else:
                        ind = int(rel[-4])
                        if len(self.args_rules) > ind and node2.concept in self.args_rules[ind]:
                            legals[i] = self.args_rules[ind][node2.concept]
                        else:
                            legals[i] = 1
                else:
                    if node1.concept is not None and re.match(".*-[0-9][0-9]*", node1.concept) is None:
                        legals[i] = 0
                    else:
                        ind = int(rel[-1])
                        if len(self.args_rules) > ind and node1.concept in self.args_rules[ind]:
                            legals[i] = self.args_rules[ind][node1.concept]
                        else:
                            legals[i] = 1
            else:
                legal = True
                if rel in self.rels_rules:
                    rules = self.rels_rules[rel]
                    if "a" in rules and node1.isRoot == False and rules["a"].match(node1.var) == None:
                        legal = False
                    if "b" in rules and rules["b"].match(node2.concept) == None:
                        legal = False
                    if "a_isroot" in rules and rules["a_isroot"] == "true" and node1.isRoot == False:
                        legal = False
                    if "b_isconst" in rules and rules["b_isconst"] == "true" and node2.isConst == False:
                        legal = False
                    if "b_const" in rules and node2.isConst == True and rules["b_const"].match(node2.constant) == None:
                        legal = False
                    if legal:
                        if "excl" in rules and rules["excl"] == "true":
                            legals = [0]*len(self.labels)
                            legals[i] = 1
                            break
                        else:
                            legals[i] = 1
                    else:
                        legals[i] = 0
                else:
                    legals[i] = 1
        assert(-1 not in legals)
        return legals class Dependencies:
    def __init__(self, deps):
        self.children = defaultdict(set)
        self.parents = defaultdict(set)

        for (n1, label, n2) in deps:
            assert (isinstance(n1, BufToken) and isinstance(n2, BufToken) and type(label) == str)
            self.add(n1, n2, label)

    def add(self, node1, node2, label):
        assert (isinstance(node1, BufToken) and isinstance(node2, BufToken) and type(label) == str)
        self.children[node1].add((node2,label))
        self.parents[node2].add((node1,label))

    def isArc(self, node1, node2, seen):
        assert (isinstance(node1, BufToken) and isinstance(node2, BufToken))
        for (node, label) in self.children[node1]:
            if node == node2:
                return label
        return "<NULLDEP>"

    def nArcs(self, node1, node2):
        assert ((isinstance(node1, BufToken) or node1 is None) and (isinstance(node2, BufToken) or node2 is None))

        counter = 0
        for (node, label) in self.children[node1]:
            if node == node2:
                counter += 1
        return counter

    def areSiblings(self, node1, node2):
        assert ((isinstance(node1, BufToken) or node1 is None) and (isinstance(node2, BufToken) or node2 is None))
        if len(self.parents[node1]) == 0 or len(self.parents[node2]) == 0:
            return 0

        for item1 in self.parents[node1]:
            if item1[1] == "ROOT":
                continue 
            p1 = item1[0]
            for item2 in self.parents[node2]:
                if item2[1] == "ROOT":
                    continue 
                p2 = item2[0]
                if p1 == p2:
                    return 1
        return 0

    def n_outgoing(self, node, isroot, candidates):
        assert (isinstance(node, BufToken) or node is None)
        return len([(c,l) for (c,l) in self.children[node] if c in candidates])


    def n_incoming(self, node, isroot, candidates):
        assert (isinstance(node, BufToken) or node is None)
        if isroot:
            return 0
        return len([(c,l) for (c,l) in self.parents[node] if c in candidates])

    def _postorder(self, root, visited, N):
        lst = []
        visited.append(root)
        lst.append(root)
        for i in range(0, N):
            for (child,label) in self.children[root]:
                if child != root and child not in visited:
                    diff = abs(child.index - root.index)
                    if diff == i:
                        lst.extend(self._postorder(child, visited, N))
        return lst
        
    def postorder(self, N):
        roots = []

        for node in self.children:
            for (child, label) in self.children[node]:
                if label == "ROOT":
                    roots.append(node)
        order = []
        for root in roots:
            order.extend(self._postorder(root, [], N))
        if order == []:
            return None
        return order
        
    def minundirpath(self, node1, node2):
        if node1 is None:
            node1 = node2
        if node2 is None:
            node2 = node1

        assert(node1 in self.children or node1 in self.parents)
        assert(node2 in self.children or node2 in self.parents)

        queue = [node1]
        seen = []
        bp = {}
        while len(queue) > 0:
            item = queue.pop(0)
            seen.append(item)
            if item == node2:
                ret = []
                while item in bp:
                    ret.append(bp[item][1])
                    item = bp[item][0]
                if ret == []:
                    ret = ["ROOT"]
                else:
                    ret.reverse()
                return ret
            for (child, label) in self.children[item]:
                if child not in seen:
                    queue.append(child)
                    bp[child] = (item,label)
            for (parent, label) in self.parents[item]:
                if parent not in seen:
                    queue.append(parent)
                    bp[parent] = (item,label)
        return None class Subgraph:

    def __init__(self, nodes, relations):
        self.nodes = nodes
        self.relations = relations

    def get(self, token = None, variables = None):
        if variables == None:
            return self

        tr = {}
        nodes = copy.deepcopy(self.nodes)
        relations = copy.deepcopy(self.relations)
        vs = []
        for (n1,n2,_) in relations:
            vs.append(n1)
            vs.append(n2)
        for n in nodes:
            vs.append(n)
        for n in vs:
            if n.var is not None and n.var not in tr:
                v = variables.nextVar()
                tr[n.var] = v

        seen = []
        for (n1,n2,_) in relations:
            n1.token = token
            n2.token = token
            if n1.var is not None and n1 not in seen:
                n1.var = tr[n1.var]
                seen.append(n1)
            if n2.var is not None and n2 not in seen:
                n2.var = tr[n2.var]
                seen.append(n2)
        for n in nodes:
            n.token = token
            if n.var is not None and n not in seen:
                n.var = tr[n.var]
                seen.append(n)
        return Subgraph(nodes, relations)


    def get_str(self, token = None, variables = None):
        if variables == None:
            return ([], [])

        tr = {}
        nodes = copy.deepcopy(self.nodes)
        relations = copy.deepcopy(self.relations)
        vs = []
        for (n1,n2,_) in relations:
            vs.append(n1)
            vs.append(n2)
        for n in nodes:
            vs.append(n)
        for n in vs:
            if n.var is not None and n.var not in tr:
                v = variables.nextVar()
                tr[n.var] = v

        seen = []
        for (n1,n2,_) in relations:
            n1.token = token
            n2.token = token
            if n1.var is not None and n1 not in seen:
                n1.var = tr[n1.var]
                seen.append(n1)
            if n2.var is not None and n2 not in seen:
                n2.var = tr[n2.var]
                seen.append(n2)
        for n in nodes:
            n.token = token
            if n.var is not None and n not in seen:
                n.var = tr[n.var]
                seen.append(n)
        nodes = [str(n) for n in nodes]
        relations = [str(r) for r in relations]
        return (sorted(nodes), sorted(relations))

    def __eq__(self, other):
        self2 = self.get(None,Variables())
        other2 = other.get(None,Variables())

        return self2.nodes == other2.nodes and self2.relations == other2.relations

    def __ne__(self, other):
        return self.__eq__(other) == False

    def __hash__(self):    
        self2 = self.get(None,Variables())
        return hash((tuple(self2.nodes), tuple(self2.relations)))

    def __repr__(self):
        return '<%s %s %s>' % (
            self.__class__.__name__, self.nodes, self.relations) class Resources:

    @staticmethod
    def store_table(model_dir):

        table = {}
        freq = {}
        print "Storing tables.."
        print "Number of tokens:", len(Resources.phrasetable.keys())
        for i, token in enumerate(Resources.phrasetable):
            if i % 100 == 0:
                print "Token:", i
            sg = max(Resources.phrasetable[token].iteritems(), key=operator.itemgetter(1))[0]
            table[token] = sg

        pickle.dump(table, open(model_dir + "/phrasetable.p", "wb"))

    @staticmethod
    def init_table(model_dir, empty = True):
        Resources.phrasetable = defaultdict(lambda : defaultdict(int))

        if empty == False:
            Resources.phrasetable = pickle.load(open(model_dir + "/phrasetable.p", "rb"))
            Resources.organizations = defaultdict(list)
            for line in open(model_dir + "/organizations.txt"):
                fields = line.strip().split()
                if len(fields) > 1:
                    Resources.organizations[fields[0]] = fields[1]
        else:
            Resources.organizations = None
            Resources.seen_org = []
            Resources.forg = open(model_dir + "/organizations.txt","w")

        # Resources.verbalization_list = {}
        # for line in open("resources/verbalization-list-v1.06.txt"):
        #    line = line.strip().split()
        #    if line[0] == "VERBALIZE":
        #        var = Variables()
        #        nodes = []
        #        ntop = Node(None, var.nextVar(), line[3], False)
        #        nodes.append(ntop)
        #        relations = []
        #        fields = line[4:]
        #        for i in range(0,len(fields),2):
        #            if fields[i + 1] == "-":
        #                n = Node(None, '-', "", True)
        #            else:
        #                n = Node(None, var.nextVar(), fields[i + 1], False)
        #            nodes.append(n)
        #            relations.append((ntop,n,fields[i]))
        #        Resources.verbalization_list[line[1]] = Subgraph(nodes, relations)
        # for line in open("resources/have-org-role-91-roles-v1.06.txt"):
        #    line = line.strip().split()
        #    if line[0] == "USE-HAVE-ORG-ROLE-91-ARG2":
        #        var = Variables()
        #        ntop = Node(None, var.nextVar(), "have-org-role-91", False)
        #        node = Node(None, var.nextVar(), line[1], False)
        #        Resources.verbalization_list[line[1]] = Subgraph([ntop, node], [(ntop, node, ":ARG2")])

        # for line in open("resources/have-rel-role-91-roles-v1.06.txt"):
        #    if "#" in line:
        #        line = line.split("#")[0]
        #    line = line.strip().split()
        #    if len(line) > 0 and line[0] == "USE-HAVE-REL-ROLE-91-ARG2":
        #        var = Variables()
        #        if len(line) >= 3 and line[2] == ":standard":
        #            ntop = Node(None, var.nextVar(), "have-rel-role-91", False)
        #            node = Node(None, var.nextVar(), line[3], False)
        #            Resources.verbalization_list[line[1]] = Subgraph([ntop, node], [(ntop, node, ":ARG2")])
        #            Resources.verbalization_list[line[3]] = Subgraph([ntop, node], [(ntop, node, ":ARG2")])
        #        else:
        #            ntop = Node(None, var.nextVar(), "have-rel-role-91", False)
        #            node = Node(None, var.nextVar(), line[1], False)
        #            Resources.verbalization_list[line[1]] = Subgraph([ntop, node], [(ntop, node, ":ARG2")]) class BufToken:

    def __init__(self, word, lemma, ne, pos, index, nodes):
        self.word = word
        self.lemma = lemma
        self.ne = ne
        self.pos = pos
        self.index = index
        self.nodes = nodes

    def __eq__(self, other):
        return other is not None and self.word == other.word and self.lemma == other.lemma and self.pos == other.pos and self.ne == other.ne and self.index == other.index 

    def __repr__(self):
        return '<%s %s %s %s %s %s %s>' % (
            self.__class__.__name__, str(self.word), str(self.lemma), self.ne, self.pos, self.index, self.nodes)

    def __hash__(self):
        return hash((self.word, self.lemma, self.ne, self.pos, self.index)) class Variables():
    def __init__(self):
        self.nvars = 0
        self.existingvars = []

    def nextVar(self):
        while True:
            self.nvars += 1
            v = "v" + str(self.nvars)
            if v not in self.existingvars:
                break
        self.existingvars.append(v)
        return v class Relations:

    def __init__(self, initial = []):
        self.children = defaultdict(list)
        self.parents = defaultdict(list)
        self.list = []

        for (n1, label, n2) in initial:
            self.add(n1, n2, label)

    def __eq__(self, other):
        return self.children == other.children and self.parents == other.parents

    def __repr__(self):
        return str(self.list)

    def add(self, node1, node2, label):
        if (node1,label,node2) not in self.list:
            self.list.append((node1,label,node2))

        if (node2,label) not in self.children[node1]:
            self.children[node1].append((node2,label))
        if (node1,label) not in self.parents[node2]:
            self.parents[node2].append((node1,label))

    def dfs(self, root, visited):
        lst = []
        for (child,label) in self.children[root]:
            lst.append((root.variable(),root.amrconcept(),label,child.variable(),child.amrconcept()))
            if child not in visited:
                visited.append(child)
                lst.extend(self.dfs(child,visited))
        return lst

    def _isConnToRoot(self, node, visited):
        if node in visited:
            return False
        visited.append(node)

        if node.isRoot:
            return True
        for (father,_) in self.parents[node]:
            if self._isConnToRoot(father, visited):
                return True
        return False


    def est_depth(self, node, other = None):
        n = 0
        seen = []
        while node in self.parents and len(self.parents[node]) > 0:
            for i in self.parents[node]:
                node, _ = i
                if node in seen:
                    return n
                seen.append(node)
                break
            if node != other:
                n += 1
        return n

    def est_depth_down(self, node, other = None):
        n = 0
        seen = []
        while node in self.children and len(self.children[node]) > 0:
            for i in self.children[node]:
                node, _ = i
                if node in seen:
                    return n
                seen.append(node)
                break
            if node != other:
                n += 1
        return n

    def triples(self):
        root = Node(True)
        for node in copy.deepcopy(self.children):
            if node is None:
                continue
            if self._isConnToRoot(node, []) == False and len(self.children[node]) > 0:
                self.add(Node(True), node, ":top")
        lst = self.dfs(root,[])
        if len(self.children[root]) > 1:
            counter = 1
            lst2 = []
            lst2.append(("TOP","",":top","mu","multi-sentence"))
            for v1,c1,l,v2,c2 in lst:
                if v1 == "TOP":
                    v1 = "mu"
                    c1 = "multi-sentence"
                    l = ":snt" + str(counter)
                    counter += 1
                lst2.append((v1,c1,l,v2,c2))
            return lst2
        return lst

    def _leftmost(self, node, direction, other = None):
        if node is not None:
            if direction == "child":
                lst = self.children[node]
            else:
                lst = self.parents[node]
            if len(lst) > 0:
                candidate = None
                minindex = float("inf")
                for item in lst:
                    if item[0].isRoot:
                        if item[0] != other:
                            return item
                    elif item[0].token.index < minindex and item[0] != other:
                        candidate = item
                        minindex = item[0].token.index
                return candidate
        return None

    def _rightmost(self, node, direction, other = None):
        if node is not None:
            if direction == "child":
                lst = self.children[node]
            else:
                lst = self.parents[node]
            if len(lst) > 0:
                candidate = None
                maxindex = -1
                for item in lst:
                    if item[0].isRoot and candidate is None and item[0] != other:
                        candidate = item
                        maxindex = -1
                    elif item[0].isRoot == False and item[0].token.index > maxindex and item[0] != other:
                        candidate = item
                        maxindex = item[0].token.index
                return candidate
        return None

    def leftmost_child(self, node, other = None):
        child = self._leftmost(node, "child", other)
        if child == None:
            return "<NULL>"
        if child[0].isConst:
            return child[0].constant
        elif child[0].isRoot:
            return "<TOP>"
        else:
            return child[0].concept

    def leftmost_grandchild(self, node, other = None):
        child = self._leftmost(node, "child", other)
        if child is not None:
            grandchild = self._leftmost(child[0], "child", other)
            if grandchild is not None:
                if grandchild[0].isConst:
                    return grandchild[0].constant
                elif grandchild[0].isRoot:
                    return "<TOP>"
                else:
                    return grandchild[0].concept
        return "<NULL>"

    def rightmost_child(self, node, other = None):
        child = self._rightmost(node, "child", other)
        if child == None:
            return "<NULL>"
        if child[0].isConst:
            return child[0].constant
        elif child[0].isRoot:
            return "<TOP>"
        else:
            return child[0].concept

    def rightmost_grandchild(self, node, other = None):
        child = self._rightmost(node, "child", other)
        if child is not None:
            grandchild = self._rightmost(child[0], "child", other)
            if grandchild is not None:
                if grandchild[0].isConst:
                    return grandchild[0].constant
                elif grandchild[0].isRoot:
                    return "<TOP>"
                else:
                    return grandchild[0].concept
        return "<NULL>"

    def leftmost_parent(self, node, other = None):
        parent = self._leftmost(node, "parent", other)
        if parent == None:
            return "<NULL>"
        if parent[0].isConst:
            return parent[0].constant
        elif parent[0].isRoot:
            return "<TOP>"
        else:
            return parent[0].concept

    def rightmost_parent(self, node, other = None):
        parent = self._rightmost(node, "parent", other)
        if parent == None:
            return "<NULL>"
        if parent[0].isConst:
            return parent[0].constant
        elif parent[0].isRoot:
            return "<TOP>"
        else:
            return parent[0].concept

    def isBasterd(self, node):
        return len(self.parents[node]) == 0

    def children_nodes(self, node):
        return [c[0] for c in self.children[node]]

    def isRel(self, node1, node2, boolean = False):
        assert ((isinstance(node1, Node) or node1 is None) and (isinstance(node2, Node) or node2 is None))

        if node1 is None:
            return None
        if node2 is None:
            return None

        for (node, label) in self.children[node1]:
            if node == node2:
                return label
        return None
import tostring
import hooks
import embs
import copy
import re
import numpy as np
from buf import Buffer
from stack import Stack
from node import Node
from rules import Rules
from dependencies import Dependencies 
from subgraph import Subgraph
from resources import Resources
from buftoken import BufToken
from variables import Variables
from relations import Relations
#!/usr/bin/env python
#coding=utf-8

'''
Definition of State class. It stores all info related to the state of the transition systems:
buffer, stack, and previous (state,action) pairs. It provides methods to get desired feature 
vectors for those components, for training. It updates when an action is applied. 
It also allows the use of specific "hooks" to manually deal with named entities.
The class also provides methods, used during parsing, to decide which actions are allowed
given the current state and which labels can be used to label a given relation (larc/rarc).

@author: Marco Damonte (m.damonte@sms.ed.ac.uk)
@since: 03-10-16
'''

STACKWIN = 2
BUFWIN = 4

class State:
    def __init__(self, embs, relations, tokens, dependencies, alignments, oracle, hooks, variables, stage, rules):
        self.semicol_gen_and = False
        self.hooks = hooks
        self.variables = variables
        self.buffer = Buffer(embs, tokens, alignments)
        self.embs = embs
        self.stage = stage
        self.dependencies = Dependencies([(self.buffer.tokens[i1],label,self.buffer.tokens[i2]) for (i1,label,i2) in dependencies])
        self.stack = Stack(embs)
        self.oracle = oracle
        self.rules = rules
        if relations is not None:
            self.gold = Relations(copy.deepcopy(relations))
        else:
            self.gold = None
        self.sentence = " ".join([t.word for t in tokens])
        self.counter = 0

    def isTerminal(self):
        return self.buffer.isEmpty() and self.stack.isEmpty()

    def __repr__(self):
        return '<%s %s %s>' % (self.__class__.__name__, self.stack, self.buffer)

    def nextSubgraph(self):
        token = self.buffer.peek()
        word_pos = token.word + "_" + token.pos
        lemma_pos = token.lemma + "_" + token.pos

        #TRICK FOR SEMICOLONS
        if token.word == ";":
            if self.semicol_gen_and:
                return Subgraph([],[])
            else:
                self.semicol_gen_and = True
                return Subgraph([Node(token, self.variables.nextVar(), "and", False)],[])

        #HOOKS
        if self.hooks and token.ne != "O" and (token.ne == "ORGANIZATION" and word_pos in Resources.phrasetable) == False:
            ret = hooks.run(token, token.word, token.ne, self.variables)

            if ret != False:
                return Subgraph(ret[0],ret[1])

        #ISI LISTS
        # if token.word in Resources.verbalization_list:
        #    return Resources.verbalization_list[token.word].get(token, self.variables)
        # if token.lemma in Resources.verbalization_list:
        #    return Resources.verbalization_list[token.lemma].get(token, self.variables)

        #PHRASETABLE
        if word_pos in Resources.phrasetable:
            return Resources.phrasetable[word_pos].get(token, self.variables)
        if lemma_pos in Resources.phrasetable:
            return Resources.phrasetable[lemma_pos].get(token, self.variables)

        #UNKNOWN TOKENS (variables or constants)
        if token.ne == "O": #var
            v = self.variables.nextVar()
            label = ""
            if token.pos.startswith("V"):
                label = token.lemma.replace('"','')
                if label == "":
                    label = "emptyconcept"
                label += "-01"
            if label == "":
                label = token.lemma
            if label == "":
                label = token.word
            if label.count('"') % 2 != 0:
                label = "".join(label.rsplit('"', 1))
            if label.count("'") % 2 != 0:
                label = "".join(label.rsplit("'", 1))
            label = label.replace('""','"')
            if "_" in label or "\\" in label or ":" in label or "/" in label or "(" in label or ")" in label:
                label = "genericconcept"
            if label == "":
                label = "emptyconcept"
            if label.startswith("@"):
                label = label[1:]
            label = label.lower()

            return Subgraph([Node(token, v, label, False)],[])