//======================================================
// REACTION GAME MAIN ROUTINE
//======================================================

  /* This Game Can Be Called From 
   *  Stand Alone Mode / Bluetooth Connection
   *  The primary mode is the standalone but
   *  if the bluetooth is connected it has the priority
   *  so it will take over the control of the device
   *  
   *  If you want to control the game via bluetooth
   *  you need to call : game_reaction_bluetooth(JSON String)
   *  If you want to use the stand alone mode
   *  you need to call : game_reaction_standalone()
   *  
   *  the game returns a float point number which is
   *  in seconds. so the athlete know how long he takes to react
   */

//------------------------------------------------------
// Request From Stand Alone Buttons
//------------------------------------------------------

  void game_reaction_standalone()
  {
    // Variables
    uint8_t   minDelay  = 1;
    uint8_t   maxDelay  = 3;
    uint8_t   trials    = 10;
    
    // Call the Game Play
    play_reaction(minDelay, maxDelay, trials);

    // Give Permision To Change Display
    DISPLAY_CHANGED = false;
  }

//------------------------------------------------------
//  Request From Bluetooth Via JSON
//------------------------------------------------------

  /* REACTION GAME SETTINGS PARAMETERS NOTE:
   * ------------------------------------------
   *  
   *  FORMAT :
   *  --------
   *    {"tr": 10, "mn": 1, "mx": 2}
   *  
   *  MEANNING :
   *  ----------
   *    tr : trials pre counter
   *    mn : minimum delay, between trials
   *    mx : maximum delay, between trials
   *  
   *  THINGS THAT ENDS THE GAME :
   *  ---------------------------
   *    1. BY COUNT DOWN "tr" REACH TO ZERO
   *    2. BY A COMMAND "FROM APP VIA BLUETOOTH"
   *  
   *  CALCULATING RESULTS :
   *  ---------------------
   *    Rapid Kick Speed = Number Of Kickes Made / Elasped Time In Sec
   */

  void game_reaction_bluetooth(String settings)
  {
    //------------------------------------------------------
    // START OF READING THE SETTINGS
    //------------------------------------------------------
    
    // Deserialize the JSON document
    DeserializationError error = deserializeJson(JSON, settings);

    // JSON ERROR
    if(error) {
      dualcomm(JSON_ERROR);
      return;
    }

    // PUBLIC VARIABLES
    uint8_t   minDelay  = JSON["mn"];
    uint8_t   maxDelay  = JSON["mx"];
    uint16_t  trials    = JSON["lm"];

    // Fix Random Error
    maxDelay += 1;
    
    // Clearing Buffer
    JSON.clear();

    // Play The Game
    play_reaction(minDelay, maxDelay, trials);

    // Give Permision To Change Display
    DISPLAY_CHANGED = false;
  }

//------------------------------------------------------
//  Play The Game
//------------------------------------------------------

  void play_reaction(uint8_t minDelay, uint8_t maxDelay, uint16_t trials)
  {
    // PUBLIC VARIABLES
    double    totalRes  = 0.0;

    // Fix Random Error
    maxDelay += 1;
    
    // Clearing Buffer
    JSON.clear();

    //------------------------------------------------------
    // PREPARE FOR GAME START
    //------------------------------------------------------
    
    // DisJSON Welcome Message
    terminal("");
    terminal("trials    : " + String(trials) + " Strikes");
    terminal("minDelay  : " + String(minDelay) + " Seconds");
    terminal("maxDelay  : " + String(maxDelay) + " Seconds");
    terminal("2 Seconds To Start Get Ready & Good Luck !!");
    terminal("");

    // Main Variables
    uint16_t      sdelay    = 0;
    uint16_t      power     = 0;
    uint16_t      response  = 0;
    unsigned long startTime = 0;
    unsigned long stopTime  = 0;

    // Ready Signal
    //LED_SIGNAL_REACTION_START();

    // Display On OLED
    GAME_REACTION_DISPLAY(0, 0);

    //-------------------------
    // PREPARE FOR GAME START
    //-------------------------

    // Processing Results
    for(int i=0; i<trials; i++)
    {
      // Reading Kick JSON
      terminal(" ------ Trial Number (" + String(i + 1) + ") ------");
      terminal(" -> Get Ready !!");

      // Set Random Delay Time
      sdelay = random(minDelay, maxDelay);
      sdelay *= 1000;
      delay(sdelay);

      // Light Up Green
      //LED_SET_COLOR(0, 255, 0, 255);

      // Start Timer
      startTime = millis();

      // Sensing Strike Power
      while(power < VTH)
      {
        // Reading The Strike
        power = PIEZO_MAP;

        // If Stop Command Came From Smart Phone
        if(isBluetooth)
        {
          String msg = Bluetooth.readStringUntil('\n');
          flushBluetooth;
          msg.trim();
          if(msg == CM_STOP) {
            dualcomm(GAME_OVER);
            // LightUp
            //LED_SIGNAL_END();
            // RESET
            return;
          }
          else if(msg == CM_RESET) {
            //LED_SIGNAL_REACTION_RESET();
            i         = 0;
            sdelay    = 0;
            power     = 0;
            response  = 0;
            startTime = millis();
            stopTime  = millis();
            totalRes  = 0;
            DISPLAY_CHANGED = false;
            GAME_REACTION_DISPLAY(i, response);
            //break;
          }
        }

        // Reset The Counter
        if(BTN_INCREASE.pressed()) {
          //LED_SIGNAL_REACTION_RESET();
          i         = 0;
          sdelay    = 0;
          power     = 0;
          response  = 0;
          startTime = millis();
          stopTime  = millis();
          totalRes  = 0;
          DISPLAY_CHANGED = false;
          GAME_REACTION_DISPLAY(i, response);
        }
  
        // Will Exit The Game
        if(BTN_CENTER.pressed()) {
          dualcomm(GAME_OVER);
          DISPLAY_CHANGED = false;
          return;
        }
      }
  
      // Stop Timer
      stopTime = millis();
  
      // Stop Light
      //LED_SET_COLOR(255, 0, 0, 255);
  
      // Calculating Response Time
      response = stopTime - startTime - 1;
      totalRes = totalRes + ((float)response/1000);
  
      // Create Json JSON
      String msg = reaction_JSON_json(i+1, power, response, sdelay);

      // Display On OLED
      GAME_REACTION_DISPLAY(i+1, response);
      
      // Print To Terminal
      dualcomm(msg);
      
      // Clear All
      sdelay    = 0;
      power     = 0;
      response  = 0;
    }

    // Red Light Delay
    delay(500);

    // END GAME
    dualcomm(GAME_OVER);

    // Blink Red
    //LED_SIGNAL_CELEBRATION();

    // Display Result
    GAME_REACTION_RESULT(trials, totalRes);

    // Return To Game Selector
    return;
  }

