# objet de gestion d'effets d'une matrice WS2812 8x8

import array, time
from math import cos,sin
from machine import Pin
import rp2
from graphics import table_char,table_de,raw_digits,WHITE,BLACK,RAINBOW,COLORS
import random


# table de parcours de la spirale sur la matrice 8x8
# index 0: deplacement sur l'indice de la table de leds 255= arret
# index 1: nombre de pas de déplacement
mac2= [(255,0),(8,7),(1,7),(-8,7),(-1,6),(8,6),(1,5),(-8,5) ,(-1,4),(8,4),(1,3),(-8,3),(-1,2),(8,2),(1,2),(255,0)]
    # conversion des coordonnes xy en indice dans la table des leds
    # x de 0 à 7 y de 0 a 7
    # origine 0,0 en bas a gauche = indice 56
def xy_to_i(x,y):
    i= int(56 -y*8 + x)
    if i<0: i=0
    if i>63: i=63
    return i
    
class ws2812:
    # sm = machine a états du PIO utilisé
    def __init__(self, num_leds,  brightness,sm):
        self.num_leds = num_leds
        self.brightness = brightness
        self.ar = array.array("I", [0 for _ in range(self.num_leds)])
        self.machin= sm

    def array(self):
        return self.ar
    
    def pixels_show(self):
        self.machin.put(self.ar, 8)
        time.sleep_ms(10)
        
    def pixels_brightness(self,brightness=0.005):
        self.brightness = brightness
        
    # codage RGB sur 24 bits de ar[] sera a passer en GRB pour les leds WS2812
    # applique le coeff de brightness ici
    def pixel_set(self, i=0, color=BLACK):
        r = int(((color[0] ) & 0xFF) * self.brightness)
        g = int(((color[1] ) & 0xFF) * self.brightness)
        b = int((color[2] & 0xFF) * self.brightness)
        self.ar[i] = (g<<16) + (r<<8) + b

    def pixels_fill(self, color):
        for i in range(len(self.ar)):
            self.pixel_set(i, color)

    def pixels_fill_range(self, start, num_elements, color):
        for i in range(start, num_elements, 1):
            self.pixel_set(i, color)
            
    def pixels_char(self,c,color,shift=0):
        #print(f'c= {c} t= { table_char[(c-32)*6:(c-31)*6]}')
        for i in range(len(self.ar)):
            index= i % 8
            ligne= (i >> 3)
            self.ar[i]= 0
            if (index < 7) and (index > 0) : 
                if (table_char[(c-32)*6+index] >> ligne) & 1 != 0 :
                    self.pixel_set(i,color)
                    
    def pixels_de(self,c,color):
        for i in range(len(self.ar)):
            index= i % 8
            ligne= i >>3
            self.ar[i]= 0
            if( table_de[c*8+index] << ligne ) & 0x80 != 0 :
                self.pixel_set(i,color)
    
    # pos = 1 4 colonnes a gauche
    # pos = 0 4 colonnes a droite
    # c 0 a 9 sinon 4 colonnes OFF
    def pixels_chiffre(self,c,color=WHITE,pos=0,background=BLACK):
        for i in  range(len(self.ar)):
            col = i % 8
            ligne = i >>3
            if pos == 1 : # a gauche
                if col < 4 :
                    self.pixel_set(i,background) 
                    if (raw_digits[c][col] & (0x80>>ligne)) != 0 :
                        self.pixel_set(i,color)               
            if pos != 1 : # a droite
                if col > 3 :
                    self.pixel_set(i,background) 
                    if (raw_digits[c][col-4] & (0x80>>ligne)) != 0 :
                        self.pixel_set(i,color)
                        
    def pixels_rainbow(self,shift=0) :
        for i in range (len(self.ar)):
            color_index = (i+shift) % len(RAINBOW)
            self.pixel_set( i,RAINBOW[color_index] )
    

                
    def pixels_alea (self,num=24):
        for i in range(0,num):
            color=random.choice(COLORS)
            j=random.randint(0,63)
            self.pixel_set(j,color)
        
    # spirale en color
    # invert commence au centre en 36
    # point n'utilise qu'un point
    # cumul reprend au dernier appel
    
     
        
    def pixels_spirale (self,color=WHITE,max=64,invert=False,point=False,cumul=False):
        n=0
        if invert==False: mstep=1
        else: mstep= len(mac2)-2
        if point==False or invert==True:
            for i in range (len(self.ar)):self.ar[i]=0
        if invert==True: i=37
        else: i=0
        while True:
            if n>=max :
#                 print(f'cc= {count} i= {i} m={istep} max={max}')
                return
            istep= mac2[mstep]
            count= istep[1]
            if istep[0]==255: return
            while count!=0:
#                 print(f'c= {count} i= {i} m={istep} {mstep} max={max}')
                self.pixel_set(i,color)
                n+=1
                if n>max:
#                     print(f'cc= {count} i= {i} m={istep} max={max}')
                    return
                count -=1
                if point==True: self.ar[i]=0
                if invert==True: i-= istep[0]
                else: i+=istep[0]
            # change de step
            if invert==True: mstep-=1
            else: mstep+=1
            

        
    def pixels_carre(self,color=WHITE,repeat=1):
        for i in range (len(self.ar)):self.ar[i]=0
        #print(f'shift= {shift}')
        s=0
        while repeat!=0 :
            #print(f's= {s}')
            for i in range(0,8):
                self.pixel_set(i+s*8,color)
                self.pixel_set(56+i-s*8,color)
                self.pixel_set(s+i*8,color)
                self.pixel_set(63-i*8-s,color)
            s+=1
            repeat-=1
            
    #trace d'une droite        
    def pixels_line(self, x1=0,y1=0, x2=7,y2=7,color=WHITE):
        incy= (y2-y1)/16
        incx= (x2-x1)/16 # pas minimal
        x=x1
        y=y1
        for j in range (0,16) :
           self.pixel_set(xy_to_i(x,y),color)
           x += incx
           y += incy
        
        

        
             
            
                
          
            
            
            
    