import Blender
import sys
from Blender import NMesh
if sys.platform == "win32":
	import nt
else:
	import os

def normcube(vector):
	return vector[0]**2 + vector[1]**2 + vector[2]**2

def writeTarget(filename, path):
	"""
	DESCRIPTION
	Create target file from "Base" obj in 
	the scene, where only different vertices
	between the original Basemesh are stored
  	 
	SYNOPSIS
 	 writeTarget(filename, path)
		
	PARAMATERS
	 filename 	  : Full path of file to put vertex coordinates in
	 path : the path where search the vertex list of Basemesh
	 
	
	RETURN VALUES:
	Return 1 if success, 0 otherwise.	
	""" 


	#Open the file to retrieve the comments, if exist
	comments = []
	try:
		fileDescriptor = open(filename,'r')
		try:
			lineToRead = fileDescriptor.readline()
		except IOError, (errno,strerror):
			print "I/O error(%s): %s" % (errno, strerror)
		while lineToRead:
			if "#" in lineToRead:
				comments.append(lineToRead)
			lineToRead = fileDescriptor.readline()
		fileDescriptor.close()
	except:
		print "Error in opening %s" %filename

	#Reopen the file to read the points coordinates
	try:
		fileDescriptor = open(filename,'w+')	
	except:
		print "Error in opening %s" %filename
		return 0
	sourceVertexList = []

	#Open the base file to read the points init coordinates
	file = open(path+"base.mesh")
	vertexData = file.readline()
	while vertexData:
		vertexCoo = vertexData.split(',')
		sourceVertexList.append([float(vertexCoo[0]),\
							float(vertexCoo[1]),\
							float(vertexCoo[2])])
		vertexData = file.readline()
	file.close()
	
	#Write the comments, if retrivied
	for comment in comments:
		try:
			fileDescriptor.write(comment)
		except:
			pass

	#Write the points of target		
	epsilon = 0.001
	targetVertexList = None
	try:
		targetData = Blender.Object.Get("Base")
		targetVertexList = targetData.getData().verts
	except:
		print "No target object in scene"
		return
	for index in range(len(sourceVertexList)):
		sourceVertex = sourceVertexList[index]
		if targetVertexList:
			targetVertex = targetVertexList[index]
			if abs(normcube(sourceVertex)-normcube(targetVertex.co)) > epsilon:
				# write to the target file #
				try:
					fileDescriptor.write("%d,%f,%f,%f\n" % (index,targetVertex.co[0],targetVertex.co[1],targetVertex.co[2]))
				except IOError:
					print "Error in writing data in %s" %filename
		
	# for file flushing #
	fileDescriptor.close() 
	return 1

def writeOriginalMesh(path):
	"""
	DESCRIPTION
		Create the base.mesh, an indexed list of all vertex
		of baseMesh, in their original no modified position
		
		SYNOPSIS
	 	 writeOriginalMesh(path)
		
		PARAMATERS
		 path : the path where save the file
		 	
		RETURN VALUES:
	 	 Return 1 if success, 0 otherwise.	
	""" 
	

	# Get Raw mesh data #
	try:
		obj = Blender.Object.Get("Base")
		obj_mesh = obj.getData()
	except:
		print "Base obj not in scene"
		return

	sourceMeshVertexData = obj.getData()
	sourceVertexList = sourceMeshVertexData.verts
	try:
		fileDescriptor = open(path+"base.faces", "w")
	except:
		print "error to save mesh file"
	for index in range(len(sourceVertexList)):
		sourceVertex = sourceVertexList[index]
		try:
			fileDescriptor.write("%f,%f,%f\n" % (sourceVertex.co[0],\
												sourceVertex.co[1],\
												sourceVertex.co[2]))
		except IOError:
			print "Error in writing data in %s" %filename
	fileDescriptor.close() 
	return 1

def saveFaces(path):

	"""
	DESCRIPTION
	Save an ascii file:
	each line is a the index of the vertex in 
	a face.

	SYNOPSIS
	saveFaces(path)

	PARAMATERS
	filename: the name of file
	path: the path where save the files
	SourceObject: the object in Blender scene to save
            
	RETURN VALUES:
	None
    """
	
	try:
		obj = Blender.Object.Get("Base")
		obj_mesh = obj.getData()
	except:
		print "Base obj not in scene"
		return
	
	file = open(path+"base.faces", "w")
	for f in obj_mesh.faces:
		nfaces = len(f)
		if nfaces == 3:
			file.write(str(f.v[0].index)+",\
					"+str(f.v[1].index)+",\
					"+str(f.v[2].index)+"\n")
		if nfaces == 4:
			file.write(str(f.v[0].index)+",\
				"+str(f.v[1].index)+",\
				"+str(f.v[2].index)+",\
				"+str(f.v[3].index)+"\n")
	file.close()


