import sys, math, re, os, struct, time
from  xml.parsers.expat import ParserCreate

import mesh

class daeModel(mesh.mesh):
	def __init__(self):
		super(daeModel, self).__init__()

	def load(self, filename):
		r = ParserCreate()
		r.StartElementHandler = self._StartElementHandler
		r.EndElementHandler = self._EndElementHandler
		r.CharacterDataHandler = self._CharacterDataHandler

		self._base = {}
		self._cur = self._base
		self._idMap = {}
		self._geometryList = []
		r.ParseFile(open(filename, "r"))
		
		self.vertexCount = 0
		for instance_visual_scene in self._base['collada'][0]['scene'][0]['instance_visual_scene']:
			for node in self._idMap[instance_visual_scene['_url']]['node']:
				self._ProcessNode1(node)
		self._prepareVertexCount(self.vertexCount)
		for instance_visual_scene in self._base['collada'][0]['scene'][0]['instance_visual_scene']:
			for node in self._idMap[instance_visual_scene['_url']]['node']:
				self._ProcessNode2(node)
		
		self._base = None
		self._cur = None
		self._idMap = None
		
		self._postProcessAfterLoad()
		return self
	
	def _ProcessNode1(self, node):
		if 'node' in node:
			for n in node['node']:
				self._ProcessNode1(n)
		if 'instance_geometry' in node:
			for instance_geometry in node['instance_geometry']:
				mesh = self._idMap[instance_geometry['_url']]['mesh'][0]
				if 'triangles' in mesh:
					for triangles in mesh['triangles']:
						self.vertexCount += int(triangles['_count']) * 3
				elif 'lines' in mesh:
					pass #Ignore lines
				else:
					print mesh.keys()
		if 'instance_node' in node:
			for instance_node in node['instance_node']:
				self._ProcessNode1(self._idMap[instance_node['_url']])

	def _ProcessNode2(self, node, matrix = None):
		if 'matrix' in node:
			oldMatrix = matrix
			matrix = map(float, node['matrix'][0]['__data'].split())
			if oldMatrix != None:
				newMatrix = [0]*16
				newMatrix[0] = oldMatrix[0] * matrix[0] + oldMatrix[1] * matrix[4] + oldMatrix[2] * matrix[8] + oldMatrix[3] * matrix[12]
				newMatrix[1] = oldMatrix[0] * matrix[1] + oldMatrix[1] * matrix[5] + oldMatrix[2] * matrix[9] + oldMatrix[3] * matrix[13]
				newMatrix[2] = oldMatrix[0] * matrix[2] + oldMatrix[1] * matrix[6] + oldMatrix[2] * matrix[10] + oldMatrix[3] * matrix[14]
				newMatrix[3] = oldMatrix[0] * matrix[3] + oldMatrix[1] * matrix[7] + oldMatrix[2] * matrix[11] + oldMatrix[3] * matrix[15]
				newMatrix[4] = oldMatrix[4] * matrix[0] + oldMatrix[5] * matrix[4] + oldMatrix[6] * matrix[8] + oldMatrix[7] * matrix[12]
				newMatrix[5] = oldMatrix[4] * matrix[1] + oldMatrix[5] * matrix[5] + oldMatrix[6] * matrix[9] + oldMatrix[7] * matrix[13]
				newMatrix[6] = oldMatrix[4] * matrix[2] + oldMatrix[5] * matrix[6] + oldMatrix[6] * matrix[10] + oldMatrix[7] * matrix[14]
				newMatrix[7] = oldMatrix[4] * matrix[3] + oldMatrix[5] * matrix[7] + oldMatrix[6] * matrix[11] + oldMatrix[7] * matrix[15]
				newMatrix[8] = oldMatrix[8] * matrix[0] + oldMatrix[9] * matrix[4] + oldMatrix[10] * matrix[8] + oldMatrix[11] * matrix[12]
				newMatrix[9] = oldMatrix[8] * matrix[1] + oldMatrix[9] * matrix[5] + oldMatrix[10] * matrix[9] + oldMatrix[11] * matrix[13]
				newMatrix[10] = oldMatrix[8] * matrix[2] + oldMatrix[9] * matrix[6] + oldMatrix[10] * matrix[10] + oldMatrix[11] * matrix[14]
				newMatrix[11] = oldMatrix[8] * matrix[3] + oldMatrix[9] * matrix[7] + oldMatrix[10] * matrix[11] + oldMatrix[11] * matrix[15]
				newMatrix[12] = oldMatrix[12] * matrix[0] + oldMatrix[13] * matrix[4] + oldMatrix[14] * matrix[8] + oldMatrix[15] * matrix[12]
				newMatrix[13] = oldMatrix[12] * matrix[1] + oldMatrix[13] * matrix[5] + oldMatrix[14] * matrix[9] + oldMatrix[15] * matrix[13]
				newMatrix[14] = oldMatrix[12] * matrix[2] + oldMatrix[13] * matrix[6] + oldMatrix[14] * matrix[10] + oldMatrix[15] * matrix[14]
				newMatrix[15] = oldMatrix[12] * matrix[3] + oldMatrix[13] * matrix[7] + oldMatrix[14] * matrix[11] + oldMatrix[15] * matrix[15]
				matrix = newMatrix
		if 'node' in node:
			for n in node['node']:
				self._ProcessNode2(n, matrix)
		if 'instance_geometry' in node:
			for instance_geometry in node['instance_geometry']:
				mesh = self._idMap[instance_geometry['_url']]['mesh'][0]
				
				if 'triangles' in mesh:
					for triangles in mesh['triangles']:
						for input in triangles['input']:
							if input['_semantic'] == 'VERTEX':
								vertices = self._idMap[input['_source']]
						for input in vertices['input']:
							if input['_semantic'] == 'POSITION':
								vertices = self._idMap[input['_source']]
						indexList = map(int, triangles['p'][0]['__data'].split())
						positionList = map(float, vertices['float_array'][0]['__data'].split())

						vertexCount = int(triangles['_count']) * 3
						stepSize = len(indexList) / vertexCount
						for i in xrange(0, vertexCount):
							idx = indexList[i * stepSize]
							if matrix != None:
								x = positionList[idx*3]
								y = positionList[idx*3+1]
								z = positionList[idx*3+2]
								self.addVertex(x * matrix[0] + y * matrix[1] + z * matrix[2] + matrix[3], x * matrix[4] + y * matrix[5] + z * matrix[6] + matrix[7], x * matrix[8] + y * matrix[9] + z * matrix[10] + matrix[11])
							else:
								self.addVertex(positionList[idx*3], positionList[idx*3+1], positionList[idx*3+2])
		if 'instance_node' in node:
			for instance_node in node['instance_node']:
				self._ProcessNode2(self._idMap[instance_node['_url']], matrix)
	
	def _StartElementHandler(self, name, attributes):
		name = name.lower()
		if not name in self._cur:
			self._cur[name] = []
		new = {'__name': name, '__parent': self._cur}
		self._cur[name].append(new)
		self._cur = new
		for k in attributes.keys():
			self._cur['_' + k] = attributes[k]
		
		if 'id' in attributes:
			self._idMap['#' + attributes['id']] = self._cur
		
	def _EndElementHandler(self, name):
		self._cur = self._cur['__parent']

	def _CharacterDataHandler(self, data):
		if len(data.strip()) < 1:
			return
		if '__data' in self._cur:
			self._cur['__data'] += data
		else:
			self._cur['__data'] = data
	
	def _GetWithKey(self, item, basename, key, value):
		input = basename
		while input in item:
			if item[basename]['_'+key] == value:
				return self._idMap[item[input]['_source']]
			basename += "!"
