#ifndef AddFastLED_H
#define AddFastLED_H

#include "FastLED.h"

class AddFastLED : public CFastLED {

	public:
		void afficher(void){show();}


				void initialisation (uint16_t taille){
					/*EDU US*/ m_nbrOfLed=taille;
		memory 		= (byte*)malloc(taille*sizeof(uint8_t));

	
	// On initialise les tableaux à 0 (=aucune LED allumée)
		for(uint16_t i=0;i<taille;i++){
			memory[i]	 =B00000000;
		}
}

/*EDU FR*/	void preparerPixel(uint16_t startLed, uint16_t r, uint16_t g, uint16_t b, uint16_t widthGroupe, uint8_t step, int16_t endR, int16_t endG, int16_t endB,CRGB* _leds){

		setPixel(startLed, r, g, b, widthGroupe, step, endR, endG, endB,_leds );
}//*/

/*EDU US*/	void setPixel     (uint16_t startLed, uint16_t r, uint16_t g, uint16_t b, uint16_t widthGroupe, uint8_t step, int16_t endR, int16_t endG, int16_t endB,CRGB* _leds){
	/*	n 				numéro de la première LED
		r,g,b			les 3 couleurs
		endPixel		la dernière LED concernée
		step			pas pour la répétition (toutes les step LED)
	*/
	
	//---- On corrige les valeurs
		//--- On limite à 1000
			if(r>1000){r=1000;} if(g>1000){g=1000;}	if(b>1000){b=1000;}	

		//--- On ajuste la LED de fin
			/**/ if(widthGroupe>=m_nbrOfLed){widthGroupe=m_nbrOfLed;}
	
	//--- Calculs utiles par la suite
		//-- On calcule combien de led sont concernées par ce fade
			//Serial.println("--------");
			int nbrLedFade = widthGroupe;					    // Plage active
			//Serial.println(nbrLedFade);							// Ex : 7
		
			nbrLedFade*=10;										// Pour pouvoir obtenir un reste
			//Serial.println(nbrLedFade);							// Ex 70
			
			nbrLedFade/=step;									// Division par nbr de step (Ex:3)
			//Serial.println(nbrLedFade);							// Ex : 26 (pour 2.6)
			
			int reste;											// Reste de la division entière
			reste=nbrLedFade%10;								// Ex : 6
			//Serial.println(reste);		
				
			nbrLedFade/=10;										// On repasse à la valeur réelle
			//Serial.println(nbrLedFade);							// Ex : 2
			
			/*//*/if(reste!=0){nbrLedFade+=1;}					// Ajustement de la valeur par excès
			//Serial.println(nbrLedFade);							// Ex : 3
			
			// => A ce stade, on connaît le nbr exact de led allumée sur le ségments.
	
		//-- On Calcule l'atténuation totale en rouge
			//Serial.println("FADE ROUGE------");
			int deltaFadeR=0;				// Par défaut, elle est nulle
			int deltaFadeG=0;				// Par défaut, elle est nulle
			int deltaFadeB=0;				// Par défaut, elle est nulle
			
			//Serial.print("r : ");
			//Serial.println(r);
			
			//- Si la couleur de fin est -1 alors, il n'y a pas de changement à opérer
			if(endR==-1){endR=r;}
			if(endG==-1){endG=g;}
			if(endB==-1){endB=b;}
			//Serial.print("endR : ");
			//Serial.println(endR);
			
			deltaFadeR =r-endR;		        // Amplitude de la modification en rouge (entre début et fin de section)
			deltaFadeG =g-endG;
			deltaFadeB =b-endB;
			//Serial.print("deltaFadeR total : ");
			//Serial.println(deltaFadeR);		// Ex : 1000

			deltaFadeR/=(nbrLedFade-1);		// Saut en rouge
			deltaFadeG/=(nbrLedFade-1);		// Saut en vert
			deltaFadeB/=(nbrLedFade-1);		// Saut en bleu
			//Serial.print("deltaFadeR par pas : ");
			//Serial.println(deltaFadeR);		// Ex : 250
				
	
	//--- On prépare les pixels
		uint16_t 	curseurPixel;			// Led à traiter
		uint16_t	ampR;					// Quantité de rouge
		uint16_t	ampG;					
		uint16_t	ampB;					
		
	//-- On détermine l'adresse de la première Led (StratLed peut être très grand)
		uint16_t effectiveStartLed;
		if(startLed<m_nbrOfLed){
			//- Pas de calcul à faire
				effectiveStartLed=startLed;
		}
		else{
			//- Il faut retirer la partie entière
				effectiveStartLed=startLed%m_nbrOfLed;
				//Serial.println(effectiveStartLed);
		}		

		
		for(int i=0;i<nbrLedFade;i++){ 
			//-- On détermine le n° de la Led concernée 
				curseurPixel = effectiveStartLed + i*step;
				if(curseurPixel>=m_nbrOfLed){
					curseurPixel=(effectiveStartLed + i*step)-m_nbrOfLed;
				}
			//-- On calcule les couleurs
				ampR = r-(i*deltaFadeR);							
				ampG = g-(i*deltaFadeG);
				ampB = b-(i*deltaFadeB);
			
			//--- Actualisation des réglages
				setPixelColor1000(curseurPixel, ampR, ampG, ampB,_leds);
		}
}//*/

/*EDU US*/ void setPixelColor1000( uint16_t n, uint16_t r, uint16_t g, uint16_t b,CRGB* _leds){
	//-- On ajuste les valeurs à 255 max
		r/=4; g/=4; b/=4;
		//RgbColor Color(r,g,b);
		//SetPixelColor(n,Color);
		_leds[n]= CRGB( r, g, b);
		//leds[20]= CRGB( 255, 68, 0);
		Serial.print(n);
		Serial.print(" ");
		Serial.print(r);
		Serial.print(" ");
		Serial.print(g);
		Serial.print(" ");
		Serial.print(b);
		Serial.print(" ");
		
}

/*EDU FR*/ void preparerPixel(uint16_t startLed, uint16_t r, uint16_t g, uint16_t b, uint16_t widthGroupe, uint8_t step, int16_t endR,int16_t endG,int16_t endB, int16_t dep,CRGB* _leds){
	
	// Variable utilisée pour vérifier s'il est nécessaire de mettre à jour le ruban
		bool updateNecessaryFlag=true;		
	
	// dep : déplacement 0 à 1000 (0..500 = dans 1 sens / 500..1000 = dans l'autre sens)
	//-- On limte la valeur de vitesse (issue par exemple d'un capteur)
		if(dep>1000) dep=1000; 
		if(dep<-1000)dep=-1000;


	//-- On calcule un curseur
		int cur = millis()*(dep)/2000;		// Donne un rythm au déplacement 1,2,3...

	// On calcule l'adrese de début du ruban
			uint16_t startIndex = (startLed+cur)%m_nbrOfLed;			//%m_nbrOfLed permet de ne jamais dépasser la taille du ruban
	
	//-- Si aucun changement => on baisse le flag
		if(startIndex==m_startIndex && r==m_r && g==m_g && b==m_b && widthGroupe==m_widthGroupe && step==m_step && endR==m_endR && endG==m_endG && endB==m_endB ){
			//Serial.println("IDEM");
			updateNecessaryFlag = false;
		}
	
	//-- Si un changement détecté 
		if(updateNecessaryFlag){
			//- On met à jour le context
				m_startIndex=startIndex;
				m_r=r;
				m_g=g;
				m_b=b;
				m_widthGroupe=widthGroupe;
				m_step=step;
				m_endR=endR;
				m_endG=endG;
				m_endB=endB;
		}
		
	
	//-- On gère la préparation du nouveau segment et l'enregistrement dans le tableau memory
		//- On actualise le tableau memory (effacé par show())
			// On calcule une adresse de fin. Si l'adresse de fin est au dela la la fin du ruban, on enlève la largeur du ruban
				uint16_t endIndex   = startIndex+widthGroupe;
			
			// Cas où l'index de fin déborde >>>[1111E0000000S1111] S=stratIndex E=endIndex
			if(endIndex>m_nbrOfLed){
				//- On ajuste le endIndex 
					endIndex-=m_nbrOfLed;
				//- On enregistre la partie S1111 du ruban
					for(uint16_t j=startIndex; j<m_nbrOfLed; j+=step){
						saveBit(1,j,memory);
					}
				//- On enregistre la partie 1111E du ruban
					for(uint16_t j=0; j<endIndex; j+=step){
						saveBit(1,j,memory);
					}
			}
			// Cas où il n'y a pas débordement >>>[S111E00000000000] S=stratIndex E=endInde
			else{
				//- On enregistre tout le segment S111E
					for(uint16_t j=startIndex; j<endIndex; j+=step){
						saveBit(1,j,memory);
					}
			}
			

					
		//- On fait la préparation effective du ruban si besoin
			if(updateNecessaryFlag){
				//Serial.println("UP");
				preparerPixel(startIndex, r ,g ,b ,widthGroupe,step ,endR ,endG ,endB, _leds );
			}
}

/*EDU US*/	void saveBit(bool value, uint16_t place, byte *tab){
// Permet de placer un bit unique dans un tableau de byte (divise / 8 la place nécessaire)

	//---- Calcul de l'index du tableau réel
		uint16_t indexTab;
		indexTab = place/8;	
	
	//---- Calcul de l'emplacement du bit dans le mot
		uint8_t indexBit;
		indexBit = place%8;
	
	//---- Sauvegarde du bit sans toucher aux autres
		//-- On récupère le mot concerné
			uint8_t word = memory[indexTab];
		//-- On force le seul bit concerné	
			if(value==1) {
				word |= B00000001<<indexBit ;
				//bitSet(word,indexTab);
				memory[indexTab]=word;		
			}else{
				word &= ~(B00000001<<indexBit);
				//bitClear(word,indexTab);
				memory[indexTab]=word;		
			}	
}

/*EDU US*/	bool readBit(uint16_t place, byte *tab){
// Permet de placer un bit unique dans un tableau de byte (divise / 8 la place nécessaire)	
	
	//---- Calcul de l'index du tableau réel
		uint16_t indexTab;
		indexTab = place/8;	
	
	//---- Calcul de l'emplacement du bit dans le mot
		uint8_t indexBit;
		indexBit = place%8;
		
	//---- Lecture du bit
		//-- On récupère le mot concerné
			uint8_t	word = memory[indexTab];
		//-- On teste la valeur du bit en question	
			if(bitRead(word,indexBit)==1){
				return true;
			}else{
				return false;
			}
}
	protected:
	/*EDU US*/	uint16_t m_nbrOfLed;
			uint16_t 	m_startIndex			;   // Position effective du premier pixel (après calcul) 
			uint16_t 	m_r, m_g, m_b			;
			uint16_t	m_widthGroupe			;
			uint8_t		m_step					;
			uint16_t	m_endR, m_endG,m_endB	;
			byte *memory;			
};
#endif