import sys,os
from tree import *

sys.path.insert(0,os.pardir)
from constant import *

HASCYCLE=1
NOCYCLE=0

__verbose__=0

class Data:
	def __init__(self, dict, xpos, ypos):
		self.xpos=xpos
		self.ypos=ypos
		self.parents=[]            # the cell data depend on me
		self.children=[]           # the cell data on which I depend.
		self.tree=None
		self.val=None
		self.data_dict=dict

	def getXPosition(self):
		return self.xpos

	def getYPosition(self):
		return self.ypos
		
	def getValue(self):
		return self.val

	def setTree(self, tree):
		changedcells=[]
		if tree==None:
			self.tree=None
			self.val=None
			self.children=[]
			self.notify(changedcells)
			return changedcells
			
		self.cyclestr=[]
		dep=self.checkDependence((self.xpos,self.ypos),self.cyclestr, tree)
		if dep==HASCYCLE:
			if __verbose__:
				for s in self.cyclestr:
					print s
				print 'cyclic dependence detected.'
			return (CYCLICDEPENDENCEERROR, self.cyclestr)
		else:
			#
			# remove this cell data from it's current children's parent list, since
			# new relationship is defined by a new tree.
			#
			for child in self.children:
				child.removeParent(self)

			self.tree=tree
			#
			# update the children of this cell data
			#
			self.children=[] #remove all the previous children.
			iterator=tree.createIterator()
			while not iterator.isDone():
				node=iterator.next()
				if isinstance(node, CellNode):
					self.children.append(self.data_dict[(node.row,node.col)])
			#print `self.children`

			#
			# Update add this cell node to its new children's parent list
			#
			for child in self.children:
				child.addParent(self)

			#
			# Calculate the new value for this cell node if possible, which means all its
			# children are defined.
			#
			childrendefined=1
			for child in self.children:
				if child.getValue==None:
					childrendefined=0
					break
		      		
			#
			# this cell node, its parents, and its parents' parents will change their value
			# since they all directly or indirectly depend on this cell node.
			#
			#
			self.notify(changedcells)
			if __verbose__:
				for d in changedcells:
					print `d`
			return changedcells
	
	def notify(self, changedcells):
		#
		# Calculate the new value for this cell node if possible, which means all its
		# children are defined.
		#
		childrendefined=1
		for child in self.children:
			if child.getValue()==None:
				childrendefined=0
				break

		if childrendefined and (not self.tree==None):
				self.val=self.tree.root.interpret(self.data_dict)
		else:
				self.val=None
	
		changedcells.append(self)

		if __verbose__:
			for p in self.parents:
				print `p`
		
		for parent in self.parents:
			parent.notify(changedcells)
		
	def checkDependence(self, cellposition, cyclestr, tree=None):
		if tree==None:
			tree=self.tree
		if tree==None:
			return NOCYCLE

		iterator=tree.createIterator()
		while not iterator.isDone():
			node=iterator.next()
			if isinstance(node, NumNode):
				pass
			elif isinstance(node, CellNode):
				if (node.row, node.col)==cellposition:
					cyclestr.insert(0,'$%d$%d-->$%d$%d'%(self.xpos, self.ypos,node.row,node.col)+\
							'\t'+'$%d$%d'%(self.xpos,self.ypos)+'='+`tree`)
					return HASCYCLE
				else:
					if self.data_dict[(node.row, node.col)].checkDependence(cellposition, cyclestr):
						cyclestr.insert(0, '$%d$%d-->$%d$%d' %(self.xpos,self.ypos,node.row,node.col)+\
								'\t'+'$%d$%d'%(self.xpos,self.ypos)+'='+`tree`)
						return HASCYCLE
					else:
						pass
			else:
				pass  # it should raise an error.
		return NOCYCLE

	def getParents(self):
		return self.parents

	def getChildren(self):
		return self.children

	def addParent(self, parent):
		self.parents.append(parent)

	def removeParent(self, parent):
		self.parents.remove(parent)

	def addChildList(self, childlist):
		self.parent.children=childlist

	def __repr__(self):
		return '('+'('+`self.xpos`+','+`self.ypos`+')'+','+`self.val`+')'

		
	















