#include <Arduino.h>



#define debugger

#define DEBUG 1

#if DEBUG == 1
  #define debug(x) Serial.print(x)
  #define debugln(x) Serial.println(x)
#else
#define debug(x)
#define debugln(x)
#endif

  char serialIn[100]; //Captures initial delimited input
  char pairs[100];
  char call[10][15];
  char action[10][15];

  char plusNumber[2];

  struct KEYWORDS
{
  char *first[5] = {"set","get","reset","clearbuffer","resetesp"};
  char *second[4] = {"function","wifi","led","ble"};
  char *option[8] = {"on","off","up","down","bright","delay","fillall","effect"};
  char *hsv[4] = {"hsv","hue","sat","val"};
  char *rgb[6] = {"rgb","red","green","blue","rgbplus","rgbminus"};
  char *wifi[7] = {"sta","ap","ssid","password","ip","dns","gateway"};
};

struct KEYWORDS k;

void STRCHR() {
  //strchr
    const char str[] = "set:function+1,delay:1,length:10";
    const char serchForColon = ':';
    char *colonIndex;

    colonIndex = strchr(str, serchForColon);
    printf("First colon location is %s\n", colonIndex);

    int colonIndexLength = strlen(colonIndex);
    printf("colonIndexTemp = %i\n", colonIndexLength);

    colonIndexLength = strlen(str) - colonIndexLength;
    colonIndexLength = colonIndexLength + 1;
    printf("Adding 1 to colonIndexTemp %i\n", colonIndexLength);

    colonIndex = strchr(&str[colonIndexLength], serchForColon);

    printf("Second strchr location + 1 return is %s\n", colonIndex);
    printf("\n");
    printf("\n");
    printf("\n");

  }


void STRSTR() {
  //strstr
    char strstrSTR[] = "set:function+1,delay:1,length:10";
    char strstrCH[] = ":";
    char *strstrIndex;
    int strstrResult;

    strstrIndex = strstr(strstrSTR, strstrCH);

    printf("strstr return is %s\n", strstrIndex);

    strstrResult = strlen(strstrIndex);
    printf("strstr return is %i\n", strstrResult);
  }


void STRCPY() {
    char source[] = "set:function+1,delay:1,length:10";
    char dest[50];
    strcpy(dest, source);
    printf("String copied to the destination is: %s\n", dest);

  }

void STRNCPY() {

    char source[] = "set:function+1,delay:1,length:10";
    char dest[50];
  
    int length = strlen(source);
    length = length - 1; // Make room for the terminating char in t5he str

    strncpy(dest, &source[4], length - 3); // Only remove 3 as it stops copying at index before specified

    printf("String copied to the destination is: %s\n", dest);
  }

