import animation
import mesh
import matrixmath
import skeleton
 
#	enum Type { STATIC, DEFORMABLE };
 
(STATIC,DEFORMABLE) = range(2)
 
class Model(object):
 
	'''
	type: enum Type { STATIC, DEFORMABLE }
	'''
	def __init__(self, type, texture_loader = None):
		self.__meshCacher = mesh.MeshCacher()
		self.__animCacher = animation.AnimCacher()
 
		self.__anims = [] # vector<AnimPlayer *>
		self.__blends= [] # vector<BlendBase *>
		self.__masks = [] # vector<HiBoneMask *>
 
		self.meshes = []# vector<Mesh *>
		self.originSubtraction = False # bool
		self.fp = texture_loader
		self.type = -1 # enum Type
		self.arbitraryAnim = None
 
		self.renderPose = None
		self.worldBones = matrixmath.Matrix()
		self.worldBonesTEMP = matrixmath.Matrix()
 
 
 
	def AllocateRenderPose(self):
		if (self.arbitraryAnim == None):
			raise(Exception.new("ERROR: Load an animation before allocating render pose."))
			return
		else:
			self.renderPose = skeleton.Pose(self.arbitraryAnim.bones.numBones)
			self.worldBones = [matrixmath.Matrix() \
				for i in range(self.arbitraryAnim.bones.numBones)]
 
			self.worldBonesTEMP = [matrixmath.Matrix() \
				for i in range(self.arbitraryAnim.bones.numBones)]
 
	def AddMesh(self,filename): #returns unsigned int
		self.meshes.append( self.__meshCacher.GetMesh(filename, self.fp) )
		return len(self.meshes) - 1
 
	def SwapMesh(self,index, filename):
		self.meshes[index] = self.__meshCacher.GetMesh(filename, self.fp)
 
	def AddAnim(self, filename, startFrame = 0):
		handle = animation.AnimPlayer(self.__animCacher.GetAnim(filename), startFrame)
		if (self.arbitraryAnim == None):
			self.arbitraryAnim = handle.anim
		self.__blends.append(handle)
		self.__anims.append(handle)
		return handle
 
	def CreateBlend( self, source, dest ):
		if (self.arbitraryAnim == None):
			raise(Exception("ERROR: Load an animation before creating a blend."))
			return None
		handle = skeleton.Blend(self.arbitraryAnim.bones.numBones, source, dest )
		self.__blends.append(handle)
		return handle
 
	def CreateMask( self, selections ):
		if (self.arbitraryAnim == None):
			raise(Exception("ERROR: Load an animation before creating a mask."))
			return None
		handle = skeleton.HiBoneMask(self.arbitraryAnim.bones, selections)
		self.__masks.append(handle)
		return handle
 
	def GenerateRenderPoseMatrices(self):
		for i in range(self.arbitraryAnim.bones.numBones):
			if (i==0):
				self.worldBones[i].Set(self.renderPose.bones[i].q, \
						self.renderPose.bones[i].x,\
						self.renderPose.bones[i].y,\
						self.renderPose.bones[i].z)
			else:
				self.worldBones[i].Set(self.renderPose.bones[i].q, \
						self.arbitraryAnim.frames[0].pose.bones[i].x,\
						self.arbitraryAnim.frames[0].pose.bones[i].y,\
						self.arbitraryAnim.frames[0].pose.bones[i].z)
			parent = self.arbitraryAnim.bones.nodes[i].parent
			if (parent >= 0):
				self.worldBones[i] = self.worldBones[parent] * self.worldBones[i]
		# Careful!
		# A mesh can be bound to a subset of the skeleton. Therefore two
		# different meshes could be bound to the same bones, but at different
		# poses. This means we have to multiply the inverse when we know which
		# mesh we're dealing with. Which means when different meshes do have
		# the same bind pose (usually) we calculate the same value twice. If
		# there is only one mesh, this is all very unecessary.
 
		# OPTIMIZE: to solve this problem, when a mesh is loaded, a record
		# could be kept of common bind poses, and then, at this point, we
		# could store the common-bind-pose to render-pose transformations for
		# all bones. If a mesh's bind pose differs from an already loaded bind
		# pose, the bones that differ can cause an extra transform when the mesh
		# is drawn that account for the difference. 
 
#		for (i=0; i < arbitraryAnim->bones->numBones; i++)
#			worldbones[i] = worldbones[i] * meshes[0]->inverseBindPose[i];
	def Update(self, timestep):
		for it in self.__anims:
			it.Update(timestep * it.anim.fps)