def buildMesh(path):
	"""
	DESCRIPTION
	Build the mesh reading two ascii file:
	a vertex list and a faces list, named
	Basedata.vertex and Basedata.faces
	If the Base object already exist, the
	function only print a short message
 
	SYNOPSIS
	buildMesh(path)

	PARAMATERS
	filename : The list of faces
	filename2 : The list of vertex
            
	RETURN VALUES:
	Return an object named Base, using a mesh 
	named Base.
    """
	#test if an obj named Base or Base.***
	#is already in the scene.
	allObjs = Blender.Object.Get()
	obAlreadyInScene = 0
	for ob in allObjs:
		if ob.name[:4] == "Base":
			obAlreadyInScene = 1
	if obAlreadyInScene == 1:
		print "Base object already in scene"
	else:
		newBaseMesh = NMesh.GetRaw()
		file = open(path+"base.mesh")
		vertexData = file.readline()
		while vertexData:
			vertexCoo = vertexData.split(',')
			vx,vy,vz=float(vertexCoo[0]),\
					float(vertexCoo[1]),\
					float(vertexCoo[2])
			vertex=NMesh.Vert(vx,vy,vz)
			newBaseMesh.verts.append(vertex)
			vertexData = file.readline()
		file.close()
		file = open(path+"base.faces")
		faceData = file.readline()
		while faceData:
			vertexIndex = faceData.split(',')
			newFace=NMesh.Face()
			for i in vertexIndex:
				index=int(i)
				newFace.v.append(newBaseMesh.verts[index])
				#newFace.smooth=1										# added
			newBaseMesh.faces.append(newFace)
			faceData = file.readline()
		file.close()
		newBaseObj=NMesh.PutRaw(newBaseMesh)
		newBaseObj.setName("Base")
		#newBaseMesh.setMode('SubSurf', 'Optimal')						# added
		newBaseMesh.update(1)											# added
		newBaseObj.setLocation(Blender.Window.GetCursorPos())			# added
		newBaseObj.makeDisplayList()									# added
		Blender.Window.RedrawAll()
		

def saveIni(path):
	"""
	DESCRIPTION
	Save a text file makehuman.ini
			
	SYNOPSIS
	saveIni(path)

	PARAMATERS
	path: the path where save the files
			            
	RETURN VALUES:
	None
    """
	try:
		file = open("makehuman.ini", "w")
		file.write(path)
		file.close()
		print "saved new ini file"
	except:
		print "problem to save ini file"


def readIni():
	"""
	DESCRIPTION
	Read a text file makehuman.ini
			
	SYNOPSIS
	readIni()

	PARAMATERS
	no parameter
			            
	RETURN VALUES:
	the path of targets lib
    """
	try:
		file = open("makehuman.ini")
		targetsPath = file.readline()
		file.close()
		return targetsPath
	except:
		print "problem to retrieve ini file"



	
def save_vertexgroups(path, names_to_save = []):
	"""
	DESCRIPTION
	save the vertexgroup of a mesh
			
	SYNOPSIS
	save_vertexgroups (filename, names_to_save = [])

	PARAMATERS
	path = the path into save the vertexgroups file
	names_to_save = name of vertexgroup to save. If not gived save all
			            
	RETURN VALUES:
	no
	
	OTHER
	thanks to Michael Shardt
	
	USAGE
	The scene must contain a object called "Base"
	to save all vertexgroups in "C:/base.vgroup":
	save_vertexgroups ("C:/")
	to save vertexgroups named "group1" and "group2" (if existing) of object obj to file "C:/base.vgroup":
	save_vertexgroups ("C:/", ["group1", "group2"])
    """
	filename = path+"base.vgroup"
    # Get Raw mesh data #
	try:
		object = Blender.Object.Get("Base")
		mesh = object.getData()
	except:
		print "Base obj not in scene"
		return
	
	if not names_to_save:						# save all
		groupnames = mesh.getVertGroupNames()
	else:										# save only specified groups (if existing)
		groupnames = [name for name in names_to_save if name in mesh.getVertGroupNames()]

	if groupnames:								# is there anything to save? If not - no need to create an empty file, right?
		f = file (filename, "w")
		for groupname in groupnames:
			f.write (groupname + ":\n")
			for data in mesh.getVertsFromGroup(groupname, 1):
				f.write (str(data[0]) + "," + str(data[1]) + "\n")
		f.close()

