#include <IRremote.h>
#include <FastLED.h>
#include <Bounce2.h>

// How many LEDs are used in each digit
#define NUM_LEDS_PER_DIGIT 29
// Total number of LEDs in the strip
#define NUM_LEDS 116
// The pin which is connected to the DataIn of the LED strip
#define DATA_PIN 6
// If defined, timer shows minutes and seconds MM:SS, rather than seconds SSSS
#define DISPLAY_MMSS
#define PIN_RECEIVER 2   // Signal Pin of IR receiver
// CONSTANTS
// The following array defines the sequence of LEDs that should be lit to represent each digit 0-9
// This will vary depending on the order in which the strip has been physically wired through
// the segments, the number of LEDs in each segment, whether there are any unused LEDs in the strip
// (e.g. between digits) etc.
// Segments of a 7-segment display are generally labelled as follows:
//    /-A-\
//    F   B
//    --G-/
//    E   C
//    \-D-/
// The way I've wired the strips is:
// - Strip is fed through the segments in the order G->B->A->F->E->D->C (then onto the next digit)
// - There are 4 LEDs in each segment
// - There is a single unused LED in the strip between segments F and E
// - This makes the total length of 29 LEDs in the strip for each digit
// - I'm packing these into a single 32-bit integer, and since bitwise operations are MSB, this will
// be counted from the right-hand side, and then padded at the front with 3x0s up to 32 bits.
// e.g. 0b000ccccddddeeee0ffffaaaabbbbgggg
// If you have an even bigger display containing more LEDs, it might be necessary to pack them into a
// 64-bit integer instead, i.e. uint64_t.
const uint32_t digits[10] = {
  0b00011111111111101111111111110000, // 0
  0b00011110000000000000000011110000, // 1
  0b00000001111111100000111111111111, // 2
  0b00011111111000000000111111111111, // 3
  0b00011110000000001111000011111111, // 4
  0b00011111111000001111111100001111, // 5
  0b00011111111111101111111100001111, // 6
  0b00011110000000000000111111110000, // 7
  0b00011111111111101111111111111111, // 8
  0b00011111111000001111111111111111, // 9
};

// The array of RGB values assigned to each LED in the strip
CRGB leds[NUM_LEDS];
// The time at which the counter was (most recently) started
unsigned long startTime;
// Duration is specified in ms. So 1000 = 1 second, 60000 = 1 minute, etc.
unsigned long timerDuration = 3600000;
// Keep track of elapsed time from previous start/stop cycles
enum State {Inactive, Active};
State state = State::Inactive;
// Count direction
enum Mode {CountUp, CountDown};
Mode mode = Mode::CountUp;
//Receiver Object
IRrecv receiver(PIN_RECEIVER);
void setup() {
  // Initialise a serial connection, used only for debugging
receiver.enableIRIn(); // Start the receiver
 Serial.begin(9600);
// Initialise the LED strip
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
  // Configure the debounced inputs
  state = State::Active;
  Start();
  mode = Mode::CountDown;

}
void loop() {
  // Grab the current timestamp
  unsigned long currentTime = millis();
  // Calculate the value to be displayed
  static long timeValue =0;
  // The colour hue in which the time will be displayed
  int timeHue = 170;
  // What to do next depends on the current state of the device
  if(state == State::Active){
    if(mode == Mode::CountDown) {
      // The time remaining is the total game duration, less the time spent during the
      // current period of play, less the time elapsed during any previous sessions
      // or other deductions
      timeValue = timerDuration - (currentTime - startTime);
      // Map colour hue from green -> red based on fraction of time remaining
      timeHue = map(timeValue, 0, timerDuration, 0, 100);
      // Countdown has reached zero
      if(timeValue <= 0) {
        timeValue =0;      //If the value of time becomes zero start again
      }
    }
if (receiver.decode()) {
    if(receiver.decodedIRData.command==48)
{                                 //One minute is decremented
if(timerDuration >60000) { timerDuration -= 60000;
Start();
}
}
if(receiver.decodedIRData.command==24)
{                                  
  if(timerDuration >300000) { timerDuration -= 300000; 
  Start();
  }
                               //Five minutes penalized if button 2 is pressed
}
if(receiver.decodedIRData.command==122)
{
 if(timerDuration<3300000)                                               //Five Bonus Minutes if button 3 is pressed
{
timerDuration+=300000;
}
 if(timerDuration>3300000)                                               //Five Bonus Minutes if button 3 is pressed
{
timerDuration=3600000;
}
Start();
}
if(receiver.decodedIRData.command==16)
{
RandomGame();//Random game gets started for one minutes
}
receiver.resume();  // Receive the next value
} 
  // Display as mm:ss
  #ifdef DISPLAY_MMSS
    // Use modulo to calculate "remainder" seconds
    int seconds = (timeValue / 1000) % 60;
    int minutes = timeValue / 60000;
    // Units
    setDigit(3, seconds%10, CHSV(timeHue, 255, 255));
    // Tens
    setDigit(2,(seconds/10)%10, CHSV(timeHue, 255, 255));
    // Hundreds
    setDigit(1, minutes%10, CHSV(timeHue, 255, 255));
    // Thousands
    setDigit(0,(minutes/10)%10, CHSV(timeHue, 255, 255));
  // Display in seconds
  #else
    // Units
    setDigit(3, (timeValue / 1000) % 10, CHSV(timeHue, 255, 255));
    // Tens
    setDigit(2, (timeValue / 10000) % 10, CHSV(timeHue, 255, 255));
    // Hundreds
    setDigit(1, (timeValue / 100000) % 10, CHSV(timeHue, 255, 255));
    // Thousands
    setDigit(0, (timeValue / 1000000) % 10, CHSV(timeHue, 255, 255));
  #endif

  // Send the updated values to the LED strip
  FastLED.show();
  delay(20);
}
}
void setDigit(int display, int val, CHSV colour){
  for(int i=0;i<NUM_LEDS_PER_DIGIT; i++){
    colour.v = bitRead(digits[val], i) * 255;
    leds[display*NUM_LEDS_PER_DIGIT + i] = colour;
  }
}
void Start(){
  Serial.println(F("Timer activated!"));
  state = State::Active;
  startTime = millis();
}
void RandomGame()
{
Serial.println("Random Numbers Game Begin for 30 Seconds");
unsigned long Start=millis();
while(millis()-Start>60000)
{                                                   //This will continue for 30 seconds and the lights will flash random numbers
    setDigit(3, random(0,9), CHSV(random(0,255), 255, 255));
    // Tens
    setDigit(2,random(0,9), CHSV(random(0,255), 255, 255));
    // Hundreds
    setDigit(1, random(0,9), CHSV(random(0,255), 255, 255));
    // Thousands
    setDigit(0,random(0,9), CHSV(random(0,255), 255, 255));
  // Display in seconds
    FastLED.show();
  delay(1000);
}
}