#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <Adafruit_NeoPixel.h>
#include <user_interface.h>

#define NUM_PIXELS 20
Adafruit_NeoPixel pixels(NUM_PIXELS, D2, NEO_GRB | NEO_KHZ800);

MDNSResponder mdns;

os_timer_t osTimer;

// network credentials
const char* ssid     = "ssid";
const char* password = "password";

// amber      FFC200 = color 00
// orange     FFA500 = color 01
// vermillion E34234 = color 02
// red        FF0000 = color 03
// magenta    FF00FF = color 04
// purple     800080 = color 05
// indigo     4B0082 = color 06
// blue       0000FF = color 07
// aquamarine 7FFFD4 = color 08 
// green      00FF00 = color 09
// chartreuse 7FFF00 = color 10
// yellow     FFFF00 = color 11
// off        000000 = color 12 // deselect all other colors

int R[13] = {255,255,227,255,255,128,075,000,127,000,127,255,000};
int G[13] = {194,165,066,000,000,000,000,000,255,255,255,255,000};
int B[13] = {000,000,052,000,255,128,130,255,212,000,000,000,000};
int countColors = 0;
int numColors = 12;

// Buttons text colors and initial values
String buttonColor [2] = {"white", "black"};
boolean ColorState [13] = {1,1,1,1,1,1,1,1,1,1,1,1,1}; // initial colors
boolean buttonSparkle  = 1; 
boolean buttonBrighter = 1; 
boolean buttonFaster   = 1;
boolean buttonDarker   = 1;
boolean buttonSlower   = 1; 
boolean buttonReset    = 1; 

int brightValue = 4;
int brightMax   = 16; // brightness (1..16)

int waitTimes [16]= {50, 100, 150, 200, 250, 500, 750, 1000, 1500, 2000, 2500, 3000, 5000, 10000, 30000, 60000}; // millis()
int waitTime     = 5; // default values
int lastColor    = 0;
int foundColor   = 0;
int currentColor = 0;
int beginSparkle = 0;
int currentLed   = 0;

ESP8266WebServer server(80);

String webPage = "";

void setColor(int Rs, int Gs, int Bs) 
{
   for (int i = 0; i < NUM_PIXELS; i++) 
   {
      pixels.setPixelColor (i, (Rs * brightValue)/brightMax, (Gs * brightValue)/brightMax, (Bs * brightValue)/brightMax);
   }
   pixels.show();
}

int nextColor (int lastColor)
{
   foundColor = numColors; // nothing found return value
   countColors = 0;        // count number of searches inside the loop

   do
   { 
      currentColor += 1;
      countColors  += 1;
      if (currentColor>numColors)   {currentColor=0;}
      if (ColorState[currentColor]) {foundColor=currentColor;}
   } 
   while (currentColor != lastColor && foundColor == numColors && countColors < numColors+1);
   return (foundColor);
}

// interrupt os-timer
void timerCallback(void *pArg) 
{   
   if (!buttonSparkle)
   {
      // Sparkle Off
      currentColor = nextColor (lastColor);
      if (lastColor != currentColor)
      {
         setColor (R[currentColor], G[currentColor], B[currentColor]);
         lastColor = currentColor;
      }
   }
   else
   {
      // Sparkle
      beginSparkle += 1;                            // Startposition for first color
      if (beginSparkle>numColors-1) {beginSparkle=0;}
      
      currentColor = 0;                             // Begin with first color in array
      for (int x = 0; x < NUM_PIXELS; x++) 
      {
         currentColor = nextColor (lastColor);
         lastColor = currentColor;
         currentLed = beginSparkle + x;
         if (currentLed >= NUM_PIXELS) 
         {
            currentLed = currentLed - NUM_PIXELS;

         }
      pixels.setPixelColor (currentLed, (R[currentColor] * brightValue)/brightMax, (G[currentColor] * brightValue)/brightMax, (B[currentColor] * brightValue)/brightMax);
      }
      pixels.show();
   }
} 