def load_vertexgroups(path, names_to_load = [], append_mode = 0):

	"""
	DESCRIPTION
	load the vertexgroup from file, and apply it yo an object
			
	SYNOPSIS
	load_vertexgroups (path, names_to_load = [], append_mode = 0)

	PARAMATERS
	path = path from load the vertexgroups
	names_to_load = name of vertexgroup to load. If not gived load all
	append_mode = if true, the vertexgroup will be append to existent, else it replace all
			            
	RETURN VALUES:
	no
	
	OTHER
	thanks to Michael Shardt
	
	USAGE
	The scene must contain a object called "Base"
	to load all vertexgroups from file "C:/base.vgroup" to object obj, deleting existing groups first:
	load_vertexgroups ("C:/")
	to load all vertexgroups from file "C:/base.vgroup" to object obj, keeping existing groups (except for name-collisions - see remark below):
	load_vertexgroups ("C:/", [],  1)
	to load only vertexgroups named "group1" and "group2" (if existing) from file "C:/base.vgroup" to object obj, deleting existing groups first:
	load_vertexgroups ("C:/", ["group1", "group2"])
	to load only vertexgroups named "group1" and "group2" (if existing) from file "C:/base.vgroup" to object obj,  keeping existing groups (except for name-collisions - see remark below):
	load_vertexgroups ("C:/", ["group1", "group2"], 1)
    """
	filename = path+"base.vgroup"
    # Get Raw mesh data #
	try:
		object = Blender.Object.Get("Base")
		mesh = object.getData()
	except:
		print "Base obj not in scene"
		return
	
	if not append_mode:
		for name in mesh.getVertGroupNames():
			mesh.removeVertGroup(name)			# remove all existing vertexgroups before loading new ones
	try:
		f = file (filename, "r")
	except:
		print "Problem to open the vertex group file"
		return

	line = (f.readline()).strip()
	while line:
		if line[len(line) - 1] == ":": 			# last character is a colon - it's a new groupname
			groupname = line[:len(line) - 1]
			if (not names_to_load) or (groupname in names_to_load):	# new group will be added
				if groupname in mesh.getVertGroupNames(): mesh.removeVertGroup(groupname) # name conflict - remove (old) duplicate group first
				mesh.addVertGroup (groupname)	# now add new one
				skip_data = 0
			else:								# skip this group (and the data following) 
				skip_data = 1
		else:									# it's data
			if not skip_data:
				data = line.split(",")
				index  = int(data[0])		
				weight = float(data[1])
				try:
					mesh.assignVertsToGroup (groupname, [index], weight, "replace") # could also use "add" or "substract" instead of "replace" - dont't know
				except:
					print "vertex group file corrupted or not for this mesh"
					return
		line = (f.readline()).strip()
	f.close()
	
def saveUV(path):
	"""
	DESCRIPTION
	save the UV coordinates in a text file
			
	SYNOPSIS
	saveUV(path)

	PARAMATERS
	path = the full path for file to save
			            
	RETURN VALUES:
	no
    """
    # Get Raw mesh data #
	path = path+"base.uv"
	try:
		obj = Blender.Object.Get("Base")
		obj_mesh = obj.getData()
	except:
		print "Base obj not in scene"
		return
	try:
		file = open(path, "w")
	except:
		print "problem to save file"
		return
		
	for f in obj_mesh.faces:
		nvrt = len(f.uv)
		if nvrt == 0:
			print "Object do not have UV"
			return
		for n in range(nvrt-1):
			file.write(str(f.uv[n][0])+","+str(f.uv[n][1])+";")
		file.write(str(f.uv[nvrt-1][0])+","+str(f.uv[nvrt-1][1]))
		file.write("\n")
	file.close()

def applyUV(path):
	"""
	DESCRIPTION
	apply the UV coordinates from  a text file
			
	SYNOPSIS
	saveUV(path)

	PARAMATERS
	path = the full path for file to save
			            
	RETURN VALUES:
	no
    """
	path = path+"base.uv"
	# Get Raw mesh data #
	try:
		obj = Blender.Object.Get("Base")
		obj_mesh = obj.getData()
	except:
		print "Select the human, please"
		return
	obj_mesh.hasFaceUV(0)
	try:
		file = open(path)
	except:
		print "problem to open file", path
		return
	
	for f in obj_mesh.faces:
		uvData = file.readline()
		uvCoo = uvData.split(';')
		if len(f.uv) != 0:
			hasUV = 1
		else:
			hasUV = 0
		try:
			for i in range(len(f.v)):
				uvVertCoo = uvCoo[i].split(',')
				x = float(uvVertCoo[0])
				y = float(uvVertCoo[1])
				if hasUV:
					f.uv[i] = (x,y)
				else:
					f.uv.append((x,y))
		except:
			print "the UV is not suitable for object"
			return
	file.close()
	obj_mesh.update(1)

def fileExist(filename):
	"""
	this function will be deleted
	when os module will be included
	in blender built-in
    """
	try:
		file = open(filename)
		file.close()
		return 1
	except:
		return 0


def saveTargetsValue(filePath, targetList, valuesList):
	"""
	DESCRIPTION
	Save a text file with row target,value
			
	SYNOPSIS
	saveTargetsValue(filePath, targetList, valuesList)

	PARAMATERS
	path: the path where save the files
	targetList: a list of all targets local path
	valuesList: a list of all targets values applied
			            
	RETURN VALUES:
	None
    """
	#try:
	file = open(filePath, "w")
	for i in range(len(targetList)):
		file.write(targetList[i]+","+str(valuesList[i])+"\n")
	file.close()
	print "Body setting saved to ",filePath
	#except:
	#	print "problem to save body setting"


def loadTargetsValue(filePath):
	"""
	DESCRIPTION
	Read file with slider setting info
			
	SYNOPSIS
	loadTargetsValue(filePath)

	PARAMATERS
	no parameter
			            
	RETURN VALUES:
	filePath
    """
	try:
		file = open(filePath)
		nameAndValues = file.readline()
		valuesData = []
		while nameAndValues:
			valuesData.append(nameAndValues)
			nameAndValues = file.readline()
		file.close()
		return valuesData
	except:
		print "problem to open setiing file"