/*
void STRCSPN(char userInput[75], size_t numChars) {
  char plusSign[] = "+";  //Plus Sign
    char inputSource[] = "set:function,delay:1,length:10";
    char remainder[100];
    char chColon[] = ":";
    char chComma[] = ",";
    char dest[50];
    int counter = 0;
  userInput[numChars] = '\0'; //Add terminating char to end of input
  debugln(" ");
  printf("You entered:   %s\n", userInput); // Print input for review
  debugln(" ");
  int userInputLen = strlen(userInput); //Length of userInput
  
  int plusIndex = strcspn(userInput, plusSign); //Look for "+"
  if(plusIndex != 0) { // If "+" found, capture and remove "+#"" from  input
    //debugln("Plus found");
    strncpy(serialIn, &userInput[0], plusIndex); //Copy input to "+#" > serialIn 

    //debugln("copying userInput to serialIn");
    strcpy(&serialIn[plusIndex], &userInput[plusIndex + 2]);//copy after "+#" > serialIn
      //debugln("Adding 1 to the plusIndex");
    plusIndex = plusIndex + 1;  // Add 1 to get # location afrer the "+"
    strncpy(plusNumber, &userInput[plusIndex], (int)1); // copy the #
    }
  else if(plusIndex == 0) { // No "+" found, copy input to serialIn
    //debugln("Plus not found");
    strcpy(serialIn, userInput);
    }

    size_t inputSize = strlen(serialIn);
    //printf("size of input is %i\n", inputSize);
    
    size_t colonIndex = strcspn(serialIn, chColon); //"set:function,delay:1,length:10" c
                                             //           |        |     | |      |
      //printf(" Index 3 = \"%c\"\n", inputSource[3]);//     3       12    18 20    27
      printf("Colon index = %i\n", colonIndex); // colonIndex = 3 correct

    strcpy(remainder, &serialIn[colonIndex+1]); //Store remainder of string in "remainder"
      printf("Remainder of input %s\n", remainder);

    int remainderLen = strlen(remainder);
    strncpy(call[0], serialIn, colonIndex); 
      printf("call 0 = %s\n", call[0]);

  for(int i = 0; remainderLen > 0; i++)  {
    //colonIndex = colonIndex + 1; 
      //printf("colonIndex = %i\n", colonIndex);


    size_t commaIndex = strcspn(remainder, chComma);
      printf("CommaIndex = %i\n", commaIndex); // 9 = correct

    //size_t commaLen = commaIndex;
        //memset(remainder,0,sizeof(remainder));
    strncpy(action[i], remainder, commaIndex);
      printf("Action[%i] %s\n", i, action[i]);

      //memset(remainder,0,sizeof(remainder));
    strcpy(remainder, &remainder[commaIndex+1]);
    remainderLen = sizeof(remainder);
      printf("Remainder after action %s\n", remainder);

    colonIndex = strcspn(remainder, chColon);
      printf("Colon index = %i\n", colonIndex); 
    
    strcpy(remainder, &remainder[colonIndex]);
      printf("Remainder of input %s\n", remainder);
    remainderLen = strlen(remainder);
      strcpy(call[i+1], )
   
    }
  } 
*/
 

 void STRCSPN(char userInput[75], size_t numChars) {
  char plusSign[] = "+";  //Plus Sign
  char delimiter[] = ";,,";
  char chColon[] = ":";
  char chComma[] = ",";
  char remainder[100];
  int callCounter = 0;
  int actionCounter = 0;

// 1. Find the length of userInput
   userInput[numChars] = '\0'; //Add terminating char to end of input
  size_t userInputLen = strlen(userInput); //Length of userInput

// 2. Check for a + sign  
  int plusIndex = strcspn(userInput, plusSign); 
  //If found, copy the part before he +# and after the +# to serialIn capturing he # in plusNumber
  if(plusIndex < strlen(userInput)) { // If "+" found, capture and remove "+#"" from  input
      debugln("Plus found");
    strncpy(serialIn, &userInput[0], plusIndex); //Copy input to "+#" > serialIn 
      debugln("copying userInput to serialIn");
    strcpy(&serialIn[plusIndex], &userInput[plusIndex + 2]);//copy after "+#" > serialIn
      debugln("Adding 1 to the plusIndex");
    plusIndex = plusIndex + 1;  // Add 1 to get # location afrer the "+"
    strncpy(plusNumber, &userInput[plusIndex], 1); // copy the #
    }
  //If not found copy the input to serialIn    
  else if(plusIndex == 0) { // No "+" found, copy input to serialIn
      debugln("Plus not found");
    strcpy(serialIn, userInput);
    }

// 3. Find the Size of serialIn
    size_t inputSize = strlen(serialIn);
      printf("size of input is %i\n", inputSize);

// 4. Look for one of 5he delimiters , or : and capture it's location in the strint 
  size_t indexNumber = strcspn(serialIn, delimiter);
    printf("IndexNumber %i\n", indexNumber);

    callCounter = 0;
    actionCounter = 0;

  while(indexNumber < strlen(serialIn)) {
    size_t tempIndex;
    debugln("Index number is less than serial In");
    


    for(size_t i = 0; i <= inputSize; i++ ) {
      if(&serialIn[i] == chColon) {
        //if(sizeof(call[0]) < 1 && sizeod(action[0] < 1))
        if(callCounter == 0){
			    strncpy(call[callCounter], serialIn, i);
			      printf("call[%i] = %s\n", callCounter, call[callCounter]);
            }
        else if(callCounter > 0) {
          strncpy(call[callCounter], remainder, indexNumber);
            printf("call[%i] = %s\n", callCounter);
            }
           callCounter++;
      }

            if(&serialIn[i] == chComma) {
              //if(strlen(call[0]) < 1 && strlen(action[0] < 1))
              if(actionCounter == 0){
                  strncpy(action[actionCounter], serialIn, i);
                    printf("Action[%i] = %s\n", actionCounter, action[actionCounter]);
                }
              else if(actionCounter > 0){
                  strncpy(action[actionCounter], remainder, indexNumber);
                    printf("Action[%i] = %s\n", actionCounter, action[actionCounter]);
                }
            actionCounter++;
            }
          indexNumber = i + 1;
          strcpy(remainder, &remainder[indexNumber]);	
			    printf("Remainder = %s\n", remainder);
          tempIndex = i;
          }
         }
       }




