/**
   Copyright (C) 2018, Uri Shaked
   Licensed under the MIT License.
*/

#include <Arduino.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <TinyDebug.h>

#include "pitches.h"

const int totalSwitches = 3;
byte buttonPins[] = {1, 2, 3};

int switchVal = 0;
/* Constants - define pin numbers for leds, buttons and speaker, and also the game tones */
// byte buttonPins[] = {1, 2, 3, 4};

int gameTones[] = { NOTE_G3, NOTE_C4, NOTE_E4, NOTE_G5};

#define SPEAKER_PIN 0


/**
   Set up the GPIO pins
*/

ISR(PCINT0_vect) {
  GIMSK &= ~0b00100000;  // Turn off pin change interrupts
  sleep_disable();
}

// Alternate sleep function
// void sleep() {
//   sleep_enable();
//   noInterrupts();

//   GIMSK |= 0b00100000; // Turn on pin change interrupts
//   PCMSK = 0; // Clear all pin change interrupts

//   // Enable pin change interrupts for button pins (assuming pins are within PCINT0-7 group)
//   for (byte i = 0; i < totalSwitches; i++) {
//     PCMSK |= (1 << buttonPins[i]);
//   }

//   interrupts();
//   sleep_cpu();
// }

void sleep() {
  Debug.println("-- ENTERING SLEEP MODE --");
  sleep_enable();
  noInterrupts();
  GIMSK |= 0b00100000;  // Turn on pin change interrupts
  // check if disabling more buttons saves power verify totalbuttons
  for (byte i = 0; i < totalSwitches; i++) {
    PCMSK |= 1 << buttonPins[i];
  }
  interrupts();
  sleep_cpu();
}


// The sound-producing function
void beep (unsigned char speakerPin, int frequencyInHertz, long timeInMilliseconds)
{ // http://web.media.mit.edu/~leah/LilyPad/07_sound_code.html
  int  x;
  long delayAmount = (long)(1000000 / frequencyInHertz);
  long loopTime = (long)((timeInMilliseconds * 1000) / (delayAmount * 2));
  pinMode(speakerPin, OUTPUT);
  for (x = 0; x < loopTime; x++) {
    digitalWrite(speakerPin, HIGH);
    delayMicroseconds(delayAmount);
    digitalWrite(speakerPin, LOW);
    delayMicroseconds(delayAmount);
  }
  pinMode(speakerPin, INPUT);
}

void playButtonTone(byte buttonIndex) {
  beep(SPEAKER_PIN, gameTones[buttonIndex], 150);

  // Wait until button is released.
  while (digitalRead(buttonPins[buttonIndex]) == LOW);
  delay(50);
}

int readSwitch() {
  for (;;) { 
    int switchState = 0;
    for (int i = 0; i < totalSwitches; i++) {
      byte buttonPin = buttonPins[i];
      if (digitalRead(buttonPin) == LOW) {
        switchState |= (1 << i);
      }
    }
    if (switchState != 0) {
      return switchState;
    }
    else if (switchState == 0) { // if all buttons are high, return 0
      return 0;
    }
    sleep();
  }
}


/*
int readSwitch() {
  for (;;) { 
    int switchState = 0;
    for (int i = 0; i < totalSwitches; i++) {
      // Debug.print(digitalRead(buttonPins[i]));
      byte buttonPin = buttonPins[i];
      if (digitalRead(buttonPin) == LOW) {
        switchState |= (1 << i);
        // Debug.println(switchState |= (1 << i), HEX);
      }
    }
    // Debug.println("");
    if (switchState != 0) {
      return switchState;
    }
    sleep();
  }
}
*/
void decodeSwitch(int switchValue) {
  // Add different modes depending on the switchValue
  switch (switchValue) {
    case 01: // Mode 1
      Debug.println("1");
      break;
    case 10: // Mode 2
     Debug.println("2");      // Code for mode 2
      break;
    case 00: // Mode 3
     Debug.println("3");      // Code for mode 3
      break;
    case 11: // Mode 3
     Debug.println("11");      // Code for mode 3
    break;

    // Add more cases for different modes
    default:
    Debug.println("default"); 
      // Code for invalid mode or no mode selected
      break;
  }
}




void setup()
{
  Debug.begin();
  for (int i = 0; i < totalSwitches; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }  
}

void loop()
{  

    // Read the switch values
  switchVal = readSwitch();
  Debug.println(switchVal);

  // Decode and perform actions based on the switch values
  // decodeSwitch(switchVal);

  // beep(SPEAKER_PIN, gameTones[], 300);

  // Debug.print(digitalRead(switchPin1));
  // Debug.println(digitalRead(switchPin2)); 
  sleep();  
  delay(50);
}

/*
The switchState |= (1 << i); line of code combines the current switchState with 
the value obtained from shifting the number 1 left by i positions using a bitwise OR operation.

Let's break it down:

1 << i: This operation is a bitwise left shift. It takes the binary representation of 
the number 1 (which is 00000001 in 8-bit representation) and shifts it left by i positions. 
For example, if i = 2, the result would be 00000100.

switchState |= ...: This operation is a bitwise OR assignment. 
It takes the current value of switchState, performs a bitwise OR with the value obtained in step 1, 
and assigns the result back to switchState.
00000100
00000010
00000110

*/
ATTINY8520PU