#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Aug 22 19:46:36 2019

@author: mysaa
"""
import numpy as np
from data import CollageWorldChunk
from perlin import CavernedNoise2,TestNoise



def getTriangles(x0,y0,chunk,xp,yp,xy):
    
    
    nx,ny = chunk.size
    newChunk = CollageWorldChunk(chunk,xp,yp,xy)
    
#    pointIndexes = np.zeros((nx+1,ny+1),dtype=np.uint32)
#    pointLengthes = np.zeros((nx+1,ny+1),dtype=np.uint32)
#    points = []
#    
#    
#    pos = 0
#    for j in range(ny):
#        for i in range(nx):
#            carotte = [(x0+i/nx,y0+j/ny,z) for z in sorted([0.]+list(chunk.getColumn(i,j)))]
#            points += carotte
#            pointLengthes[i,j] = len(carotte)
#            pointIndexes[i,j] = pos
#            pos+=len(carotte)
#        carotte = [(x0+1,y0+j/ny,z) for z in sorted([0.]+list(xp.getColumn(0,j)))]
#        points += carotte
#        pointLengthes[nx,j]= len(carotte)
#        pointIndexes[nx,j] = pos
#        pos+=len(carotte)
#    for i in range(nx):
#        carotte = [(x0+i/nx,y0+1,z) for z in sorted([0.]+list(yp.getColumn(i,0)))]
#        points += carotte
#        pointLengthes[i,ny] = len(carotte)
#        pointIndexes[i,ny] = pos
#        pos+=len(carotte)
#    carotte = [(x0+1,y0+1,z) for z in sorted([0.]+list(xy.getColumn(0,0)))]
#    points += carotte
#    pointLengthes[nx,ny] = len(carotte)
#    pointIndexes[nx,ny] = pos
    
    
    
    points,pointIndexes = newChunk.getIndexed(fullCoords=True,addZero=True)
    
    points=[(p[0]/nx+x0,p[1]/ny+y0,p[2]) for p in points]
    pointLengthes = np.reshape([pointIndexes[i+1]-pointIndexes[i] for i in range(len(pointIndexes)-1)],(nx+1,ny+1))
    pointIndexes = np.reshape(pointIndexes[:-1],(nx+1,ny+1))
    print(points,pointIndexes,pointLengthes)
    
    
    
    
    
    
    triangles = []
    
    
    for x in range(nx*2):
        for y in range(ny):
            # On récupère les coordonées entières du triangle indicé (x,y)
            if(x%2==0):
                col0=(x//2  ,y  )
                col1=(x//2+1,y  )
                col2=(x//2  ,y+1)
            else:
                col0=(x//2+1,y+1)
                col1=(x//2+1,y  )
                col2=(x//2  ,y+1)
            
            # On récupère la liste des points dans la colonne
            colonne0 = points[pointIndexes[col0[0],col0[1]]:pointIndexes[col0[0],col0[1]]+pointLengthes[col0[0],col0[1]]]
            colonne1 = points[pointIndexes[col1[0],col1[1]]:pointIndexes[col1[0],col1[1]]+pointLengthes[col1[0],col1[1]]]
            colonne2 = points[pointIndexes[col2[0],col2[1]]:pointIndexes[col2[0],col2[1]]+pointLengthes[col2[0],col2[1]]]
            #print("colonne:",colonne1)
            # st contient des triplets (numéro de colonne,index interne dans la colonne,coordonée z)
            st  = [(0,i,colonne0[i][2]) for i in range(len(colonne0))]
            st += [(1,i,colonne1[i][2]) for i in range(len(colonne1))]
            st += [(2,i,colonne2[i][2]) for i in range(len(colonne2))]
            
            
            # On y trie par coordonée z
            st = sorted(st,key=lambda c:c[2])
            
            #Liste des coordonées des colonnes, pour pouvoir sélectionner les coordonées selon l'index de la colonne
            cols = [col0,col1,col2]
            # Là, tout est bon à peu près
            
            i=0
            try:
                while i<len(st):
                    v1 = st[i] ; i+=1
                    v2 = st[i] ; i+=1
                    if v1[0]==v2[0]: continue #Cas où une colonne apparait puis disparaît
                    von = [v1,v2,None]
                    voff = [None,None,None]
                    while not None in von and voff!=[None,None,None]:
                        # On est dans la chaine aller-retour 2/1
                        v3 = st[i] ; i+=1
                        if voff[v3[0]]==None and von[v3[0]]!=None:
                            # Il s'agit d'un changement plein->vide
                            voff[v3[0]] = v3
                        else:
                            # Changement vide->plein
                            von[v3[0]]  = v3
                            voff[v3[0]] = None
                        if not None in von and not None in voff:
                            # Les deux colonnes ont disparu
                            # On peut créer le rectangle entre les deux derniers à avoir disparu et leur point d'apparitions
                            v3,v4 = st[i],st[i-1]
                            v1,v2 = von[v3[0]],von[v4[0]]
                            triangle1 = [pointIndexes[cols[v[0]]] + v[1] for v in (v1,v2,v3)]
                            triangle2 = [pointIndexes[cols[v[0]]] + v[1] for v in (v1,v3,v4)]
                            triangles.append(triangle1)
                            triangles.append(triangle2)
                            break
                        
                    else:
                        # On est dans le cas ou v1,v2,v3 correspondent à trois colonnes
                        # différentes (le cas (1,1,1) ayant déjà été filtré par la première condition)
                        
                        # On ajoute le triangle en dessous
                        triangle = [pointIndexes[cols[v[0]]] + v[1] for v in (v1,v2,v3)]
                        triangles.append(triangle)
                        
                        # On "attends" jusqu'à ce que les trois colonnes soient à nouveau vides
                        vs = [None,None,None]
                        while None in vs:
                            print("Quentin",st,i,vs)
                            v = st[i] ; i+=1
                            vs[v[0]] = v if vs[v[0]]==None else None
                        
                        # Avec cette mthode, on déssine le triangle avec les derniers points étant apparus (les plus hauts)
                        triangle = [pointIndexes[cols[v[0]]] + v[1] for v in vs]
                        triangles.append(triangle)
                    
                    continue
                    
                        
                        
                    
            except ValueError:
                # Une fin de liste a été atteinte, la colonne n'a pas été refermée: lance un warn
                print("Attention ! Une colonne n'avait pas de toit. veuillez vérifier que vos colonnes aient un nombre impair de coordonées, merci !")
            
    return points,triangles
            ########################################
#            while i<len(st):
#                #Plein
#                v0 = st[i]
#                i+=1
#                v1 = st[i]
#                i+=1
#                if(v0[0] == v1[0]): # S'est la même colonne qui est apparu puis disparu
#                    
#                    print("Tribord")
#                    colz = cols[v0[0]]
#                    # Triangle sur les bords
#                    # Demis-points
#                    halfZ = (v0[2]+v1[2])/2
#                    #Les deux autres colonnes sont :
#                    cola = cols[(v0[0]+1)%3]
#                    colb = cols[(v0[0]+2)%3]
#                    
#                    zi1,zi2=pointIndexes[colz]+v0[1],pointIndexes[colz]+v1[1]
#                    print('OoOOoO',points[zi1],points[zi2])
#                    
##                    points.append( (x0+(cola[0])/nx,y0+(cola[1])/ny,halfZ) )
##                    points.append( (x0+(colb[0])/nx,y0+(colb[1])/ny,halfZ) )
##                    
##                    triangles.append([zi1,len(points)-1,len(points)-2])
##                    triangles.append([zi2,len(points)-1,len(points)-2])
#                    print("Tribord-fin")
#                    #                    print(points[-1],points[-2],points[zi1])
#                    #print(cola,colb,points[triangles[-1][0]-1],points[triangles[-1][1]-1],points[triangles[-1][2]-1])                    
#                    
#                else: # Deux colonnes différentes ont apparus successivement 
#                    # vs stoque les états des colonnes
#                    # vs[i] est l'état de la ième colonne, le point de st, dernier à apparaître si
#                    # cette colonne est présente, None sinon
#                    vs=[None,None,None]
#                    vs[v0[0]] = v0
#                    vs[v1[0]] = v1
#                    while None in vs and vs != [None,None,None]:# Tant qu'il y a une abscente ou une présente
#                        v2 = st[i]
#                        i+=1
#                        vs[v2[0]] = v2 if vs[v2[0]]==None else None
#                    
#                    if not None in vs:
#                        # Une face complète a été créée
#                        # Triangle complet
#                        # Face dessous (apparition de la colonne)
#                        triangle = [pointIndexes[cols[i]] + vs[i][1] for i in range(3)]
#                        triangles.append(triangle)
#                        #print("#",[points[triangle[i]] for i in range(0,3)])
#                        
#                        
#                        # On inverse le sens de vs, et stoque les premiers points à apparaître
#                        vs = [None,None,None]
#                        while None in vs and i<len(st):
#                            v2 = st[i]
#                            i+=1
#                            vs[v2[0]] = v2 if vs[v2[0]]==None else None
#                            
#                        #Face dessus
#                        if not None in vs:
#                            triangle = [pointIndexes[cols[i]] + vs[i][1] for i in range(3)]
#                            triangles.append(triangle)
#                            #print("0",[points[triangle[i]] for i in range(3)])
#                    else:
#                        # Il faut placer un carré
#            #########################################
#    print(points)
#    return points,triangles
   


def getRectangles(x0,y0,chunk):
    nx,ny = chunk.size
    
    triangles = []
    points = []
    
    for x in range(nx) :
        for y in range(ny):
            for z in [0]+chunk.getColumn(x,y):
                points.append([x/nx+x0,y/ny+y0,z])
                points.append([x/nx+x0+1/nx,y/ny+y0,z])
                points.append([x/nx+x0,y/ny+y0+1/ny,z])
                points.append([x/nx+x0+1/nx,y/ny+y0+1/ny,z])
                triangles.append([len(points)-4,len(points)-3,len(points)-2])
                triangles.append([len(points)-3,len(points)-2,len(points)-1])
                
    return points,triangles

def getRectCols(x0,y0,chunk):
    nx,ny = chunk.size
    
    triangles = []
    points = []
    e=0.3
    
    for x in range(nx) :
        for y in range(ny):
            for z in [0]+chunk.getColumn(x,y):
                points.append([x/nx+x0-e,y/ny+y0-e,z])
                points.append([x/nx+x0+e,y/ny+y0-e,z])
                points.append([x/nx+x0-e,y/ny+y0+e,z])
                points.append([x/nx+x0+e,y/ny+y0+e/ny,z])
                triangles.append([len(points)-4,len(points)-3,len(points)-2])
                triangles.append([len(points)-3,len(points)-2,len(points)-1])
                
    return points,triangles

    
def getFilled(x0,y0,chunk):
    nx,ny = chunk.size
    
    triangles = []
    points = []
    
    for x in range(nx) :
        for y in range(ny):
            boule = True
            lz = 0
            for z in sorted(chunk.getColumn(x,y)):
                
                if boule:
                    points.append([x/nx+x0     ,y/ny+y0     ,z ])
                    points.append([x/nx+x0+1/nx,y/ny+y0     ,z ])
                    points.append([x/nx+x0     ,y/ny+y0+1/ny,z ])
                    points.append([x/nx+x0+1/nx,y/ny+y0+1/ny,z ])
                    points.append([x/nx+x0     ,y/ny+y0     ,lz])
                    points.append([x/nx+x0+1/nx,y/ny+y0     ,lz])
                    points.append([x/nx+x0     ,y/ny+y0+1/ny,lz])
                    points.append([x/nx+x0+1/nx,y/ny+y0+1/ny,lz])
                    l = len(points)
                    triangles.append([l-4,l-2,l-1])
                    triangles.append([l-4,l-3,l-1])
                    triangles.append([l-4,l-2,l-6])
                    triangles.append([l-4,l-8,l-6])
                    triangles.append([l-4,l-3,l-7])
                    triangles.append([l-4,l-8,l-7])
                    triangles.append([l-5,l-1,l-2])
                    triangles.append([l-5,l-6,l-2])
                    triangles.append([l-5,l-6,l-8])
                    triangles.append([l-5,l-7,l-8])
                    triangles.append([l-5,l-7,l-3])
                    triangles.append([l-5,l-1,l-3])
                    
                boule = not boule
                lz = z
            
                
    return points,triangles

def printObject(file,name,delta,points,triangles):
    file.write("o "+name+"\n\n")

    sf = lambda x : "%.6f" % float(x)
    si = lambda x : str(int(x+1)+delta)
    
    for p in points:
        file.write("v "+sf(p[0])+" "+sf(p[1])+" "+sf(np.array(p[2])/20.)+"\n")
    
    file.write("\n")
    
    for t in triangles:
        file.write("f "+" ".join([si(tp) for tp in t])+"\n")
        

def writeMap(filePath,noise,x0,y0,sx,sy,cx,cy,objType='triangle',log=print):
    log("Génération de la carte")
    generated = {}
    formatter='\rÉcriture du chunk {};{}                          '+" "*(sx//10+sy//10)
    for i in range(x0,sx+x0+(1 if objType=='triangle' else 0)):
        for j in range(y0,sy+y0+(1 if objType=='triangle' else 0)):
            log(formatter.format(i,j), end='\r')
            generated[(i,j)] = noise.getChunk(i,j,(cx,cy))
    log("Génération des objets")
    file = open(filePath,"w+")
    file.write("g carte\n")
    delta=0
    for i in range(x0,sx+x0):
        for j in range(y0,sy+y0):
            log(formatter.format(i,j), end='\r')
            if objType=='triangle':
                points,triangles = getTriangles(i,j,generated[(i,j)],generated[(i+1,j)],generated[(i,j+1)],generated[(i+1,j+1)])
            elif objType=='rectangle':
                points,triangles = getRectangles(i,j,generated[(i,j)])
            elif objType=='filled':
                points,triangles = getFilled(i,j,generated[(i,j)])
            elif objType=='rectcols':
                points,triangles = getRectCols(i,j,generated[(i,j)])
            else:
                raise ValueError("Je en connais pas le type d'objet "+objType)
            printObject(file,"chunk_"+objType+"_"+str(i)+"-"+str(j),delta,points,triangles)
            file.write("\n\n")
            delta+=len(points)
    log("\nTerminé !           "+" "*(sx//10+sy//10))
    file.close()
    
    
   
   


noise = CavernedNoise2(93152)

size = 12
taille=16

#writeMap("gros.obj",noise,-size//2+1,-size//2+1,size,size,taille,taille,'triangle')
#writeMap("carte.obj",noise,2,1,1,1,16,16,'triangle')
writeMap("carteTri.obj",noise,-8,-8,16,16,16,16,'triangle')
#writeMap("carteRec.obj",noise,-8,-8,16,16,16,16,'rectangle')
#writeMap("carteFil.obj",noise,-8,-8,16,16,16,16,'filled')
#writeMap("carteRCo.obj",noise,-8,-8,16,16,16,16,'rectcols')

#xy0=-taille*size
#for x in range(2*taille):
#    for y in range(2*taille):
#        
#        writeMap("render2/carte"+str(x)+","+str(y)+".obj",noise,xy0-size//2+x*size,xy0-size//2+y*size,size,size,'rectangle')

    
   