void showPage() 
{
   webPage  = "<h2>Gosse Adema</h2>";                                                                                                                   
   webPage += "<p><a href=\"socketAmb\"><button style=\"background:#FFC200;font-size:200%;width:33%;padding:3%;color:" + buttonColor [ColorState[0]]  + "\">amber     </button></a>";   
   webPage += "   <a href=\"socketOra\"><button style=\"background:#FFA500;font-size:200%;width:33%;padding:3%;color:" + buttonColor [ColorState[1]]  + "\">orange    </button></a>";   
   webPage += "   <a href=\"socketVer\"><button style=\"background:#E34234;font-size:200%;width:33%;padding:3%;color:" + buttonColor [ColorState[2]]  + "\">vermillion</button></a>";   
   webPage += "   <a href=\"socketRed\"><button style=\"background:#FF0000;font-size:200%;width:33%;padding:3%;color:" + buttonColor [ColorState[3]]  + "\">red       </button></a>";  
   webPage += "   <a href=\"socketMag\"><button style=\"background:#FF00FF;font-size:200%;width:33%;padding:3%;color:" + buttonColor [ColorState[4]]  + "\">magenta   </button></a>";   
   webPage += "   <a href=\"socketPur\"><button style=\"background:#800080;font-size:200%;width:33%;padding:3%;color:" + buttonColor [ColorState[5]]  + "\">purple    </button></a>";   
   webPage += "   <a href=\"socketInd\"><button style=\"background:#4B0082;font-size:200%;width:33%;padding:3%;color:" + buttonColor [ColorState[6]]  + "\">indigo    </button></a>";   
   webPage += "   <a href=\"socketBlu\"><button style=\"background:#0000FF;font-size:200%;width:33%;padding:3%;color:" + buttonColor [ColorState[7]]  + "\">blue      </button></a>";   
   webPage += "   <a href=\"socketAqu\"><button style=\"background:#7FFFD4;font-size:200%;width:33%;padding:3%;color:" + buttonColor [ColorState[8]]  + "\">aquamarine</button></a>";   
   webPage += "   <a href=\"socketGre\"><button style=\"background:#00FF00;font-size:200%;width:33%;padding:3%;color:" + buttonColor [ColorState[9]]  + "\">green     </button></a>";   
   webPage += "   <a href=\"socketCha\"><button style=\"background:#7FFF00;font-size:200%;width:33%;padding:3%;color:" + buttonColor [ColorState[10]] + "\">chartreuse</button></a>";   
   webPage += "   <a href=\"socketYel\"><button style=\"background:#FFFF00;font-size:200%;width:33%;padding:3%;color:" + buttonColor [ColorState[11]] + "\">yellow    </button></a>";   
   webPage += "   <a href=\"socketBri\"><button style=\"background:#7F7F7F;font-size:200%;width:33%;padding:3%;color:" + buttonColor [buttonBrighter] + "\">brighter  </button></a>";   
   webPage += "   <a href=\"socketFas\"><button style=\"background:#7F7F7F;font-size:200%;width:33%;padding:3%;color:" + buttonColor [buttonFaster]   + "\">faster    </button></a>";   
   webPage += "   <a href=\"socketSpa\"><button style=\"background:#7F7F7F;font-size:200%;width:33%;padding:3%;color:" + buttonColor [buttonSparkle]  + "\">sparkle   </button></a>";   
   webPage += "   <a href=\"socketDar\"><button style=\"background:#7F7F7F;font-size:200%;width:33%;padding:3%;color:" + buttonColor [buttonDarker]   + "\">darker    </button></a>";   
   webPage += "   <a href=\"socketSlo\"><button style=\"background:#7F7F7F;font-size:200%;width:33%;padding:3%;color:" + buttonColor [buttonSlower]   + "\">slower    </button></a>";   
   webPage += "   <a href=\"socketRes\"><button style=\"background:#7F7F7F;font-size:200%;width:33%;padding:3%;color:" + buttonColor [buttonReset]    + "\">reset     </button></a></p>";

   server.send(200, "text/html", webPage);
   yield (); 
}

void setup(void){

   // neopixel
   pixels.begin();
   pixels.show();
   setColor(4,4,4); // wait for IP

   // preparing GPIOs
   delay(1000);
   Serial.begin(115200);
   WiFi.begin(ssid, password);
   Serial.println("");

   // Wait for connection
   while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
   }
   Serial.println("");
   Serial.print("Connected to ");
   Serial.println(ssid);
   Serial.print("IP address: ");
   Serial.println(WiFi.localIP());

   // timer
   os_timer_setfn (&osTimer, timerCallback, NULL);
   os_timer_arm   (&osTimer, waitTimes[waitTime], true);

   server.on ("/", [](){showPage(); });
   server.on ("/socketAmb", [](){ColorState [0]  = !ColorState [0];  showPage(); });
   server.on ("/socketOra", [](){ColorState [1]  = !ColorState [1];  showPage(); });
   server.on ("/socketVer", [](){ColorState [2]  = !ColorState [2];  showPage(); });
   server.on ("/socketRed", [](){ColorState [3]  = !ColorState [3];  showPage(); });
   server.on ("/socketMag", [](){ColorState [4]  = !ColorState [4];  showPage(); });
   server.on ("/socketPur", [](){ColorState [5]  = !ColorState [5];  showPage(); });
   server.on ("/socketInd", [](){ColorState [6]  = !ColorState [6];  showPage(); });
   server.on ("/socketBlu", [](){ColorState [7]  = !ColorState [7];  showPage(); });
   server.on ("/socketAqu", [](){ColorState [8]  = !ColorState [8];  showPage(); });
   server.on ("/socketGre", [](){ColorState [9]  = !ColorState [9];  showPage(); });
   server.on ("/socketCha", [](){ColorState [10] = !ColorState [10]; showPage(); });
   server.on ("/socketYel", [](){ColorState [11] = !ColorState [11]; showPage(); });
   server.on ("/socketBri", [](){brightValue += 1; 
                                 buttonDarker = 1; 
                                 if (brightValue>=16){brightValue=16;
                                                      buttonBrighter=0;}
                                 showPage();  });
   server.on ("/socketFas", [](){waitTime -= 1;
                                 buttonSlower = 1; 
                                 if (waitTime<=0){waitTime=0;
                                                  buttonFaster=0;} 
                                 os_timer_arm (&osTimer, waitTimes[waitTime], true);
                                 showPage(); });
   server.on ("/socketSpa", [](){buttonSparkle = !buttonSparkle;
                                 showPage(); });
   server.on ("/socketDar", [](){brightValue -= 1; 
                                 buttonBrighter = 1;
                                 if (brightValue<=1){brightValue=1;
                                                     buttonDarker = 0;}
                                 showPage(); });
   server.on ("/socketSlo", [](){waitTime += 1;
                                 buttonFaster=1;
                                 if (waitTime>=15){waitTime=15;
                                                   buttonSlower=0;} 
                                 os_timer_arm (&osTimer, waitTimes[waitTime], true);
                                 showPage(); });

   server.on ("/socketRes", [](){brightValue = 4;
                                 waitTime = 5;
                                 os_timer_arm(&osTimer, waitTimes[waitTime], true);

                                 buttonSparkle  = 1;
                                 buttonBrighter = 1;
                                 buttonFaster   = 1;
                                 buttonDarker   = 1;
                                 buttonSlower   = 1; 
    
                                 showPage (); });

   server.begin();
   Serial.println("HTTP server started");
}

void loop(void)
{
   server.handleClient();
}
