from lar import *
from scipy import *
import json
import scipy
import numpy as np
import time as tm
import gc
import struct
import getopt, sys
import os
import traceback

# ------------------------------------------------------------
# Logging & Timer
# ------------------------------------------------------------

logging_level = 0;

# 0 = no_logging
# 1 = few details
# 2 = many details
# 3 = many many details

def log(n, l):
	if __name__=="__main__" and n <= logging_level:
		for s in l:
			print "Log:", s;

timer = 1;

timer_last =  tm.time()

def timer_start(s):
	global timer_last;
	if __name__=="__main__" and timer == 1:
		log(3, ["Timer start:" + s]);
	timer_last = tm.time();

def timer_stop():
	global timer_last;
	if __name__=="__main__" and timer == 1:
		log(3, ["Timer stop :" + str(tm.time() - timer_last)]);

# ------------------------------------------------------------

# ------------------------------------------------------------

def triangulate_quads(F):
    Ftr = []
    for [v1, v2, v3, v4] in F:
        Ftr.append([v1, v2, v3])
        Ftr.append([v1, v3, v4])
    return Ftr

def invertIndex(nx,ny,nz):
	nx,ny,nz = nx+1,ny+1,nz+1
	def invertIndex0(offset):
		a0, b0 = offset / nx, offset % nx
		a1, b1 = a0 / ny, a0 % ny
		a2, b2 = a1 / nz, a1 % nz
		return b0,b1,b2
	return invertIndex0

def readFile(V,FV,chunksize,inputFile,OUT_DIR): #outputVtx="outputVtx.obj",outputFaces="outputFaces.obj"):
	outputId = os.path.basename(inputFile).split('.')[0].split('-')[1]
	outputVtx=OUT_DIR+"/output-a-"+outputId+".stl"
	outputFaces=OUT_DIR+"/output-b-"+outputId+".stl"

	with open(inputFile, "rb") as file:
		with open(outputVtx, "w") as fileVertex:
			with open(outputFaces, "w") as fileFaces:

				vertex_count = 1
				old_vertex_count = vertex_count
				count = 0

				try:
					while True:
						count += 1

						zStart = struct.unpack('>I', file.read(4))[0]
						xStart = struct.unpack('>I', file.read(4))[0]
						yStart = struct.unpack('>I', file.read(4))[0]

						log(1, ["zStart, xStart, yStart = " + str(zStart) + "," + str(xStart) + "," + str(yStart)]);
						#	zStart, xStart, yStart = LISTA_OFFSET[i].astype(float64)

						LISTA_VETTORI2 = np.zeros(chunksize,dtype=int32);

						# log(1, ["chunksize = " + str(chunksize)]);
						temp = file.read(chunksize);
						# log(1, ["chunksize = OK"]);

						i = 0
						timer_start("LISTA_VETTORI2 " + str(i));
						while (i < chunksize):
							if (temp[i] == '\x01'):
								LISTA_VETTORI2[i] = 1;
							i = i + 1;
						timer_stop();
						log(1, ["LISTA_VETTORI2[i] = " + str(i)]);

						timer_start("objectBoundaryChain ");
						l = len(LISTA_VETTORI2)
						objectBoundaryChain = scipy.sparse.csr_matrix(LISTA_VETTORI2.reshape((l,1)))
						timer_stop();

						timer_start("csrChainToCellList " + str(i));
						b2cells = csrChainToCellList(objectBoundaryChain)
						timer_stop();

						timer_start("MKPOLS " + str(i));

						for f in b2cells:
							old_vertex_count = vertex_count

							for vtx in FV[f]:
								fileVertex.write("v ")
								fileVertex.write(str(V[vtx][0] + xStart))
								fileVertex.write(" ")
								fileVertex.write(str(V[vtx][1] + yStart))
								fileVertex.write(" ")
								fileVertex.write(str(V[vtx][2] + zStart))
								fileVertex.write("\n")
								vertex_count = vertex_count + 1

							fileFaces.write("f ")
							fileFaces.write(str(old_vertex_count + 0))
							fileFaces.write(" ")
							fileFaces.write(str(old_vertex_count + 1))
							fileFaces.write(" ")
							fileFaces.write(str(old_vertex_count + 3))
							fileFaces.write("\n")

							fileFaces.write("f ")
							fileFaces.write(str(old_vertex_count + 0))
							fileFaces.write(" ")
							fileFaces.write(str(old_vertex_count + 3))
							fileFaces.write(" ")
							fileFaces.write(str(old_vertex_count + 2))
							fileFaces.write("\n")

						fileVertex.flush()
						fileFaces.flush()

					timer_stop();
				except:
					exc_type, exc_value, exc_traceback = sys.exc_info()
					lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
					log(1, [ "EOF or error: " + ''.join('!! ' + line for line in lines) ])

def main(argv):
	ARGS_STRING = 'Args: -x <borderX> -y <borderY> -z <borderZ> -i <inputfile> -o <outdir>'

	try:
		opts, args = getopt.getopt(argv,"i:o:x:y:z:")
	except getopt.GetoptError:
		print ARGS_STRING
		sys.exit(2)

	nx = ny = nz = 64
	mandatory = 3
	#Files
	FILE_IN = ''
	OUT_DIR = ''

	for opt, arg in opts:
		if opt == '-x':
			nx = ny = nz = int(arg)
			mandatory = mandatory - 1
		elif opt == '-y':
			ny = nz = int(arg)
		elif opt == '-z':
			nz = int(arg)
		elif opt == '-i':
			FILE_IN = arg
			mandatory = mandatory - 1
		elif opt == '-o':
			OUT_DIR = arg
			mandatory = mandatory - 1

	if mandatory != 0:
		print 'Not all arguments where given'
		print ARGS_STRING
		sys.exit(2)

	def ind(x,y,z): return x + (nx+1) * (y + (ny+1) * (z))

	chunksize = nx * ny + nx * nz + ny * nz + 3 * nx * ny * nz
	V = [[x,y,z] for z in xrange(nz+1) for y in xrange(ny+1) for x in xrange(nx+1) ]

	v2coords = invertIndex(nx,ny,nz)

	FV = []
	for h in xrange(len(V)):
		x,y,z = v2coords(h)
		if (x < nx) and (y < ny): FV.append([h,ind(x+1,y,z),ind(x,y+1,z),ind(x+1,y+1,z)])
		if (x < nx) and (z < nz): FV.append([h,ind(x+1,y,z),ind(x,y,z+1),ind(x+1,y,z+1)])
		if (y < ny) and (z < nz): FV.append([h,ind(x,y+1,z),ind(x,y,z+1),ind(x,y+1,z+1)])

	try:
		readFile(V,FV,chunksize,FILE_IN,OUT_DIR)
	except:
		exc_type, exc_value, exc_traceback = sys.exc_info()
		lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
		log(1, [ "Error: " + ''.join('!! ' + line for line in lines) ])
		sys.exit(2)

if __name__ == "__main__":
	main(sys.argv[1:])
