#include <SD.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
 
#define TFT_CS 10
#define TFT_DC 9
#define TFT_RST 8
Adafruit_ILI9341 tft= Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
#define KEY_UP 3
#define KEY_SEL 4
#define KEY_DOWN 5
int file_num = 0; // поточний (вибраний) файл
int file_cnt = 0; // кількість файлів у каталозі
File fl;
#define MAX_CURSOR_Y 300
int char_width, char_height;
unsigned long positions[100];
int page;
void setup() {
  pinMode(KEY_UP, INPUT_PULLUP);
  pinMode(KEY_SEL, INPUT_PULLUP);
  pinMode(KEY_DOWN, INPUT_PULLUP);
  tft.begin();
  Serial.begin(115200);
  if ( SD.begin( 7 ) ){
     Serial.println("Card is found"); 
     while ( true ) {
      select_file();
      open_file();
      prepare_screen();
      display_pages();
     }
  }
}
void prepare_screen(){
  tft.setTextSize(1);
  tft.setCursor(0,0);
  tft.println();
  tft.print(" ");
  char_width = tft.getCursorX();
  char_height = tft.getCursorY();
  Serial.print("cx=");Serial.println( char_width );
  Serial.print("cy=");Serial.println( char_height );
  tft.setCursor(0,0);
  page = 0;
}
void open_file(){
  File dir = SD.open("/");
  int cur_file = 0;
  while ( true ) {
    fl = dir.openNextFile();
    if ( fl ) {
      if ( cur_file == file_num ) {
        Serial.print("Open file ");
        Serial.println( fl.name() );
        break;
      }
      cur_file++;
    }
    else {
      break;
    }
    fl.close();
  }
  dir.close();
}
void display_pages(){
  show_next_page();
  while ( true ) {
    if ( digitalRead(KEY_UP) == 0 ) {
      if (page > 0) {
        page--;
        fl.seek(positions[page]);
        show_next_page();
      }      
    }
    if ( digitalRead(KEY_DOWN) == 0 ) {
      if ( fl.available() ) {
        page++;
        positions[page] = fl.position();
        show_next_page();
      }
    }
    if ( digitalRead(KEY_SEL) == 0 ) {
      fl.close();
      tft.fillScreen( ILI9341_BLACK );
      break;
    }
  }
}
void print_pages(){
  Serial.print(" > ");
  for (int i=0; i<10; i++) {
    Serial.print( positions[i] ); Serial.print(" ");
  }
  Serial.println();
}
void prepare_page(){
  tft.fillScreen( ILI9341_BLACK );
  tft.setCursor(0,0);
  Serial.print("page ");Serial.print(page);
  Serial.print(" pos=");Serial.print( fl.position() );
  print_pages();
}
void show_next_page(){
  char c;
  prepare_page();
  while ( fl.available() ) {
    if ( tft.getCursorY() + char_height >= MAX_CURSOR_Y ) break;
    if ( tft.getCursorX() + char_width >= 240 )  {
      if ( tft.getCursorY() + 2*char_height >= MAX_CURSOR_Y ) break;
    }
    //Serial.print(" x=");Serial.print(tft.getCursorX());Serial.print(" y=");Serial.println(tft.getCursorY());
    c = fl.read();
    tft.print( c );
  }
  tft.drawFastHLine(0,MAX_CURSOR_Y,240,ILI9341_YELLOW);
}
void select_file(){
  show_dir();
  for (;;) {
    if ( digitalRead(KEY_UP) == 0 ) {
      if (file_num > 0) file_num--;
      show_dir();
    }
    if ( digitalRead(KEY_DOWN) == 0 ) {
      if ( file_cnt > file_num+1 ) file_num++;
      show_dir();
    }
    if ( digitalRead(KEY_SEL) == 0 ) {
      break;
    }
  }
  Serial.print("Select file ");
  Serial.println( file_num );
}
void show_dir() { // показати вміст головного каталогу
  tft.setTextSize(2);
  tft.setCursor(0,0);
  File dir = SD.open("/");
  int cur_file = 0;
  while ( true ) {
    File f = dir.openNextFile();
    if ( f ) {
      /*
      Serial.print( f.name() );
      Serial.print( "\t" );
      Serial.println( f.size() );
      */
      if ( file_num == cur_file ) {
        tft.setTextColor( ILI9341_WHITE );
        tft.print("--> ");
      }
      else {
        tft.setTextColor( ILI9341_BLACK );
        tft.print("--> ");
        tft.setTextColor( ILI9341_WHITE );
      }
      tft.println( f.name() );
      cur_file++;
      file_cnt = cur_file;
    }
    else {
      break;
    }
    f.close();
  }
  dir.close();
}
void loop() {
  // put your main code here, to run repeatedly:
}