char* mystrtok(char* s, char d) {
  // Stores the state of string
  static char* input = NULL;
    // Initialize the input string
  if (s != NULL)
      input = s;
    // Case for final token
  if (input == NULL)
      return NULL;
 
  // Stores the extracted string
  char* result = new char[strlen(input) + 1];
  int i = 0;
 
  // Start extracting string and
  // store it in array
  for (; input[i] != '\0'; i++) {
 
      // If delimiter is not reached
      // then add the current character
      // to result[i]
      if (input[i] != d)
          result[i] = input[i];
 
      // Else store the string formed
      else {
          result[i] = '\0';
          input = input + i + 1;
          return result;
      }
    }
 
  // Case when loop ends
  result[i] = '\0';
  input = NULL;
    // Return the resultant pointer
  // to the string
  return result;
  }
/////
/**
  *_strcmp — A special compare function that compares is sub
  * is aubset of fstring. for example if fstring is “hello”
  * “h”, “he”, … but not “hello” are all subsets and
  * in such a case a 1 will be returned
  *@fstring: fstring
  *@sub: subset
  *Return: 1 on success and -1 on faliur
  */
/////  
int _strcmp(char *fstring, const char *sub) {
   if (!fstring || !sub)
       return (-1);
   if (strlen(fstring) < strlen(sub))
       return (-1);
   while (*sub && *fstring)
   {
      if (*sub != *fstring)
         return (-1);
      sub++, fstring++;
   }
   return (1);
  }
/////  

/**
 * _strtok - tokenizes a string according to a certain delimiter
 * it doesnt creat a new string to hold the tokens but rather creats a
 * a static variable that will directly copy str and puts the null
 * terminator everytime it finds the delimeter, the default str will be
 * manipulated so beware
 * for example if you have a string str = "helo; now; bo"
 * when _strtok is called for the first time (_strtok(str, ";")) it will put
 * \0 (a null terminator in the first location of the delimeter so the str
 * variable will be "helo\0 nowo; bo", ";" and it will be returned and the
 * static variable save would hold " nowo; bo" and when _strtok is called
 * for the second time _strtok(NULL, ";"); the same cyle continue
 * but this time instead of str save will be manipulated. This
 *cycle continues untile save == NULL
 * @str: the string to be tokenized
 * @delimeter: the delimiter to separate tokens
 * Return: a character pointer to the current delimited token
 */

/////
char *_strtok(char *str, const char *delimeter) {
	static char *save;
	char *_new = NULL;
	int i = 0;

	if (!str || !*str)
	{
		if (!save || !*save)
			return (NULL);

		while (_strcmp(save + i, delimeter) != 1 && *(save + i) != '\0')
			i++;
		if (*(save + i) == '\0')
		{
			save = NULL;
			return (save);
		}

		_new = save;
		*(save + i) = '\0';
		save = save + i + strlen(delimeter);

		return (_new);

	}
	while (_strcmp(str + i, delimeter) != 1 && *(str + i) != '\0')
		i++;

	if (*(str + i) == '\0')
		return (str);

	save = str + i + strlen(delimeter);
	*(str + i) = '\0';

	return (str);
}

void ParseToMulti(char *a, size_t l, char d, char (*r)[10][15], size_t *size)
  {                                                   debug("P2M1");
  // Need to add strncpy to copy the first iterataion of 
  // the string up to the first delimiter and keep it goint
  // until the end is reached\
  // Should we use a char array to store the strings???  ==== yes
	static char* temp = nullptr;
  static size_t rem = 0;

  	//r[0] = NULL;
	if(a != NULL) 
    {                                               debug("P2M2");
      temp = a;
    	*size = 0;
      rem = strlen(temp);  //Workig right
      temp[rem] = '\0';
      printf("temp size 1: %i\n", rem);
      printf("temp : %s\n", temp);
    }
	if(temp == NULL)
    {                                               debug("P2M3");   
      r = NULL;
    }

  for(int n = 0; n < rem + 2; n++)
    {
      printf("n = %i\n", n);
      if(a[n] == '\0') { printf("Char %i = '\\0'\n", n); }
      else if (a[n] == '\n') { printf("Char %i = '\\n'\n", n); }
    }

  for(int e = 0; e < strlen(a); e++)
  {
    printf("a = %c\n", a[e]);
  }

  int i = 0;
  int j = 1;
  
  while (rem > 0)
    {   
                                                          debug("P2M4");
          if(temp[i] == d || temp[i] == '\0')
            { 
                                                          debug("P2M5"); 
              *size += 1;                                                   
              printf("Delimiter length: %i\n", *size); // Working Right
              
              strncpy(r[j][0], &temp[0], *size);
              printf("last char = %c\n", r[j][*size]);
              
              printf("last char = %c\n", r[j][*size]);
              //if(*r[j][*size] == '\0') { printf("yes\n"); }
              
                        printf("Stored in parsed %i : %s\n", j, r[j]);
              rem -= 1;
              
                        printf("Remaining : %i\n", rem);  

            if(rem == 0) { break; }

              strncpy(&temp[0], &a[*size], rem);
              temp[rem] = '\0';
              printf("Temp: %s\n", temp);
              j++;                                 debug("P2M6");

                        *size = 0;
                        i = 0;
            rem > 0 ? i = 0: printf("Nothintg left to parse\n");
            i++;
            }               
          else
            {                                                    
                                                        debug("P2M7");      
              *size += 1;
              rem -= 1;
              *r[j][i] = temp[i];    
              i++;                         
            }
          }
                                                        debug("P2M8");    
  //*size = *size + 1;
  //strncpy(&temp[0], &a[0], *s);
                                                         debug("P2M9");    
  //temp = NULL;       
  } 

