#ifndef _DISPLAY_H_
#define _DISPLAY_H_

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Fonts/FreeMonoBold18pt7b.h>
#include <Fonts/FreeSansBold9pt7b.h>


#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels

#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

uint8_t standingDisplayScreen=0;
#define NUM_STANDINGDISPLAYSCREEN 3

#define DISPLAYSTANDSTILLTIME 5000

bool display_init();
void display_update(ESCSerialComm& escFront, ESCSerialComm& escRear);
void display_drivingDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear);
void display_standingDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear);
void display_standingDisarmedDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear);

void display_debugDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear);


bool display_init(){
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    return false;
  }
  display.clearDisplay();
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,0);             // Start at top-left corner
  display.display();
  return true;
}

void display_update(ESCSerialComm& escFront, ESCSerialComm& escRear){
  display.clearDisplay();
  /*
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,0);             // Start at top-left corner
  display.print(F("Speed   : ")); display.println((escFront.getMeanSpeed()+escRear.getMeanSpeed())/2.0);
  display.print(F("Thr: ")); display.print(throttle_pos);
  display.print(F(" Brk : ")); display.println(brake_pos);
  display.print(F("Current : ")); display.println(filtered_currentAll);
  display.print(F("Vbat : ")); display.print(escFront.getFeedback_batVoltage());
  display.print(F(" / ")); display.println(escRear.getFeedback_batVoltage());
  */

  if ( (error_brake_outofrange || error_throttle_outofrange || error_throttle_difftoohigh || error_ads_max_read_interval || error_sdfile_unavailable) && ((loopmillis/2000)%2==0)) {
    //Error Messages
    
    display.setFont();
    display.setTextSize(1);             // Normal 1:1 pixel scale
    display.setTextColor(SSD1306_WHITE);        // Draw white text
    display.setCursor(0,0);             // Start at top-left corner
    display.print(F("Error!"));
    display.println();

    String errorstring="";
    if (error_brake_outofrange) {
      errorstring+="brake_outofrange\n";
    }
    if (error_throttle_outofrange) {
      errorstring+="throttle_outofrange\n";
    }
    if (error_throttle_difftoohigh) {
      errorstring+="throttle_difftoohigh\n";
    }
    if (error_ads_max_read_interval) {
      errorstring+="ads_max_read_interval\n";
    }if (error_sdfile_unavailable) {
      errorstring+="error_sdfile_unavailable\n";
    }
    display.print(errorstring);

  }else{
    //Normal Display Routines here
    
    if (armed) {
      if (loopmillis-last_notidle>DISPLAYSTANDSTILLTIME) {
        display_standingDisplay(escFront,escRear);
      }else{
        display_drivingDisplay(escFront,escRear);
        //display_debugDisplay(escFront,escRear);        
      }
      
    }else{
      display_standingDisarmedDisplay(escFront,escRear);
    }
    
  }
  

  
  
  display.display();
}


