#include <ArtnetWifi.h>
#include <Arduino.h>
#include <FastLED.h>



const int numLeds = 120; // CHANGE FOR YOUR SETUP
// Wifi settings
const char* ssid = "Fahnenlan";
const char* password = "Fahnenschlaeger";
IPAddress local_IP(192, 168, 1, 109);
const int startUniverse = 9; // CHANGE FOR YOUR SETUP most software this is 1, some software send out artnet first universe as 0.



IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);

// LED settings
const int numberOfChannels = numLeds * 3; // Total number of channels you want to receive (1 led = 3 channels)
const byte dataPin = 3;
CRGB leds[numLeds];
CRGB ledsbuff[numLeds];
CRGB ledsout[numLeds];
const int topled = 1;
long lastMillis;
long currentMillis;
long interval;
bool flicker;
bool flickerOnOff;

// Art-Net settings
ArtnetWifi artnet;

// Check if we got all universes
const int maxUniverses = numberOfChannels / 512 + ((numberOfChannels % 512) ? 1 : 0);
bool universesReceived[maxUniverses];
bool sendFrame = 1;


// connect to wifi – returns true if successful or false if not
bool ConnectWifi(void)
{
    bool state = true;
    int i = 0;

    WiFi.config(local_IP,gateway,subnet);
    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED)
    {
    delay(500);

    if (i > 20)
    {
        state = false;
        break;
    }
    i++;
    }

    return state;
}

void initTest()
{
    for (int i = 0 ; i < numLeds ; i++)
    {
    leds[i] = CRGB(127, 0, 0);
    }
    FastLED.show();
    delay(500);
    for (int i = 0 ; i < numLeds ; i++)
    {
    leds[i] = CRGB(0, 127, 0);
    }
    FastLED.show();
    delay(500);
    for (int i = 0 ; i < numLeds ; i++)
    {
        leds[i] = CRGB(0, 0, 127);
    }
    FastLED.show();
    delay(500);
    for (int i = 0 ; i < numLeds ; i++)
    {
        leds[i] = CRGB(0, 0, 0);
    }
    FastLED.show();
}

void showing() {
    FastLED.show();
    // Reset universeReceived to 0
    memset(universesReceived, 0, maxUniverses);
}

void onDmxFrame(uint16_t universe, uint16_t length, uint8_t sequence, uint8_t* data)
{
    // check if all frames are received yet, if false no output, waiting for next frame
    sendFrame = 1;
    
    // range check
    // if universe is under startuniverse break
    if (universe < startUniverse)
    {
        return;
    }
    // when more universes received than wanted break
    uint8_t index = universe - startUniverse;
    if (index >= maxUniverses)
    {
        return;
    }

    // Store which universe has got in
    universesReceived[index] = true;
    
    //loop over all Universes 
    for (int i = 0 ; i < maxUniverses ; i++)
    { 
        if (!universesReceived[i])
    {
        sendFrame = 0;
        break;
    }
    }

     // read universe and put into the right part of the display buffer
    for (int i = 0; i < length / 3; i++)
    {
        int led = i + (index * 170);
        if (led < numLeds)
        {
        leds[led] = CRGB(data[i * 3], data[i * 3 + 1], data[i * 3 + 2]);
        }
    }

    switch (data[numLeds]*3)
    {
    case 0:
        interval = 0;
        break;
    case 1 ... 50:
        interval = 50;
        break;
    case 51 ... 255:
        interval = data[numLeds] *3;
        break;
    }

    if (sendFrame) {
        for (int i = 0; i < numLeds; i++) {
            ledsbuff[i] = leds[i];
            ledsout[i] = leds[i];
        }
    }
    
    if (interval == 0 && sendFrame) {
        showing();
        sendFrame = false;
    }

}


void setup()
{
    ConnectWifi();
    artnet.begin();
    FastLED.addLeds<WS2812, dataPin, GRB>(ledsout, numLeds);
    delay(500);
    initTest();

    memset(universesReceived, 0, maxUniverses);
  // this will be called for each packet received
    artnet.setArtDmxCallback(onDmxFrame);
}

void loop()
{
    currentMillis = millis();
    // we call the read function inside the loop
    artnet.read();

    if (interval != 0 && lastMillis + interval < currentMillis) {
        flickerOnOff = !flickerOnOff;
        lastMillis = currentMillis;

        if (flickerOnOff) {
            for (int i = 0; i < numLeds; i++) {
                ledsbuff[i] = leds[i];
                ledsout[i] = 0;
            }
        } else {
            for (int i = 0; i < numLeds; i++) {
                ledsout[i] = ledsbuff[i];
            }
        }
        showing();
    }




}