//======================================================
// TIME ATTACK 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 : time_attack_bluetooth(JSON String)
   *  If you want to use the stand alone mode
   *  you need to call : time_attack_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 time_attack_standalone()
  {
    // Variables
    uint16_t time     = 30; 
    uint16_t limit    = 10; 
    bool limitEnable  = true;

    // Call the Game Play
    game_timeAttack(time, limit, limitEnable);

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

//======================================================
//  Request From Bluetooth Via JSON
//======================================================

  /* TIME ATTACK GAME SETTINGS PARAMETERS NOTE:
   * ------------------------------------------
   *  
   *  FORMAT :
   *  --------
   *    {"tm": 10, "le": false, "lm": 10}
   *
   *    tm : count down timer starting value
   *    le : stands for limit enable, if is TRUE the game end if target value is meet
   *    lm : targeted amount of kicks
   *  
   *  THINGS THAT ENDS THE GAME :
   *  ---------------------------
   *    1. BY COUNT DOWN "tm" REACH TO ZERO
   *    2. BY A COMMAND "FROM APP VIA BLUETOOTH"
   *    3. BY LIMITS MEET "WHEN NUMBER OF YOUR KICKS REACH TO lm VALUE"
   *  
   *  CALCULATING RESULTS :
   *  ---------------------
   *    Rapid Kick Speed = Number Of Kickes Made / Elasped Time In Sec
   *    Delay Between Kicks = Time Of Current Kick - Time Of Last Kick
   *  
   *  RETURNNING JSON FORMAT :
   *  ------------------------
   *    {"tm" : 82, "ct" : 10, "dl" : 1234, "st" : 585}
   *    
   *    tm  : timer count in Sec
   *    ct  : strike counter (number of kicks)
   *    dl  : delay between strikes
   *    st  : time stampe of the strike in milli Seconds
   */

  void time_attack_bluetooth(String settings)
  {   
    // Deserialize the JSON document
    DeserializationError error = deserializeJson(JSON, settings); // the main JSON body container

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

    // PUBLIC VARIABLES
    const uint16_t  time        = JSON["tm"]; // Time Window To JSON
    uint16_t        limit       = JSON["lm"]; // Kick Target Limit
    bool            limitEnable = JSON["le"]; // Enable Kick Target Limit

    // Clearing Buffer
    JSON.clear();

    // Play The Game
    game_timeAttack(time, limit, limitEnable);

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

//======================================================
//  Play Time Atack Game
//======================================================

  void game_timeAttack(uint16_t time, uint16_t limit, bool limitEnable) 
  { 
    // Building Timers 1000mSec -> 1Sec
    TimeTrigger   sec_tick(1000);

    // Kick Counter
    uint16_t counter  = 0;      // This is what counts your kicks
    uint16_t timer    = time;   // This is what your running timer

    // Start LED Signal
    //LED_SIGNAL_START();

    // Initial Display Of Game Data Before Start
    GAME_TIMEATTACK_DISPLAY(timer, 0);

    // Send Initial DisJSON
    dualcomm(timeAttack_JSON_json(timer, counter, 0, 0));

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

    // staring Of time stamp
    unsigned long startStamp = millis();
    
    // store the time of the previous kick
    unsigned long lastStamp = 0;

    // reseting time ticker
    sec_tick.Reset();

    // While The Game Is Still On
    while(timer != 0)
    {
      // Time Stamp
      unsigned long timeStamp = millis() - startStamp;

      // If Stop Command Came From Smart Phone
      if(isBluetooth)
      {
        String msg = Bluetooth.readStringUntil('\n');
        flushBluetooth;
        msg.trim();
        if(msg == CM_STOP) 
        {
          dualcomm(GAME_OVER);
          // Grean Light In
          //LED_SIGNAL_END();
          // Return
          return;
        }
        else if(msg == CM_RESET)
        {
          timer = time;
          counter = 0;
          startStamp = millis();
          timeStamp = startStamp;
          lastStamp = timeStamp;
          sec_tick.Reset();
          GAME_TIMEATTACK_DISPLAY(counter, timer);
          //LED_SIGNAL_RESET();
        }
      }

      // Reset The Counter
      if(BTN_INCREASE.pressed()) {
        timer = time;
        counter = 0;
        startStamp = millis();
        timeStamp = startStamp;
        lastStamp = timeStamp;
        sec_tick.Reset();
        GAME_TIMEATTACK_DISPLAY(counter, timer);
      }

      // Will Exit The Game
      if(BTN_CENTER.pressed()) {
        dualcomm(GAME_OVER);
        DISPLAY_CHANGED = false;
        return;
      }
      
      // Every Kick ---------------------------->>>
      if(PIEZO_MAP > VTH)
      {
        // Count As A Strike
        counter++;

        // Display On OLED
        GAME_TIMEATTACK_DISPLAY(counter, timer);

        // Send JSON String Out
        dualcomm(timeAttack_JSON_json(timer, counter, lastStamp, timeStamp));
        
        // Time Snap Shot
        lastStamp = timeStamp;
        
        // Wait For Analog Sampler To by pass the strike
        delay(100);
      }

      // Every Second ---------------------------->>>
      if(sec_tick.Trigger())
      {
        // Decrement Time After Every Second
        timer--;

        // Display Time And Count Every Second
        GAME_TIMEATTACK_DISPLAY(counter, timer);

        // Send JSON String Out
        dualcomm(timeAttack_JSON_json(timer, counter, 0, 0));
      }
      
      // If Limits Are Enabled And Meet
      if(limitEnable == true && counter == limit)
      {
        // END GAME
        dualcomm(GAME_OVER);

        // Time Difference Between Start & Count Down Timer
        const uint16_t diff = time - timer;

        // Display The Game Result
        GAME_TIMEATTACK_RESULT(counter, diff);
        
        // Celebrate
        //LED_SIGNAL_CELEBRATION();
        
        // Return
        return;
      }
    }

    // Send End Game Signal To Smart Phone
    dualcomm(GAME_OVER);
    
    // Display The Result
    GAME_TIMEATTACK_RESULT(counter, time);
    
    // LightUp
    //LED_FADEIN(255, 0, 0);   // RED Color
    //delay(2000);        // Delay 2000
    //LED_CLEAR();        // CLEAR OFF
    
    // Return
    return;
  }

//======================================================
// TIME ATTACK KICK JSON -> To Send Back To Mobile
//======================================================

  String timeAttack_JSON_json(unsigned int RunningTime, unsigned int KickCount, unsigned int LastStamp, unsigned int TimeStamp)
  {  
    // Building The Buffer
    JSON["tm"]  = RunningTime;
    JSON["ct"]  = KickCount;

    // Calculations
    if(TimeStamp > 0) 
    {
      // Calculate Time Stamp In Seconds
      float st = TimeStamp;
      st /= 1000;
      JSON["st"] = String(st, 3).toFloat();
      
      // Calculate Strike Delay In Seconds
      float dl = TimeStamp - LastStamp;
      dl /= 1000;
      JSON["dl"] = String(dl, 3).toFloat();
    }
    
    String output;
    serializeJson(JSON, output);
    JSON.clear();
    return output;
  }
  
//------------------------------------------------------
//  OLED - GAME TIMEATTACK PLAY
//------------------------------------------------------
  
  void GAME_TIMEATTACK_DISPLAY(uint16_t count, uint16_t time) 
  {
    OLED_CLEAR();
    drawTextCenter(128/2, 0, 2, "TIME ( " + String(time) + " ) Sec");
    drawTextCenter(128/2, 20, 2, "KICKS ( " + String(count) + " )");
    drawTextCenter(128/2, 50, 1, "<< EXIT >>");
    OLED_SHOW();
  }

//------------------------------------------------------
//  OLED - GAME TIMEATTACK RESULT
//------------------------------------------------------
  
  void GAME_TIMEATTACK_RESULT(uint16_t count, uint16_t time) 
  {
    OLED_CLEAR();
    float avgSpeed = 0.0;
    avgSpeed = (float)count/time;
    drawTextCenter(128/2, 0, 2, "RESULT");
    drawTextCenter(128/2, 20, 2, String(avgSpeed, 2) + " K/s");
    drawTextCenter(128/2, 50, 1, "<< EXIT >>");
    OLED_SHOW();

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