//------------------------------------------------------
// REACTION JSON -> To Send Back To Mobile Device
//------------------------------------------------------

  String reaction_JSON_json(unsigned int count, unsigned int power, unsigned int response, unsigned int startDelay)
  {
    // Convert To Seconds Unit
    float re = response;
    re /= 1000;

    // Asignning Values
    JSON["ct"]  = count;  // Strike Number
    JSON["pw"]  = power;  // Strike Power In Analog Read
    JSON["sd"]  = startDelay/1000;  // LED Strip Start Delay in Seconds
    JSON["re"]  = String(re, 3).toFloat();  // Strike Reaction Time In Milli Sec
    
    String output;
    serializeJson(JSON, output);
    JSON.clear();
    return output;
  }

//------------------------------------------------------
// REACTION GAME START LED SIGNAL
//------------------------------------------------------

  void LED_SIGNAL_REACTION_START()
  {
    // Cross fade the white signal to get ready
    //LED_CROSS_FADE(255, 255, 255, 3);
    
    // Set the LED strip color to red
    //LED_SET_COLOR(255, 0, 0, 255);
  }
  
//------------------------------------------------------
// REACTION GAME RESET LED SIGNAL
//------------------------------------------------------

  void LED_SIGNAL_REACTION_RESET()
  {
    // Light Bright Blue
    //LED_BLINK(0, 0, 255, 2);
    
    // Wait For 1/4 Second
    //delay(250);
    
    // Fade Out The Blue
    //LED_SET_COLOR(0, 255, 0, 255);
  }

//------------------------------------------------------
//  OLED GAME PLAY REACTION
//------------------------------------------------------

  void GAME_REACTION_DISPLAY(uint16_t count, float reatime) 
  {
    OLED_CLEAR();
    drawTextCenter(128/2, 0, 2, "KICK : " + String(count));
    drawTextCenter(128/2, 20, 3, "TIME : " + String(((float)reatime/1000), 2));
    
    // Exit Button Command Only Via Stand Alone Mode
    if(BLUETOOTH_STATUS == false) {
      drawTextCenter(128/2, 50, 1, "<< EXIT >>");
    }
    
    OLED_SHOW();
  }

//------------------------------------------------------
//  OLED - GAME TIMEATTACK RESULT
//------------------------------------------------------
  
  void GAME_REACTION_RESULT(uint16_t trials, uint16_t total_reaction) 
  {
    OLED_CLEAR();
    float avgReaction = 0.0;
    avgReaction = (float)total_reaction/trials;
    drawTextCenter(128/2, 0, 2, "RESULT");
    drawTextCenter(128/2, 20, 2, String(avgReaction, 3) + " s");
    drawTextCenter(128/2, 50, 1, "<< EXIT >>");
    OLED_SHOW();

    // Waiting For Center Button To Move On
    while(1){
      if(BTN_CENTER.pressed()) {
        break;
      }
    }
  }
