#ifndef Buttongrid_h
#define Buttongrid_h

#include "Adafruit_SH110X.h"
#include "Adafruit_GFX.h"
#include "potentiometers.h"
#include "buttons.h"
#include "ui.h"


extern Potentiometer pot_1, pot_2, pot_3, pot_4, pot_5, pot_6, pot_7;
extern Button button_1, button_2, button_3, button_4, button_5, button_6;
extern Adafruit_SH1106G display;

// Represents the different types of GridButtons in the UI
enum ButtonType {
  BUTTON_TYPE_SIMPLE,       // Simple Button that can be pressed
  BUTTON_TYPE_TOGGLE,       // Toggles between two values (name needs to have a break "\n")
  BUTTON_TYPE_MULTITOGGLE,  // Toggles between two or more values (name needs to have a break "\n")
  BUTTON_TYPE_ENUM,         // Toggles between a group of buttons
  BUTTON_TYPE_LAST
};

// A Gridbutton is a single button within the Ui-Button Grid
// The name can have multiple lines, delimited by "\n" which
// will be used to represent different states for buttons of
// the type BUTTON_TYPE_TOGGLE or BUTTON_TYPE_MULTITOGGLE
// is_home tells us if this is the home button (and thus should
// be rendered inverted)
class GridButton {
  public:
    const char* name;
    const char* description;
    GridButton(const char* name, Button *button, bool is_home=false, ButtonType type=BUTTON_TYPE_SIMPLE, int default_value=0, const char* description="")
     : 
      name(name),
      button(button),
      is_home(is_home),
      type(type),
      active(default_value),
      description(description)
    {
      // Count the number of lines in the name
      for(int i = 0; name[i] != '\0'; i++) {
          if(name[i] == '\n')
              ++lines;
      }
    }
    Button *button;
    ButtonType type;
    bool is_home;
    bool should_render_description = false;
    int active;
    int lines = 0;
    
    // Go to the next option
    void next() {
      active++;
      if (active > lines) {
        active = 0;
      }
    }

    void renderDescription() {
      if (should_render_description) {
        display.setTextWrap(true);
        display.clearDisplay();
        display.setCursor(0,0);
        display.setTextColor(SH110X_WHITE);
        display.print(description);
        display.setTextWrap(false);
      }
    }
};

// The ButtonGrid is a grid of 2×3 = 6 buttons
class ButtonGrid {
  public:
    ButtonGrid(int home_mode, const GridButton (&grid_buttons)[6]) 
    : grid_buttons_{
        grid_buttons[0], 
        grid_buttons[1], 
        grid_buttons[2], 
        grid_buttons[3], 
        grid_buttons[4], 
        grid_buttons[5]
      },
      ui_mode(home_mode)
    {}
    GridButton grid_buttons_[6];
    int ui_mode;

    void setup() {
      for (int n=0; n<6; n++) {
        if (!grid_buttons_[n].is_home) {
          // Not a home button, display help on long hold and hide on release
          grid_buttons_[n].button->onLongHold([this, n](){
            grid_buttons_[n].should_render_description = true;
          });
          grid_buttons_[n].button->onReleased([this, n](){
            grid_buttons_[n].should_render_description = false;
          });
        }
      }
    }

    int homeButtonIndex() {
      for (int i=0; i<6; i++) {
        if (grid_buttons_[i].is_home) {
          return i;
        }
      }
      return -1;
    }

    void hideAllDescriptions() {
      for (int i=0; i<6; i++) {
        grid_buttons_[i].should_render_description = false;
      }
    }

    void render(int button_enum) {
      int width = display.width();
      int height = display.height();
      int box_width = int(width/3.0f);
      int box_height= int(height/2.0f);
      int i = 0;
      // Draw boxes (2 rows, 3 columns)
      for (int box_y=0; box_y<2; box_y++) {
        for (int box_x=0; box_x<3; box_x++) {
          // Get the current buttons name
          const char* name = grid_buttons_[i].name;

          // Prepare colors
          uint16_t bg_color = SH110X_BLACK;
          uint16_t text_color = SH110X_WHITE;

          // Home-Buttons have a inverted color scheme
          if (grid_buttons_[i].is_home) {
            bg_color = SH110X_WHITE;
            text_color = SH110X_BLACK;
          }

          // Position variables
          uint16_t x = box_x * box_width;
          uint16_t y = box_y * box_height;
          uint16_t xc = x + box_width/2;
          uint16_t yc = y + box_height/2;

          // Fill Background
          display.fillRect(x, y, box_width, box_height, bg_color);

          // Render the different button types
          if (grid_buttons_[i].type == BUTTON_TYPE_TOGGLE) {
            centeredTextMarkMulti(name, xc, yc, text_color, grid_buttons_[i].active, 12);
          } else if (grid_buttons_[i].type == BUTTON_TYPE_MULTITOGGLE) {
            button_multi(name, xc, yc, text_color, grid_buttons_[i].active, grid_buttons_[i].lines);
          } else if (grid_buttons_[i].type == BUTTON_TYPE_ENUM) {
            bool active = i == button_enum;
            centeredTextMark(name, xc, yc, text_color, active);
          } else {
            centeredText(name, xc, yc, text_color);
          }
          // Increase ounter for the index of the button
          i++;
        }
      }
      
      // Draw divider lines
      display.drawFastVLine(box_width, 0, height, SH110X_WHITE);
      display.drawFastVLine(box_width*2, 0, height, SH110X_WHITE);
      display.drawFastHLine(0, box_height, width, SH110X_WHITE);

      // Render Descriptions on top (hence another loop)
      i = 0;
      // Draw boxes (2 rows, 3 columns)
      for (int box_y=0; box_y<2; box_y++) {
        for (int box_x=0; box_x<3; box_x++) {
          grid_buttons_[i].renderDescription();
          i++;
        }
      }
    }
};


#endif