#include <lilParser.h>
#include <neoPixel.h>
#include <strTools.h>


// Our list of commands beginning with.. noCommand.
enum commands {
   noCommand,  // Used to pass zero values by when parsing.
   setColor,   // set the inputted color to the LEDs
   getColor,   // Read and repirt the LEDs color.
   blend       // Blend the inputted color with the LEDs.
};

lilParser   ourParser(40);   // The guy that we're showing off.
neoPixel    ourRing(12,2);   // Some neoPixles to show off with.

void setup() {
   
   ourRing.begin();                             // Fire up neoPixle stuff.
   ourRing.setAll(&black);                      // Set all to black. (off)
   ourRing.show();                              // Turn them all off.
                                                //
   ourParser.addCmd(setColor,"setcolor");       // Set up the command list. 
   ourParser.addCmd(getColor,"getcolor");       //
   ourParser.addCmd(blend,"blend");             //
                                                //
   Serial.begin(57600);                         // Fire up the Serial stuff..
   Serial.println();                            // Give the user a hint.
   Serial.println("Type ? for command list.");  //
}


void loop() {
   
   char  inChar;
   int   command;
   
   if (Serial.available()) {                        // If serial has some data..
      inChar = Serial.read();                       // Read out a charactor.
      Serial.print(inChar);                         // *Optional* echo the charactor.
      command = ourParser.addChar(inChar);          // Try parsing what we have.
      switch (command) {                            // Check the results.
         case noCommand : break;                    // Nothing to report, move along.
         case setColor  : doSetColor();   break;    // Call the handler function for setColor
         case getColor  : doGetColor();   break;    // Call the handler function for getColor
         case blend     : doBlend();      break;    // And this one too.
         case -2        : Serial.println("Config error. Parser could not start.");
         case -3        : Serial.println("Param error. Paramiter buffer was too small.");
         default        : showList();     break;   // No idea. Show list.
      }
   }
}


void showList(void) {

   Serial.println();
   Serial.println("                  Command list");
   Serial.println("               ----------------------");
   Serial.println("setcolor R G B  : RGB 1 byte values to set the ring colors.");
   Serial.println("setcolor COLOR  : Sets color to the name string if it can.");
   Serial.println("getcolor        : Prints out the current color.");
   Serial.println("blend R B G %   : Blends this color into the original by specified %.");
   Serial.println("blend COLOR %   : Blends this color into the original by specified %.");
   Serial.println();
}


// Given a string representation of a number. pass back
// the best fitting one byte value for it.
byte textToByte(char* inNum) {

   int value;
   
   value = atoi(inNum);          // Inturprit it as an integer.
   if (value<0) return 0;        // Negitives are zero.
   if (value>255) return 255;    // 255 is max value.
   else return (byte)value;      // everything else? Fine.
}


void doSetColor(void) {

   int      numParams;
   byte     r;
   byte     g;
   byte     b;
   char*    colorText;
   colorObj ourColor;


   numParams = ourParser.numParams();                                   // Save the number of parameters.
   if (numParams == 3) {                                                // If we have 3 parameters..
      r = textToByte(ourParser.getNextParam());                         // Grab red value.
      g = textToByte(ourParser.getNextParam());                         // Grab green.
      b = textToByte(ourParser.getNextParam());                         // Grab blue.
      ourColor.setColor(r,g,b);                                         // Setup this color.
      ourRing.setAll(&ourColor);                                        // Set all the LEDs to this color.
      ourRing.show();                                                   // Let the user see what we did.
   } else if (numParams == 1) {                                         // Else, we only have one parameter..
      colorText = ourParser.getParamBuff();                             // Grab it all as a string..
      if (!strcmp("red",colorText)) ourRing.setAll(&red);               // Is it.. "red"?
      else if (!strcmp("blue",colorText)) ourRing.setAll(&blue);        // Is it.. "blue"?
      else if (!strcmp("white",colorText)) ourRing.setAll(&white);      // You get the pattern..
      else if (!strcmp("black",colorText)) ourRing.setAll(&black);      //
      else if (!strcmp("green",colorText)) ourRing.setAll(&green);      //
      else if (!strcmp("cyan",colorText)) ourRing.setAll(&cyan);        //
      else if (!strcmp("magenta",colorText)) ourRing.setAll(&magenta);  //
      else if (!strcmp("yellow",colorText)) ourRing.setAll(&yellow);    //
      else Serial.println("Don't know that color.");                    // Don't know?
      ourRing.show();                                                   // We call show in any case.
  }
}


void doGetColor(void) {

   colorObj  ourColor;
   
   ourColor = ourRing.getPixelColor(0);   // Read the color of the first pixel.
   Serial.print("Current color RGB : ");  // They are all the same, so..
   Serial.print(ourColor.getRed());       // Just pint this out.
   Serial.print(", ");                    //
   Serial.print(ourColor.getGreen());     //
   Serial.print(", ");                    //
   Serial.println(ourColor.getBlue());    //
}


void doBlend(void) {

   int      numParams;
   byte     r;
   byte     g;
   byte     b;
   char*    colorText;
   char*    localColorText;
   byte     percent;
   colorObj ourColor;
   colorObj blendColor;

   localColorText = NULL;                                                           // We always start stuff at NULL.
   ourColor = ourRing.getPixelColor(0);                                             // Grab the current color.
   numParams = ourParser.numParams();                                               // Save number of params.
   if (numParams == 4) {                                                            // If we got 4 params..
      r = textToByte(ourParser.getNextParam());                                     // First three are RGB
      g = textToByte(ourParser.getNextParam());                                     //
      b = textToByte(ourParser.getNextParam());                                     //
      percent = textToByte(ourParser.getNextParam());                               // Number 4 is percent.
      blendColor.setColor(r,g,b);                                                   // Fill in our blending color.
      ourColor.blend(&blendColor,percent);                                          // Do the blend.
   } else if (numParams == 2) {                                                     // Else if we got 2 params..
      colorText = ourParser.getNextParam();                                         // Grab the first param.
      heapStr(&localColorText,colorText);                                           // But wait! We need a copy because..
      percent = textToByte(ourParser.getNextParam());                               // Grabbing the next would clear the string we got.
      if (!strcmp("red",localColorText)) ourColor.blend(&red,percent);              // Is it "red"?
      else if (!strcmp("blue",localColorText)) ourColor.blend(&blue,percent);       // "blue"?
      else if (!strcmp("white",localColorText)) ourColor.blend(&white,percent);     // "black"?
      else if (!strcmp("black",localColorText)) ourColor.blend(&black,percent);     // And so on..
      else if (!strcmp("green",localColorText)) ourColor.blend(&green,percent);     //
      else if (!strcmp("cyan",localColorText)) ourColor.blend(&cyan,percent);       //
      else if (!strcmp("magenta",localColorText)) ourColor.blend(&magenta,percent); //
      else if (!strcmp("yellow",localColorText)) ourColor.blend(&yellow,percent);   //
      else Serial.println("No color match?");                                       // Again with the odd color names..
      freeStr(&localColorText);                                                     // Free the local string.
   }                                                                                //
   ourRing.setAll(&ourColor);                                                       // Whatever we ended up with, set the LEDs with it.
   ourRing.show();                                                                  // And show the user the result.
}