void LenandSize()
  {
    char s1[10] = "Today is ";
    char s2[10] = "the day!";
    char s3[20];
  
    strcpy(s3, s1);
    strcpy(&s3[strlen(s1)], s2);
  
    printf("S1: %s\n", s1);
    printf("S2: %s\n", s2);
    printf("String 1 and String 2 concatonated = %s\n", s3);
  
    size_t s1len = strlen(s1);
    size_t s2len = strlen(s2);
    size_t s3len = strlen(s3);

    printf("Len of s1: %i, s2: %i, s3: %i\n", s1len, s2len, s3len);

    size_t s1size = sizeof(s1);
    size_t s2size = sizeof(s2);
    size_t s3size = sizeof(s3);
  
    printf("Size of s1: %i, s2: %i, s3: %i\n", s1size, s2size, s3size);
  }


void ReadSerial() {
  // To Clear the incoming: clearbuffer
  
  debugln("Reading Serial");
    char userInput[75] = "";
    char tempUserInput[50];
  char clrbfr[] = "clearbuffer";
  char resetesp[] = "resetesp";

    while(Serial.available() > 0) {
      size_t numChars = Serial.readBytesUntil('\n', userInput, sizeof(userInput) - 1);
        userInput[numChars] = '\0';
        strcpy(tempUserInput, userInput);
        debugln("tempUserInput = "+String(tempUserInput));

        debugln(" ");
        printf("You entered: %s\n", tempUserInput); // Print input for review
        debugln(" ");
  size_t userInputLen = strlen(userInput);

    // To Clear the incoming: clearbuffer
    if (strncmp(clrbfr, &tempUserInput[0], int(11)) == 0) {
      Serial.println("Clearing Input Buffer");

        memset(tempUserInput,0,sizeof(tempUserInput));
        memset(userInput,0,sizeof(userInput));
        debugln(" ");

      debugln("Buffer Cleared!");
      }
    else if(strcpy(resetesp, tempUserInput) == 0) {
      debugln("Reseting ESP cpu");
      debugln(" ");

      esp_cpu_reset(0);
      debugln("Resetting ESP APP");
      debugln(" ");

      esp_cpu_reset(1);
      debugln("ESP CPU and APP have been reset!");
      debugln(" ");

    }
      else {
        //ParseSerial(userInput, numChars);
        //STRCSPN(userInput, numChars);


  int buffer = 100; 
  char res[buffer];
  size_t rs = 0;    
  int row = 10;
  int col = 15;

  char parsed[10][15] = { { } }; 

  //void ParseToMulti(char *a, size_t l, char d, char (*r)[10][15], size_t *size)

    ParseToMulti(userInput, userInputLen, ' ', (&parsed),  &rs);        

    char* token = NULL;

    token = _strtok(userInput, ":");
    while ( token != NULL ) {
        printf("token = %s\n", token);
        token = _strtok ( NULL, ":");
      }
  

        }
      }
    }

void setup() {
  Serial.begin(115200);
  //STRCSPN();
  //STRCHR();
  //STRSTR();
  //STRCPY();
  //STRNCPY();
  
  
  }

void loop() {
  delay(10); // this speeds up the simulation
    if ( Serial.available() > 0) {
    ReadSerial();
    }




  
  }