#ifndef LEDSTRIP_H
#define LEDSTRIP_H

//#include <Arduino.h>
#include "LEDStrip.h"
#include <stdint.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_intr_alloc.h"

#define HIGH_RES_BIT_RATE 0

#if(HIGH_RES_BIT_RATE == 1)
  #define PIXEL_SIZE (8*3)
  #define SAMPLE_RATE (360000) // 1.6us cycle 
  #define RESET_BUFFER_SIZE (100 * PIXEL_SIZE) // led latching timeout 300us mininum (50us older chips)
#else
  // This can be set to 1 (normally 50) as long at the update freq isn't fast enough to interfere with the required reset length time
  // This reduces memory requirements
  #define RESET_PIXELS 1
  #define PIXEL_SIZE (4*3)// each colour takes 4 bytes and 3 colors per pixel
  #define SAMPLE_RATE (160000) // 1.6us cycle
  #define RESET_BUFFER_SIZE (RESET_PIXELS * PIXEL_SIZE) // led latching timeout 4 or more pixel lengths
#endif

#define I2S_TX_DMA_BUFF_SIZE 128 // smaller buffer means it will start quicker

typedef struct{
  uint8_t red;
  uint8_t grn;
  uint8_t blu;
} rgbpixel_t;

enum LED_DIR{DIR_REV, DIR_FWD};

enum LED_ORDER{ORDER_RGB, ORDER_RBG, ORDER_GRB, ORDER_GBR, ORDER_BRG, ORDER_BGR};

LED_ORDER getRGBOrder(const char* order);

void PixelFadeToBlack(rgbpixel_t& pix, uint8_t fadeValue);

void scalePixel(rgbpixel_t& pix, uint8_t _scale);
void linearizePixel(rgbpixel_t& pix);
//rgbpixel_t scalePixel(rgbpixel_t pix, uint8_t _scale);

//void i2sDmaInterruptHandler(void *arg);

class LEDSTRIP {
  public:
    SemaphoreHandle_t i2sSemaphore;
    int effSize;
    int size;
    int shift;
    int offset;
    int powerDiv = 0;
    LED_ORDER ledOrder;
    rgbpixel_t* pixels;
    QueueHandle_t i2sEventQueue;

    LEDSTRIP(int port, int size, int pin, LED_ORDER ledOrder, int shift=0, int offset=0);
    // process buffer before sending
    void updateBuff(void);
    // Send data to dma and I2S port
    void show(bool update=true);

    void setPixel(int index, rgbpixel_t& col);
    void setPixel(int index, const rgbpixel_t col);
    void setPixel(int index, rgbpixel_t& col, uint8_t scale=255);
    //void setPixelTrueHue(int index, int hueAngle);
    //void setPixelPowerHue(int index, int hueAngle);
    //void setPixelSineHue(int index, int hueAngle);
    void setPixelRaw(int index, rgbpixel_t& col);

    void setPixelMirrored(int index, rgbpixel_t col);
    rgbpixel_t getPixel(int index);

    //void scale(rgbpixel_t& pix, uint8_t _scale);
    void fill(rgbpixel_t color, int startIndex, int count);
    void fade(rgbpixel_t& col);
    void zeroPixels(void);
    //void setMirrored(void);

    // mirror pixels about the shift position
    void rotatePixels(LED_DIR dir);
    void shiftPixels(int numPixels, LED_DIR dir);
    void transitionPixel(int index, rgbpixel_t& newCol, uint8_t factor);
    //rgbpixel_t hueToRGB(uint8_t hue, uint8_t sat, uint8_t val);

    void setPowerDiv(uint8_t div);


  private:
    static int instanceCount; //number in class instances

    int port;


    //intr_handle_t  i2sInterruptHandle;

    int dma_frame_size;
    // dma output buffer
    uint8_t* out_buffer;
    int out_buffer_size;
    // pointer to actual active part of buffer
    uint8_t* active_out_buffer;
    // index position calculation
    uint8_t* reset_buffer;
    void i2s_write_data(const void *data, size_t size);
    int calcIndex(int ind);

};

//void IRAM_ATTR i2s0DmaTransmitComplete(void* arg);
//void IRAM_ATTR i2s1DmaTransmitComplete(void* arg);

#endif