void display_drivingDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear) {
  //Display stuff here for when bobbycar is moving or was moving recently and is armed


  //## Km/h Display
  display.setFont(&FreeMonoBold18pt7b);
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,SCREEN_HEIGHT-(SCREEN_HEIGHT-18)/2 - 3);             // Start at top-left corner


  //float _speeddisplay=(escFront.getMeanSpeed()+escRear.getMeanSpeed())/2.0*3.6;
  float _speeddisplay=minSpeedms*3.6;
  
  //_speeddisplay=(millis()/1000)%21; //debugging
  char buf[8];
  dtostrf(_speeddisplay,1,1,buf);
  String strbuf=buf;
  
  if (strbuf.length()<4) { //pad spaces on the left
    strbuf=" "+strbuf;
  }
  display.print(strbuf);
  
  display.setFont();
  display.setCursor(SCREEN_WIDTH-25,SCREEN_HEIGHT-16);
  display.print("km/h");

  //A
  display.setCursor(SCREEN_WIDTH-37,1);
  static float averaged_filtered_currentAll;
  #define CURRENT_FILTER 0.8
  averaged_filtered_currentAll=averaged_filtered_currentAll*CURRENT_FILTER+(1-CURRENT_FILTER)*filtered_currentAll; //filter over time
  float averaged_filtered_wattAll=averaged_filtered_currentAll*(escFront.getFeedback_batVoltage()+escRear.getFeedback_batVoltage())/2.0;
  //dtostrf(averaged_filtered_currentAll,1,2,buf);
  dtostrf(averaged_filtered_wattAll,1,0,buf);
  strbuf=buf;
  if (strbuf.length()<5) { //pad spaces on the left
    strbuf=" "+strbuf;
  }
  display.print(strbuf);
  //display.print("A");
  display.print("W");

  
  //## Trip / Current Consumed Display
  display.setCursor(1,SCREEN_HEIGHT-7);

  //## Current    
  /*
  dtostrf(min_filtered_currentAll,1,1,buf);
  display.print("min:");
  display.print((String)buf);
  display.print("A max:");

  dtostrf(max_filtered_currentAll,1,1,buf);
  display.print((String)buf);
  display.print("A");
  */

  //## Watt
  dtostrf(min_filtered_wattAll,1,0,buf);
  display.print((String)buf);
  display.print(" / ");

  dtostrf(max_filtered_wattAll,1,0,buf);
  display.print((String)buf);
  display.print("W ");

  display.setCursor(SCREEN_WIDTH-6*6,SCREEN_HEIGHT-7);
  dtostrf(max_meanSpeed*3.6,1,0,buf);
  display.print((String)buf);
  display.print("km/h");

}


void display_debugDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear) {
  //Debug
  display.setTextSize(2);             // Normal 1:1 pixel scale
  display.setFont();
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  char buf[8];

  display.setCursor(1,0);
  dtostrf(filtered_currentAll,1,3,buf);
  display.print((String)buf);
  display.print(" A > ");
  display.println();


  //all wheel getCMD
  
  display.setTextSize(1);
  display.setCursor(25,SCREEN_HEIGHT-8*2);
  display.print(escFront.getCmdL());
  display.setCursor(SCREEN_WIDTH-4*7-25,SCREEN_HEIGHT-8*2);
  display.print(escFront.getCmdR());
  display.setCursor(25,SCREEN_HEIGHT-8*1);
  display.print(escRear.getCmdL());
  display.setCursor(SCREEN_WIDTH-4*7-25,SCREEN_HEIGHT-8*1);
  display.print(escRear.getCmdR());
  
  /*
  display.setTextSize(1);
  display.setCursor(1,SCREEN_HEIGHT-8*2);
  display.print("minCMD=");
  display.print(min(min(min(escFront.getCmdL(),escFront.getCmdR()),escRear.getCmdL()),escRear.getCmdR()));

  display.print(" thrpos=");
  display.print(throttle_pos);
  */
}


void display_standingDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear) {
  //Display stuff here when ESCs are powered on and bobbycar is armed but was not moving for a while

  double _displaytrip=trip;
  //double _displaycurrent=currentConsumed;
  double _displaywatthours=watthoursConsumed;
  bool _displayOverall= ((millis()/2500)%2==0); //switch based on time
  
  
  

  char buf[8];

  display.setFont();
  display.setCursor(0,0);

    

  if (_displayOverall) { //alternate between this trip and overall trip
    _displaytrip=overallTrip;
    //_displaycurrent=overallCurrentConsumed;
    _displaywatthours=overallWatthoursConsumed;
  }


  //Row 1
  display.print(F("Vbat:")); display.print(escFront.getFeedback_batVoltage());
  display.print(F("/")); display.print(escRear.getFeedback_batVoltage());
  display.print(" V");
  display.println();


  //Row 2
  //display.print(F("Temp:")); display.print(escFront.getFeedback_boardTemp());
  //display.print(F("/")); display.print(escRear.getFeedback_boardTemp());
  display.print(F("T:")); display.print(temp_Front,0);
  display.print(F("/")); display.print(temp_Rear,0);
  display.print(F("/")); display.print(temp_Air,0);
  display.print(" C");
  display.println();

  //Row 3
  display.print(F("Trip:"));
  dtostrf(_displaytrip,1,0,buf);
  display.print((String)buf);
  display.print("m ");
  //dtostrf(_displaycurrent,1,2,buf);
  dtostrf(_displaywatthours,1,2,buf);
  display.print((String)buf);
  //display.print(" Ah");
  display.print("Wh");
  display.println();

  //Row 4

  display.print(F(""));
  //dtostrf( _displaytrip/1000/_displaycurrent ,1,2,buf);
  dtostrf( _displaywatthours/_displaytrip*100,1,2,buf);
  display.print((String)buf);
  //display.print(" km/Ah");
  display.print(" kWh/100km");

  if (_displayOverall){
    display.print(" sum");
  }


  display.println();



}


