#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Created on Wed Aug 28 17:39:43 2019

Module contanant les classes générales structurant les données, ainsi que les 

@author: mysaa
"""
import numpy as np

def appendeur(l1,l2):
    """
        Effectue l1=l1+l2 de manière opti
    """
    for l in l2:
        l1.append(l)

class WorldChunk():
    
    def getSize(self):
        raise NotImplementedError("Vous avez fait un monde qui n'implemente pas cette méthode. Vous êtes bizzare vous savez ? Un monde sans taille !!!")
        
     
    def getColumn(self,x,y):
        raise NotImplementedError("Vous avez fait un monde qui n'implemente pas cette méthode. Vous êtes bizzare vous savez ?")
        
    
    def asList(self):
        return [ [self.getColumn(x,y) for y in range(self.size[1])]  for x in range(self.size[0]) ]
    
    def getIndexed(self,fullCoords=False,addZero=False):
        points = []
        pointIndexes = [0]
        for pos in np.ndindex(self.getSize()):
            col = self.getColumn(pos[0],pos[1])
            if(addZero): col = np.insert(col,0,0)
            if(fullCoords): col = [(pos[0],pos[1],c) for c in col]
            appendeur(points,col)
            pointIndexes.append(pointIndexes[-1]+len(col))
        return points,pointIndexes
    
        
class CollageWorldChunk(WorldChunk):
    
    def __init__(self,chunk,xp,yp,xy):
        
        self.orgChunk,self.xp,self.yp,self.xy = chunk,xp,yp,xy
        self.orgSize = chunk.getSize()
        
    def getSize(self) : return (self.orgChunk.size[0]+1,self.orgChunk.size[1]+1)
        
    def getColumn(self,x,y):
        xout,yout = x>=self.orgSize[0],y>=self.orgSize[1]
        if(xout and yout):
            return self.xy.getColumn(x-self.orgSize[0],y-self.orgSize[1])
        if(xout):
            return self.xp.getColumn(x-self.orgSize[0],y)
        if(yout):
            return self.yp.getColumn(x,y-self.orgSize[1])
        
        return self.orgChunk.getColumn(x,y)
    
class ArrayedWorldChunk(WorldChunk):
    
    def fromList(liste):
        size = len(liste),len(liste[0])
        indexes=np.empty(size[0]*size[1]+1,dtype=np.uint32)
        index = 0
        data = []
        for y in range(size[1]):
            for x in range(size[0]):
                indexes[x+size[0]*y]=index
                data += liste[x][y]
                index += len(liste[x][y])
        indexes[size[0]*size[1]] = index
        data = np.array(data,dtype=np.float)
        return ArrayedWorldChunk(size,indexes,data)
    
    def __init__(self,size,indexes,data):
        self.size = size
        self.indexes=indexes
        self.data=data
    
    
    def getColumn(self,x,y):
        i0,i1 = self.indexes[x+self.size[0]*y],self.indexes[x+self.size[0]*y+1]
        return self.data[i0:i1]
    
    def getSize(self) : return self.size
      
    

    
    
    



class Noise:
    
    def getChunk(self,x,y,n):
        """
            Cette fonction renvoie un array numpy de taille rx*ry correspondant au chunk x y avec le seed donné.
            Cette fonction doit être déterministe (si les attributs de l'objets ne sont pas changés bien sur)
        """
        raise NotImplementedError("Vous avez fait un bruit qui n'implemente pas cette méthode. Vous êtes bizzare vous savez ?")
        
        
        
    def __add__(self,other):
        
        def addedChunk(self,x,y,n):
            return self.noise1.getChunk(x,y,n) + self.noise2.getChunk(x,y,n)
        noise = Noise()
        noise.noise1 = self
        noise.noise2 = other
        noise.getChunk = addedChunk
        return noise
    
    def __iadd__(self,other):
        
        return self.__add__(other)
    
    def __rmul__(self,other):
        
        if type(other) in ['float','int']:
            def mulChunk(self,x,y,n):
                return self.prop*self.noise1.getChunk(x,y,n)
            noise = Noise()
            noise.noise1 = self
            noise.prop = other
            noise.getChunk = mulChunk
        else:
            def mulChunk(self,x,y,n):
                return self.noise1.getChunk(x,y,n) * self.noise2.getChunk(x,y,n)
            noise = Noise()
            noise.noise1 = self
            noise.noise2 = other
            noise.getChunk = mulChunk
        return noise
    
    def __sub__(self,other):
        
        def subChunk(self,x,y,n):
            return self.noise1.getChunk(x,y,n) - self.noise2.getChunk(x,y,n)
        noise = Noise()
        noise.noise1 = self
        noise.noise2 = other
        noise.getChunk = subChunk
        return noise
    