#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <stdio.h>
#include <stdlib.h>



//define button pins
#define downPin 33
#define upPin 26
#define leftPin 25
#define rightPin 32
#define bombPin 34
#define enterPin 35

WiFiMulti wifiMulti;

//initialize server constants
const char* ssid = "Hotspot1";
const char* password = "his dadlol";

const char* serverName = "https://web.engr.oregonstate.edu/~rolphr/pleasework.php";


//button class
class Button {
  private: //variables to run in class
    byte pin;
    byte state;
    byte lastReading;
    bool lastButtonState = false;
  public: //methods and variables able to be called from the object
    Button(byte Pin) {
      this->pin = Pin;
      lastReading = LOW; //set initial button value to low
      init(); //run init method
    }
    void init() {
      pinMode(pin, INPUT); //make button input
    }
    bool risingEdge() { //check button is pressed, only when first clicked
      bool buttonState = digitalRead(pin); //read
      
      // compare the buttonState to its previous state
      if (buttonState != lastButtonState) {
        // if the state has changed run and break true
        if (buttonState == HIGH) {
          lastButtonState = buttonState;
          return true;
        } 
        delay(10); //wait to fix bouncing
      }
      // save the current state as the last state, for next time through the merthod
      lastButtonState = buttonState;
      
      return false; //else the button is either held or not pressed
    }
};

//initialize all button classes
Button down(downPin);
Button up(upPin);
Button left(leftPin);
Button right(rightPin);
Button bomb(bombPin);
Button enter(enterPin);

//
bool submitFlag = false;

/*  Adafruit_PCD8544(CLK,DIN,D/C,CE,RST); */
Adafruit_PCD8544 display = Adafruit_PCD8544(2, 4, 16, 15, 17);
int contrastValue = 60; // Default Contrast Value

//aren't necessary but could be used lateer
const int adcPin = 34;
int adcValue = 0;

//setup board map
int bitmap[72]= {}; 

//setup global index, essentially current cursor placement
int8_t currentIndex = 9;

//how many bombs are on the board currently
byte bombCount = 0;


unsigned long previousMillis = 0;

//is cursor on flag
bool cursorState = false;


bool lastButtonState = false;

void setup()
{
  //initialize the board array as all 0s
  for(int i = 0; i < 72; i++) {
    bitmap[i] = 0;
  }

  Serial.begin(115200);
  
  // Initialize the Display
  display.begin();

  //Change the contrast
  display.setContrast(contrastValue);

  
  // Clear the display
  display.clearDisplay();
  display.display();

  //setup wifi
  wifiMulti.addAP(ssid, password);
  for(int t = 4; t > 0; t--) {
    Serial.println("Connecting");
    Serial.flush();
    delay(500);
  }
  
  delay(1000);
 
}

void loop()
{
  //clear screen and set time to how long the program has run
  display.clearDisplay();
  unsigned long currentMillis = millis();

//check if d pad buttons are down and will stay within bounds of board
 if(down.risingEdge() && (currentIndex+12) < 72) {
  currentIndex+=12; //move 12 which is the array width
 }
 if(up.risingEdge() && (currentIndex-12) > -1) {
  currentIndex-=12;
 }
 if(right.risingEdge() && (currentIndex+1) % 12 != 0) {
  currentIndex++; //move right through the arary
 }
 if(left.risingEdge() && (currentIndex) % 12 != 0) {
  currentIndex--;//move left through the arary
 }

//place bomb logic
 if(bomb.risingEdge()) { //check if bomb button pressed
  switch(bitmap[currentIndex]) { //check cursor location if it is a 0 or 1
    case 0: //if 0 and bomb count is less than 10, set int in array to 1
      if(bombCount < 10) {
        bitmap[currentIndex] = 1;
        bombCount++;
      } 
    break;
    case 1://if 1 set int in array to 0
      bitmap[currentIndex] = 0;
      bombCount--;
    break;
  }
 }

 //enter button logic
 if(enter.risingEdge()){
    if(submitFlag) { //if the button has been pressed once already
      submitFlag = false; //set the flag to false
      postData(); //send array
    }
    else {
      submitFlag = true; //say that the button has been pressed already
    }
 }
 
 if(submitFlag) { //if the button has been pressed once, display a message
    display.setCursor(0,35); //set display location
    display.setTextColor(BLACK); //text parameters
    display.setTextSize(1);
    display.setTextWrap(true);
    display.print("Hit to send"); //text to display
 }

 //same as above but for remaining bombs available to place
 display.setCursor(0,25);
display.setTextColor(BLACK);
 display.setTextSize(1);
display.setTextWrap(true);
display.print("Bombs left: ");
display.print(10-bombCount);//max bombs minus current bombs on board
  
  int x = currentIndex % 12; // formula to find x from the cursor location
  int y = (currentIndex - x)/12; // formula to find y from cursor location and width of array (12)
  
  drawBoard(); //draw board with bombs 
  
  if(currentMillis - previousMillis > (1000/15*7)) { //if the time since the last blink of cursor is greater than 7 frames
    if(!cursorState) { //if cursor off
      
      display.fillRect(x*4,y*4,4,4,BLACK); //cursor filled in
      cursorState = true; //cursor is on
    }
    else if(cursorState) { //if cursor is on
      display.fillRect(x*4,y*4,4,4,WHITE); //cursor filled with white
      cursorState = false; //cursor off
    }
    previousMillis = currentMillis; //set time since last changed state
  }
  display.display(); //display the screen
  delay(1000/15); //wait for 15th of second or 15fps
}


void drawBoard() {
  for(int c = 0; c < 12; c++) { //columns from 0-11 which equals board width of 12
    for(int r = 0; r < 6; r++) { //rows from 0-5 which equals board height of 6
      if(bitmap[r*12+c] == 1) { //index from column and row data points, if it's 1 fill in to represent bomb
        display.fillRect(c*4,r*4,4,4,BLACK);
        display.fillRect(c*4+1,r*4+1,2,2,WHITE);
      }
      else if(bitmap[r*12+c] == 0) { //else at index from column and row data fill in with smaller square to represent unbombified space
        display.drawRect(1+c*4,1+r*4,2,2,BLACK);
      }
    }
  }
  display.display();
}

void postData() { //function to send data to server
  Serial.println("");
  Serial.println("==========================");
  Serial.println("       POST attempt");
  Serial.println("==========================");
  Serial.println("");
  if(wifiMulti.run() == WL_CONNECTED){ //if connected
    
      HTTPClient http;
    
      // Domain name with URL path or IP address with path
      http.begin(serverName); //begin request at URL

      // Specify content-type header
      http.addHeader("Content-Type", "application/x-www-form-urlencoded"); //html headers
      
      // Data to send with HTTP POST
      String httpRequestData = "text="; //make sure to specify post code to run right php code
      for(int i = 0; i < 72; i++) { //run through bitmap and convert the 1s and 0s to char to send to server
        if(i < 71) { //if not last bit add comma at end
          httpRequestData+=String(bitmap[i])+","; //append bit as string to string to send
        }
        else httpRequestData+=String(bitmap[i]); //if last bit don't add comma
      }
      // Send HTTP POST request
      int httpResponseCode = http.POST(httpRequestData); //post to server
     
      Serial.print("HTTP Response code: ");
      Serial.println(httpResponseCode);

      Serial.println(http.getString()); //return the echo of the php code
        
      http.end(); //stop the http
      
      delay(5000); //wait 5 seconds
   }    
}
