#include <Arduino.h>

#include <Homie.h>
#include <ArduinoOTA.h>
#include <Adafruit_NeoPixel.h>
#include "NeoPatterns.h"

#define PIN            D1
#define SENSOR         D0
#define NUMPIXELS      80



bool lastSensorValue = false;

void StripComplete(){
        return;
}

NeoPatterns pixels = NeoPatterns(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800,&StripComplete);

HomieNode stripNode("strip", "strip");
HomieNode sensorNode("sensor", "sensor");
Bounce debouncer = Bounce();


bool onSetColor(const HomieRange& range, const String& value){
        if (!range.isRange || range.index < 0 || range.index > 1) {
                return false;
        }
        switch(range.index) {
        case 0:
                pixels.SetColor1(value.toInt());
                break;
        case 1:
                pixels.SetColor2(value.toInt());
                break;
        }
        stripNode.setProperty("color_" + String(range.index)).send(value);
}




bool onSetPixel(const HomieRange& range, const String& value){
        if(!range.isRange) {
                pixels.None();
                pixels.ColorSet(value.toInt());
                stripNode.setProperty("pixel").send(value);
                return true;
        }
        if (range.index < 0 || range.index > pixels.numPixels()-1) {
                return false;
        }
        pixels.None();
        pixels.setPixelColor(range.index, value.toInt());
        pixels.show();
        stripNode.setProperty("pixel_" + String(range.index)).send(value);
}

bool onSetBrightness(const HomieRange& range, const String& value){
        long brightness= value.toInt();
        if (brightness < 0 || brightness > 255) {
                return false;
        }
        pixels.setBrightness(brightness);
        pixels.show();
        stripNode.setProperty("brightness").send(value);
}

bool onSetEffect(const HomieRange& range, const String& value){
        String effect = value;
        effect.toLowerCase();
        if(effect == "scanner") {
                pixels.Scanner(pixels.Color(255, 0, 0));
        }
        else if(effect == "randomscanner") {
                pixels.Scanner(pixels.Color(255, 0, 0), 40, true);
        }
        else if(effect == "rainbowcycle") {
                pixels.RainbowCycle(50);
        }
        else if(effect == "theaterchase") {
                pixels.TheaterChase(pixels.Color(255, 0, 0), pixels.Color(0,0,255), 100);
        }
        else if(effect == "fade") {
                pixels.Fade(pixels.Color(255, 0, 0), pixels.Color(0,0,255), 200, 100);
        }
        else if(effect == "randomfade") {
                pixels.RandomFade();
        }
        else {
                pixels.None();
        }
        stripNode.setProperty("effect").send(value);
}

bool onSetClear(const HomieRange& range, const String& value){
        pixels.None();
        pixels.clear();
        pixels.show();
        stripNode.setProperty("clear").send(value);
}

bool onSetLength(const HomieRange& range, const String& value){
        pixels.None();
        pixels.clear();
        pixels.show();
        int newLength = value.toInt();
        if(newLength > 0) {
                pixels.updateLength(newLength);
        }
        stripNode.setProperty("length").send(value);
}

void loopHandler() {
        pixels.Update();

        bool sensorValue = debouncer.read();
        if (Homie.isConfigured() && Homie.isConnected() && sensorValue != lastSensorValue) {
                sensorNode.setProperty("motion").send(sensorValue ? "true" : "false");
                lastSensorValue = sensorValue;
        }

}

void setup() {
        Serial.begin(115200);

        debouncer.attach(SENSOR,INPUT);
        debouncer.interval(50);

        Homie_setFirmware("schild", "1.0.0");
        Homie.setLoopFunction(loopHandler);

        stripNode.advertiseRange("pixel", 0, NUMPIXELS-1).settable(onSetPixel);
        stripNode.advertiseRange("color", 0, 1).settable(onSetColor);
        stripNode.advertise("brightness").settable(onSetBrightness);
        stripNode.advertise("effect").settable(onSetEffect);
        stripNode.advertise("clear").settable(onSetClear);
        stripNode.advertise("length").settable(onSetLength);

        sensorNode.advertise("motion");

        pixels.begin();
        pixels.clear();
        pixels.setBrightness(64);
        pixels.show();

        Homie.setup();

        ArduinoOTA.setHostname(Homie.getConfiguration().deviceId);
        ArduinoOTA.setPassword((const char *)"ctdo2342");
        ArduinoOTA.onStart([]() {
                pixels.clear();
        });
        ArduinoOTA.onEnd([]() {
                pixels.clear();
        });
        ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
                pixels.setPixelColor(progress / (total / NUMPIXELS), pixels.Color(100, 0, 0));
                pixels.show();
        });
        ArduinoOTA.begin();
}

void loop() {
        Homie.loop();
        debouncer.update();
        ArduinoOTA.handle();
}
