import win32com.client
from win32com.client import constants
from datetime import datetime
from struct import pack
import os

def XSILoadPlugin( in_reg ):
	in_reg.Author = "Vladimir Jankijevic"
	in_reg.Name = "STL_Export Plug-in"
	in_reg.Major = 1
	in_reg.Minor = 0
	
	in_reg.RegisterCommand("STL_Export","STL_Export")
	in_reg.RegisterMenu(constants.siMenuMainFileExportID,"STL_Export_Menu",False,False)

	return True

def XSIUnloadPlugin( in_reg ):
	strPluginName = in_reg.Name
	Application.LogMessage(str(strPluginName) + str(" has been unloaded."),constants.siVerbose)
	return True
	
def STL_Export_Init( in_ctxt ):
	oCmd = in_ctxt.Source
	oCmd.Description = "Exports Object in STL format"
	oCmd.Tooltip = "Exports Object in STL format"
	oCmd.SetFlag(constants.siCannotBeUsedInBatch,True)
	oCmd.ReturnValue = False

	oArgs = oCmd.Arguments
	oArgs.Add("filename",constants.siArgumentInput)
	oArgs.AddWithHandler("object",constants.siArgHandlerSingleObj)
	oArgs.Add("ascii",constants.siArgumentInput,False,constants.siBool)
	return True

def WriteHeader(oFile,objectName,triangleCount,ascii):
	if ascii:
		data = 'solid %s\n\n' % objectName
	else:
		headerLength = 80
		nameLength = len(objectName)
		if nameLength > 80: 
			objectName = ''
			nameLength = 0
		space = '_'*(headerLength-nameLength)
		data = pack('c'*headerLength,*str('%s' %objectName + space))
		data += pack('I',triangleCount)
	oFile.write(data)
	
def WriteData(oFile,tData,ascii):
	if ascii:
		data = 'facet normal %e %e %e\nouter loop\nvertex %e %e %e\nvertex %e %e %e\nvertex %e %e %e\nendloop\nendfacet\n' %(tData)		
	else:
		data = pack('f'*12,*tData)
		data += pack('H',0)
		
	oFile.write(data)	
	


def STL_Export_Execute( filename, object, ascii ):
	startTime = datetime.now()
	Application.LogMessage( 'STL Export 1.0 by Vladimir Jankijevic',constants.siInfo)
	
	if object == None:
		object = Application.Selection(0)
		if object == None or object.Type != 'polymsh': 
			Application.LogMessage('Please select an polymesh first!',constants.siError)
			return False

	if filename == None or filename == '':
		fileBrowser = XSIUIToolkit.FileBrowser
		fileBrowser.DialogTitle = "Export As..." 
		fileBrowser.InitialDirectory = Application.ActiveProject.Path
		fileBrowser.Filter = "STL Binary (*.stl)|*.stl||" 
		fileBrowser.ShowSave()
		filePath = fileBrowser.FilePath
		fileBaseName = fileBrowser.FileBaseName
		if fileBaseName == '':
			Application.LogMessage('Export aborted by user!',constants.siWarning)
			return False
		fileExtension = fileBrowser.FileExtension	
		filename = '%s.%s'%(os.path.join(filePath,fileBaseName),fileExtension)
		fileBrowser = None

	if ascii:
		oFile = open(filename, 'w')
	else:
		oFile = open(filename, 'wb')
		
	objectName = object.Name
	geometry = object.ActivePrimitive.Geometry
	vector = XSIMath.CreateVector3()
	rotation = XSIMath.CreateRotation(XSIMath.PI/2,0,0)
	triangles = geometry.Triangles
	triangleCount = triangles.Count 
	pointPositions = triangles.PositionArray
	polyNodeNormals = triangles.PolygonNodeNormalArray

	step = 250
	progressbar = XSIUIToolkit.ProgressBar
	progressbar.Maximum = triangleCount
	progressbar.Step = step
	progressbar.CancelEnabled = True
	progressbar.Visible = True
	canceled = False

	data = WriteHeader(oFile,objectName,triangleCount,ascii)

	for i in range(0,triangleCount):
		vector.Set(	polyNodeNormals[0][0][i]+
					polyNodeNormals[0][1][i]+
					polyNodeNormals[0][2][i],
					polyNodeNormals[1][0][i]+
					polyNodeNormals[1][1][i]+
					polyNodeNormals[1][2][i],
					polyNodeNormals[2][0][i]+
					polyNodeNormals[2][1][i]+
					polyNodeNormals[2][2][i])
		
		vector.MulByRotationInPlace(rotation)
		vector.NormalizeInPlace()
		tData = vector.Get2()
		for j in range(0,3):
			vector.Set(pointPositions[0][j][i],pointPositions[1][j][i],pointPositions[2][j][i])
			vector.MulByRotationInPlace(rotation)
			tData += vector.Get2()
		
		WriteData(oFile,tData,ascii)
		
		if i%step==0:
			if progressbar.CancelPressed: 
				canceled = True
				break
			progressbar.Caption = "Triangle %i" % i
			progressbar.Increment(1)


	oFile.close()

	if canceled:
		Application.LogMessage('Export aborted by user!',constants.siWarning)
		return False
	else:
		endTime = datetime.now()
		totalTime = endTime - startTime
		timeElapsedInSeconds = totalTime.seconds + totalTime.microseconds / 1000000.0
		Application.LogMessage('exported %s to %s in %f seconds' %(objectName,filename,timeElapsedInSeconds),constants.siInfo)
		return True

def STL_Export_Menu_Init( in_ctxt ):
	oMenu = in_ctxt.Source
	oMenu.AddCommandItem("Export STL","STL_Export")
	
	