from . import skipWhitespace, ParserWarning from .property import Property, GAME_INFO class Node: def __init__(self): self.properties=dict() self.parent=None self.children=[] @staticmethod def fits(s,i): return i<len(s) and s[i]==";" @staticmethod def create(s,start): assert Node.fits(s,start) res=Node() i=skipWhitespace(s,start+1) while Property.fits(s,i): i,x=Property.create(s,i) if x.name in res.properties: # !! raise or log or ignore raise ParserWarning('duplicate "{0}" property in a node. second value ignored'.format(x.name),s,i) else: res.properties[x.name]=x i=skipWhitespace(s,i) return (i,res) def isGINode(self): return any(prop.type==GAME_INFO for prop in self.properties.values()) def setProperty(self,name,value): self.properties[name]=value # zkontrolovat typ value def setParent(self,node): self.parent=node def setChildren(self,children): self.children=children def addChild(self,node): if node in self.children: return node self.children.append(node) return node def removeChild(self,node): if node not in self.children: return None del self.children[self.children.index(node)] return node def removeChildAt(self,i): if -len(self.children)<i<len(self.children): res=self.children[i] del self.children[i] return res return None ## Create a copy of the Node, with deep copied propeties and shallow copied parent and children. def copy(self): res=Node() res.properties={k: v.copy() for (k,v) in self.properties.items()} res.parent=self.parent res.setChildren(self.children[:]) return res def getProp(self,name): if name in self.properties: return self.properties[name].value else: return None ## Returns textual representation of the Node itself, but disregards its children. def __str__(self): return ";" + "".join(str(p) for p in self.properties.values()) def export(self): # there is a beatiful recursive solution, which this stack is too narrow to contain stack=[(self,1,1)] output=[] while len(stack)>0: node,left,right=stack.pop() if left>0: output.append("("*left) output.append(str(node)) childCount=len(node.children) if childCount==0: # a leaf output.append(")"*right) elif childCount==1: # a line stack.append((node.children[0],0,right)) else: # a branching node # first child pops first, last child closes parent's parentheses children=zip(node.children,[1]*childCount,[1]*(childCount-1)+[1+right]) stack.extend(reversed(children)) return "".join(output)