//e
int menu_array[(menu_option_lines*2)+1];
int eeprom_current_integers[(menu_option_lines)+1]; //loads the integers from eeprom, and then is edited while running to be saved later
int eeprom_integer_min_max[menu_option_lines*2]; //stores min/max values for integers //todo change to min/max of current line when going to editing mode
int eeprom_decimal_values[menu_option_lines+1];//todo
int loaded_eeprom_min; //todo not done yet, when editing an integer, the min value is loaded into this int
int loaded_eeprom_max; //todo not done yet, when editing an integer, the max value is loaded into this int

bool display_clearDisplay = false;
bool display_update_cursor = false;
bool display_update_integers = false;
bool display_update_menu_text = false;

boolean in_navigate_state;
uint8_t previous_total_offset; //todo when writing the integer on the screen, if the offset is larger than before, write blanking line on screen

int font_width;
int font_hight;

int menu_shown_min_max[2]; //min and maximum line that is displayed on screen, gets reset on menu change
int menu_shown_min_max_prev[2]; //old min and maximum line that was displayed on previously, to efficiently clear display
int cursor_selected_menu_option = 1;
int cursor_position_on_screen = 0;

class SSD1306_Menu
{
  public:

//EEPROM
  void update_eeprom_integers(int bank_number, int new_int_value){ //update running config, used when editing an integer
     
      int n = 0;
      while(1)
       {
        if(n > menu_option_lines){break;}

        if(line_variable_number(n) == bank_number){
          if(line_type_mapper(line_type(n)) == 'E'){break;}
        }

        n=n+1; //check the next line
       }
      eeprom_current_integers[n] = new_int_value;
  }

  int load_running_eeprom_integers(int bank_number){ //reads int from running config (ussualy to apply the change in real time)
      int n = 0;
      //while(eeprom_current_integers[n] != bank_number && line_type_mapper(lenght_of_integer_and_menu_line_type[n+1]) != 'E')
      while(1)
       {
        if(n > menu_option_lines){break;}

        if(line_variable_number(n) == bank_number){
          if(line_type_mapper(line_type(n)) == 'E'){break; Serial.println("OK");}
        }

        n=n+1; //check the next line
       }
       Serial.print("loaded from running: "); Serial.print(line_type_mapper(line_type(n/2))); Serial.println(eeprom_current_integers[n]);
      return eeprom_current_integers[n];
  }

  void save_eeprom_integers(){ //write the current running config integers to eeprom
      int n = 0;
      while(n < menu_option_lines)
       {
        save_to_EEPROM(line_variable_number(n),eeprom_current_integers[n]);
        n=n+1;
       }
  } 
//