void display_standingDisarmedDisplay(ESCSerialComm& escFront, ESCSerialComm& escRear) {
  //Displayed stuff here when escs are powered off / disconnected or bobbycar is not armed
  char buf[8];
  display.setFont();
  display.setCursor(0,0);

  

  switch(standingDisplayScreen) 
  {
    case 0:
    //Quick overview of inputs and status

    //Row1
    if (getDatalogging()) {
      display.print(getLogFilename());
    }else{
      display.print("LOG DISABLED");
    }
      
    display.print(F(" ")); display.print(loopmillis/1000);
    display.print(F("s"));
    display.println();

    //Row2

    display.print("Throttle ");
    dtostrf(ads_throttle_A_raw,1,0,buf);
    display.print((String)buf);
    display.print("/");
    dtostrf(ads_throttle_B_raw,1,0,buf);
    display.print((String)buf);
    display.println();

    //Row3

    display.print("Brake ");
    dtostrf(ads_brake_raw,1,0,buf);
    display.print((String)buf);  
    display.println();


    
    /*display.print(" c=");
    dtostrf(ads_control_raw,1,0,buf);
    display.print((String)buf);  */


    break;

  case 1:
    //Trip Stats (trip / overall)

    //Row 1
    display.print(F("Trip ")); display.print(trip,0); display.print(F(" / ")); display.print(overallTrip,0); display.print(F("m"));
    display.println();
    //Row 2
    display.print(F("Curr ")); display.print(currentConsumed*1000,0); display.print(F(" / "));  display.print(overallCurrentConsumed*1000,0); display.print(F("mAh"));
    display.println();
    //Row 3
    display.print(F("Pow ")); display.print(watthoursConsumed,0); display.print(F(" / "));  display.print(overallWatthoursConsumed,0); display.print(F("Wh"));
    display.println();

    break;

  case 2:
    //Configuration parameters

    //Row 1
    display.print(F("cmdred min=")); display.print(minimum_constant_cmd_reduce);
    display.print(F(" p=")); display.print(brake_cmdreduce_proportional);
    display.println();

    //Row 2

    display.print(F("brkI="));
    dtostrf(startbrakecurrent,1,1,buf);
    display.print((String)buf);
    display.print("A");
    display.print(F(" free="));
    dtostrf(freewheel_break_factor,1,1,buf);
    display.print((String)buf);
    display.println();

    //Row 3

    display.print(F("thrmax=")); display.print(throttle_max);
    display.print(F(" rev="));
    dtostrf(reverse_speed,1,2,buf);
    display.print((String)buf);
    display.println();

    break;

  }

  //Put User Inputs in last row
  //Row 4
  display.setCursor(0,24);
  if (button_start_state){
    display.print("S");
  }else{
    display.print(" ");
  }
  if (control_buttonB){
    display.print("B");
  }else{
    display.print(" ");
  }
  if (control_buttonA){
    display.print("A");
  }else{
    display.print(" ");
  }

  if (escFront.getControllerConnected()){
    display.print("F");
  }else{
    display.print(" ");
  }
  if (escRear.getControllerConnected()){
    display.print("R");
  }else{
    display.print(" ");
  }

  display.setCursor(SCREEN_WIDTH-6*3,24);
  display.print(standingDisplayScreen);
  display.print("/"); display.print(NUM_STANDINGDISPLAYSCREEN-1);

  
  


}

#endif