  void Setup(int menu_options, char menu_option_text[]){ //set variables to default
    //lenght_of_integer_and_menu_line_type[(cursor_selected_menu_option*2)+1] = '0';

    //font_width = 1;
    //font_hight = 1;

    cursor_selected_menu_option = 0;
    
    display_clearDisplay = false;
    display_update_cursor = true;
    display_update_integers = true;
    display_update_menu_text = true;

      int menu_options_lenght[menu_options];
    int i = 0;
    int a = 0;
    int n = 0;

    do
    {
      a = menu_option_text[i]+1;
   
   //---------------   
      if(menu_option_text[i]=='['){ //if there is eeprom read mark
      
      //lenght_of_integer_and_menu_line_type[n-1] = menu_option_text[i+1]; //save line type
       //Serial.print(n); Serial.print(" line_type"); Serial.println(lenght_of_integer_and_menu_line_type[n+1]);

     

        if(menu_option_text[i+1]!='R'){
        
          eeprom_current_integers[(n/2)-1] = load_from_eeprom(menu_option_text[i+2]);

          //Serial.print("x:"); Serial.println(menu_option_text[i+2]); //save int location in eeprom 
          //Serial.print("l:"); Serial.println(eeprom_current_integers[n+1]); //loaded value from eeprom
        }

      
      
        while(menu_option_text[i-1]!=']'){i++;}//skip the "[**]" (eeprom readmark)
        //i=i+4;
        a = 0;
        a = menu_option_text[i]+1;
      }
      Serial.print("spacing:"); Serial.println(i);
      menu_array[n] = i;

      Serial.print("lenght:"); Serial.println(a);
      menu_array[n+1] = a;

      i = i + a;
      n = n + 2;
    }
    while (n < (menu_option_lines*2)+1);
    
    in_navigate_state = true;
    

  }

int get_decimal_multipl(uint8_t dec_places){
  int i = 1;
  int dec = 1;
  while(i<=dec_places){i++, dec = dec*10;}
  return dec;
}

char line_type_mapper(char input_line_type = 0){ //decides what line type the current line is
  if (input_line_type == 'E'){return 'E';} //E integer refresh
  if (input_line_type == 'F'){return 'E';} //F full refresh
  if (input_line_type == 'R'){return 'H';} //R redirrect
  if (input_line_type == 'I'){return 'E';} //I integer refresh
  if (input_line_type == 'D'){return 'E';} //I integer refresh
  return 'H';
}

char line_type(int input_line = cursor_selected_menu_option){
  if(main_menu_option_text[line_text_end(input_line)+1] == '['){
    return main_menu_option_text[line_text_end(input_line)+2];
  }
  return 0;
}

int line_get_min_value(int input_line = cursor_selected_menu_option){
  return eeprom_integer_min_max[input_line*2];;
}

int line_get_max_value(int input_line = cursor_selected_menu_option){
  return eeprom_integer_min_max[input_line*2+1];
}

int line_variable_number(int input_line = cursor_selected_menu_option){


  if(main_menu_option_text[line_text_end(input_line)+1] == '['){
    return main_menu_option_text[line_text_end(input_line)+3];
  }
  return 0;

}

int line_variable_decimal_palce(int input_line = cursor_selected_menu_option){
  if(main_menu_option_text[line_text_end(input_line)+1] == '[' && line_type_mapper(line_type(input_line)) == 'E'){
    return main_menu_option_text[line_text_end(input_line)+4];
  }
  return 0;
}

int line_variable_value(int input_line = cursor_selected_menu_option){
  return eeprom_current_integers[input_line];
}

int line_variable_value_lenght(int input_line = cursor_selected_menu_option){ //lenght in characters
  int value = line_variable_value(input_line);// --> load integer
  if(line_type_mapper(line_type(input_line)) != 'E'){return 0;}

  int lenght = 0;

  //        if(line_variable_decimal_palce(input_line) > 0 && ){
  //      lenght = lenght - line_variable_decimal_palce(input_line);
    //  }
  if (line_type(input_line) == 'D'){ //decimal
  lenght = lenght + 4;
  if(value<0){lenght = lenght + 1; value = value*(-1);}

  if(value >= 1000){lenght = lenght +1;}
  if(value >= 10000){lenght = lenght +2;}
  if(value >= 100000){lenght = lenght +3;}
  return lenght;
 }

 if (value<0){lenght = lenght + 1; value = value*(-1);}

    if (value>=0 && value<10){lenght = lenght + 1;}
    if (value>=10 && value<100){lenght = lenght + 2;}
    if (value>=100 && value<1000){lenght = lenght + 3;}
    if (value>=1000 && value<10000){lenght = lenght + 4;}

  return lenght;
}
  

int line_text_start(int input_line = cursor_selected_menu_option){
  return menu_array[input_line*2]+1;
}

int line_text_end(int input_line = cursor_selected_menu_option){
  return line_text_start(input_line)+menu_array[input_line*2+1]-2;
}

int page_max_lines_on_screen(){
  return (8/font_hight)-1;
}

int page_line_start(uint8_t page = menu_number){
  int c=0;
  int n=0;
  if(page != 0)
    { 
      do{n=n+menu_options_section_lenght[c]; c++;}while(c!=page);
    };
  return n;
}

int page_line_end(uint8_t page = menu_number){
  int c=0;
  int n=0;

  do{n=n+menu_options_section_lenght[c]; c++;}while(c!=page+1);

  return n-1;
}


void reset_menu_shown_min_max(){
  Serial.print("page_max_lines_on_screen(): "); Serial.println(page_max_lines_on_screen());
  menu_shown_min_max[0]=page_line_start();
  menu_shown_min_max[1]=page_line_end();
  
  
  if(menu_shown_min_max[1]>page_max_lines_on_screen()+page_line_start()){
    menu_shown_min_max[1]=page_max_lines_on_screen()+page_line_start();
  }
}

void set_cursor_position_on_screen(int position = 0){
  cursor_position_on_screen = position;
}

void move_menu_shown_min_max(char direction){
  Serial.print("page_line_end()"); Serial.print(page_line_end()); Serial.print("   menu_shown_min_max[1]: "); Serial.println(menu_shown_min_max[1]);
  

  if(cursor_position_on_screen > menu_shown_min_max[1]-menu_shown_min_max[0]){
    Serial.println("EEE");
    if(direction == '+' && page_line_end() > menu_shown_min_max[1]){
      menu_shown_min_max_prev[0]=menu_shown_min_max[0];
      menu_shown_min_max_prev[1]=menu_shown_min_max[1];
      menu_shown_min_max[0]++;
      menu_shown_min_max[1]++;
      cursor_position_on_screen = page_max_lines_on_screen();
      display_update_menu_text = true;
      display_update('i', 'm');
    }
  }
  
 Serial.print("HERE on_screen: "); Serial.print(cursor_position_on_screen); Serial.print("   min_max0: "); Serial.println(menu_shown_min_max[1]-page_max_lines_on_screen()-1);
  if(cursor_position_on_screen == (menu_shown_min_max[1]-page_max_lines_on_screen()-1)-(menu_shown_min_max[0])){
    Serial.println("OOO");
    if(direction == '-' && menu_shown_min_max[0]>page_line_start()){
      menu_shown_min_max_prev[0]=menu_shown_min_max[0];
      menu_shown_min_max_prev[1]=menu_shown_min_max[1];
      menu_shown_min_max[0]--;
      menu_shown_min_max[1]--;
      cursor_position_on_screen = 0;
      display_update_menu_text = true;
      display_update('i', 'm');
      //display_clearDisplay = true;
    }
  }
  
  
}

int last_writable_line(int first_line){
  int last_line;
  last_line = first_line+page_max_lines_on_screen();
  if(last_line > first_line+page_max_lines_on_screen()){last_line = first_line+page_max_lines_on_screen();}
  return last_line;
}



void cursor_move_up(){
  if(cursor_position_on_screen < (page_line_end()-page_line_start())){cursor_position_on_screen++;}
  else{return;}
  //Serial.println(line_text_end()-line_text_start());
  
  cursor_selected_menu_option = cursor_position_on_screen+page_line_start()+(menu_shown_min_max[0]-page_line_start());
  display_update_cursor = true;
  move_menu_shown_min_max('+');
  if(cursor_position_on_screen>page_max_lines_on_screen()){cursor_position_on_screen = page_max_lines_on_screen();}
  if(cursor_selected_menu_option>page_line_end()){cursor_selected_menu_option = page_line_end();}
}

void cursor_move_down(){
  cursor_position_on_screen--;
  cursor_selected_menu_option = cursor_position_on_screen+page_line_start()+(menu_shown_min_max[0]-page_line_start());
  display_update_cursor = true;
  move_menu_shown_min_max('-');
  if(cursor_position_on_screen<0){cursor_position_on_screen = 0;}
  if(cursor_selected_menu_option<page_line_start()){cursor_selected_menu_option = page_line_start();}
}

void write_out_cursor(){

  if(display_update_cursor == false){return;}
 //page_max_lines_on_screen(), cursor_position_on_screen display.setCursor(0,i)
 int i = 0;
 int spacing = 0;
 int m = menu_shown_min_max[1]-menu_shown_min_max[0]+1;
 //if(m>menu_shown_min_max[1]+1){m=menu_shown_min_max[1]+1;}
  Serial.println(m);

 while(i<m){
   display.setCursor(0,spacing);
   if(i==cursor_position_on_screen){display.print(">");}
   else(display.print(" "));
   if(i>=menu_shown_min_max[1]+1){break;}

   i++;
   spacing=spacing+font_hight;
 }

  display_update_cursor = false;
}

void write_out_integer_range(int first_line, int last_line = -1){
  #define prev_lenght_offset (menu_shown_min_max[0]-menu_shown_min_max_prev[0])

  if(display_update_integers == false){return;}


  //int c = 0;


 int line_selected = first_line;
 if(last_line == -1){last_line=last_writable_line(first_line);}
 if(last_line > page_line_end()-page_line_start()){last_line = page_line_end();}
 
 Serial.print("last: "); Serial.println(last_line-first_line);

 Serial.println("---------");
 do{
    #define  old_lenght                 line_variable_value_lenght((line_selected)-prev_lenght_offset)
    #define  current_lenght             line_variable_value_lenght(line_selected)
    #define  maximum_display_position   display.getCols()- (font_width*1)-1
    #define integer_line                line_selected-menu_shown_min_max[0]

    Serial.print("c: "); Serial.println(integer_line);
    
    //Serial.print("   line_variable_value: "); Serial.print(line_variable_value(line_selected));
    //Serial.print("   current_lenght: "); Serial.print(current_lenght);
    //Serial.print("   old_lenght: "); Serial.println(old_lenght);
    //Serial.print("maximum_display_position: "); Serial.println(maximum_display_position);
    
    if(current_lenght < old_lenght){
      int n = 0; 
      while(current_lenght+n<old_lenght+0){ //+2 for the '[]'
        display.setCursor(display.getCols()-old_lenght+n-0, integer_line); //-2 for the '[]'
        display.print('#');
        //Serial.println(n);
        n++;
      }
    }
    
  
    if(line_variable_number()!=0 && line_type_mapper(line_type(line_selected)) == 'E'){ //if there is a EEPROM stored variable
      Serial.print("writing int on screen to line: "); Serial.println(line_selected);
      //lenght_of_integer_and_menu_line_type[line_selected+1] = 'E'; //E is EEPROM type of current selected line

      //fix the offset if the character was changed

      int value = line_variable_value(line_selected);// --> loaded integer
      uint8_t total_offset = maximum_display_position - (line_variable_value_lenght(line_selected)*(font_width))+2; //lenght_of_integer_and_menu_line_type[b/2] is the number of characters that have to he shifted for int to not go off the screen; 104 is the offset of the last character (]); 12 is the width of each character
      //Serial.println(total_offset);
      //Serial.println(previous_total_offset);
      if(previous_total_offset<total_offset){
        //Serial.println("CLEAR!!");
        display.setCursor(previous_total_offset,integer_line);
        display.print("#");
      }
      previous_total_offset = total_offset;

      //display.setCursor(f, c-16);
      display.setCursor(total_offset, integer_line);

      //Serial.println(c-(8*font_width));
      int g=0;
      //int dec=100;

       float gf = value;
       float value_f;
        if(line_type(line_selected)== 'D'){
          float gf = value;
          float value_f;
          value_f = gf/get_decimal_multipl(line_variable_decimal_palce(line_selected));
          display.print(value_f);
        }else(display.print(value));

    Serial.println("font_hight++");
  
    }

  line_selected++;
  Serial.println("line_selected++");

  }while(line_selected < last_line+1);
   //while(line_selected/2 < 11);

  display_update_integers = false;

}

void write_out_text_range(int first_line, int last_line = -1, int offset = 0){
  #define prev_line_offset (menu_shown_min_max[0]-menu_shown_min_max_prev[0])

  if(display_update_menu_text == false){return;}
  int line_selected = first_line;
  if(last_line == -1){last_line=last_writable_line(first_line);}

  while(line_selected <= last_line){
    #define  old_lenght         line_text_end(line_selected-prev_line_offset)-line_text_start(line_selected-prev_line_offset)
    #define  current_lenght     line_text_end(line_selected)-line_text_start(line_selected)


    if(old_lenght>current_lenght){Serial.print("Clean line: "); Serial.print(line_selected);}
    else{Serial.print("   Do NOT clean line: "); Serial.print(line_selected);}

    //Serial.print("   current_lenght: "); Serial.print(current_lenght);
    //Serial.print("   old_lenght: "); Serial.println(old_lenght);

    display.setCursor(1, offset);
    offset=offset+font_hight;
    int i = 0;
    
    while(line_text_start(line_selected)+i <= line_text_end(line_selected)){ //print text
      char c = main_menu_option_text[line_text_start(line_selected)+i];
      display.print(c);
      i++;
    }

    while(line_text_start(line_selected)+i <= line_text_start(line_selected)+old_lenght){ //print blank to clear previous test
      display.print(" ");
      i++;
    }

    line_selected++;
  }
  display_update_menu_text = false;
}

void Up(){ //if in_navigate_state == ture, move cursor
    if(in_navigate_state == true){
      cursor_move_up();
      return;
    }

    if(in_navigate_state == false && line_type() == 'E'){
        eeprom_current_integers[cursor_selected_menu_option]++;
        Serial.println(line_get_max_value());

      
      display_update_integers = true;
      //return; //'E'
    }

    if(in_navigate_state == false && line_type() == 'D'){
        eeprom_current_integers[cursor_selected_menu_option]++;
        Serial.println(line_get_max_value());

      
      display_update_integers = true;
      //return; //'E'
    }

    if(in_navigate_state == false && line_type() == 'F'){
        int i=line_variable_value()+1;
        Serial.print("up");
        Serial.println(i);
        update_eeprom_integers(line_variable_number(), i);
        display_clearDisplay = true;
        //return;
      }
      if(line_variable_value() > line_get_max_value()){ //if its larger than maximum allowed value, reset to maximum allowed value
          eeprom_current_integers[cursor_selected_menu_option] = line_get_max_value();
      }
}

void Down(){ //if in_navigate_state == true, move cursor

    if(in_navigate_state == true){
      cursor_move_down();
      return;
    }
    
    if(in_navigate_state == false && line_type() == 'E'){
      if(eeprom_integer_min_max[(cursor_selected_menu_option*2)+0] < eeprom_current_integers[cursor_selected_menu_option]){
        eeprom_current_integers[cursor_selected_menu_option]--;
        //Serial.println((cursor_selected_menu_option*2)+1);
        if(eeprom_current_integers[cursor_selected_menu_option] > eeprom_integer_min_max[(cursor_selected_menu_option*2)+1]){ //if its larger than maximum allowed value, reset to maximum allowed value
          eeprom_current_integers[cursor_selected_menu_option] = eeprom_integer_min_max[(cursor_selected_menu_option*2)+1];
        }
      }
      display_update_integers = true;
      //return;
    }

    if(in_navigate_state == false && line_type() == 'D'){
      if(eeprom_integer_min_max[(cursor_selected_menu_option*2)+0] < eeprom_current_integers[cursor_selected_menu_option]){
        eeprom_current_integers[cursor_selected_menu_option]--;
        //Serial.println((cursor_selected_menu_option*2)+1);
        if(eeprom_current_integers[cursor_selected_menu_option] > eeprom_integer_min_max[(cursor_selected_menu_option*2)+1]){ //if its larger than maximum allowed value, reset to maximum allowed value
          eeprom_current_integers[cursor_selected_menu_option] = eeprom_integer_min_max[(cursor_selected_menu_option*2)+1];
        }
      }
      display_update_integers = true;
      //return;
    }

    if(in_navigate_state == false && line_type() == 'F'){
      Serial.println("F");
      if(eeprom_integer_min_max[(cursor_selected_menu_option*2)+0] < eeprom_current_integers[cursor_selected_menu_option]){
        eeprom_current_integers[cursor_selected_menu_option]--;
        Serial.print("modifying: "); Serial.println((cursor_selected_menu_option*2)+1);
        if(eeprom_current_integers[cursor_selected_menu_option] > eeprom_integer_min_max[(cursor_selected_menu_option*2)+1]){ //if its larger than maximum allowed value, reset to maximum allowed value
          eeprom_current_integers[cursor_selected_menu_option] = eeprom_integer_min_max[(cursor_selected_menu_option*2)+1];
        }
      }
        display_clearDisplay = true;
        //return;
    }
      if(line_variable_value() > line_get_max_value()){ //if its larger than maximum allowed value, reset to maximum allowed value
        eeprom_current_integers[cursor_selected_menu_option] = line_get_max_value();
      }
}

void Ok(){ //get state of variables

    Serial.print("line_type()"); Serial.println(line_type());

    if(line_type() == 'R'){
      redirect();
      return;
    }

    if(in_navigate_state == false){
      //Serial.println("e");
      in_navigate_state = true;
      return;
    }

    Serial.print("state "); Serial.println(in_navigate_state);
    Serial.print("type" ); Serial.println(line_type());

    if(in_navigate_state == true &&  line_type() != '0'){ //E is EEPROM type of current selected line
      
      in_navigate_state = false;
      return;
    }
}

void set_int_limit(int integer_ID, int MIN = -32768, int MAX = 32767){ //assigned eeprom number, min, max -saves to eeprom_integer_min_max[]
    //; //eeprom_integer_min_max[1,2] gets saved based on on what line integer_ID relative on the eeprom_current_integers
    int line_selected = 0;
    while(line_selected<menu_option_lines*2){
      if(line_variable_number(line_selected/2) == integer_ID && line_type_mapper(line_type(line_selected/2)) == 'E'){
        Serial.println("found");
        eeprom_integer_min_max[line_selected] = MIN;
        eeprom_integer_min_max[line_selected+1] = MAX;
        Serial.println("assigned MIN, MAX to line: ");Serial.println(line_selected/2);
      }else(Serial.println("Sadge"));

      line_selected=line_selected+2;
    }

}

void display_update(char a = 0, char b = 0, char c = 0){
  if(a+b+c == 0){
    a='m';
    b='c';
    c='i';
  }
  if(a == 'm' || b == 'm' || c == 'm'){
    display_update_menu_text = true;
  }

  if(a == 'c' || b == 'c' || c == 'c'){
    display_update_cursor = true;
  }

  if(a == 'i' || b == 'i' || c == 'i'){
    display_update_integers = true;
  }
}

void redirect(int input_line = cursor_selected_menu_option){
  menu_number = line_variable_number(input_line); //redirect to submenu of the currently selected line
  reset_menu_shown_min_max();
  set_cursor_position_on_screen(0);
  cursor_selected_menu_option = page_line_start();
  //Serial.println(cursor_selected_menu_option*2);
  display_clearDisplay = true;
}
};