#include <UTFT.h>
#include <URTouch.h>
#include <Wire.h>
#include <SPI.h>
#include <SdFat.h>
SdFile myFile;
#include <UTFT_SdRaw.h>
#include "GyverTimer.h"   // подключаем библиотеку
GTimer myTimer(MS);  // создать миллисекундный таймер (ms) (по умолч. в режиме интервала)
//myGLCD.setBackColor(VGA_TRANSPARENT);
//UTFT_Buttons  myButtons(&myGLCD, &myTouch);
//#include <pwm01.h>
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
extern uint8_t Ubuntubold[];
#define imagedatatype  unsigned short
extern imagedatatype cl[];
unsigned short pic1[0x320];

#define TOUCH_ORIENTATION  LANDSCAPE
UTFT myGLCD(ITDB50, 38, 39, 40, 41); //byte model, int RS, int WR,int CS, int RST, int SER=0);
UTFT_SdRaw myFiles(&myGLCD);
//int k1=2;//размер экрана 1-240х320 2-480х640
int led = 13;
URTouch  myTouch(42, 43, 44, 45, 47); //TCLK, TCS, TDIN, TDOUT и IRQ.Папа
const int chipSelect = 10;
int xt, yt;
int day1, month1, year1, h1, m1, s1; //время дата
char* str[] = {"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
byte dow ;


#define SD_CHIP_SELECT  2  // SD chip select pin
// file system object
SdFat sd;

#include <EncButton.h>
EncButton<EB_TICK, VIRT_BTN> btn0;
EncButton<EB_TICK, VIRT_BTN> btn1;
EncButton<EB_TICK, VIRT_BTN> btn2;
EncButton<EB_TICK, VIRT_BTN> btn3;
EncButton<EB_TICK, VIRT_BTN> btn4;

#include <AnalogKey.h>
// создаём массив значений сигналов с кнопок
int16_t sigs[5] = {
  940, 900, 870, 820,
  10
};
extern uint8_t SevenSegNumFont[];
// указываем пин, количество кнопок и массив значений
AnalogKey<A1, 5, sigs> keys;
//********************PAINT***************************************************************************************
int color = 0;
word colorlist[] = {VGA_WHITE, VGA_BLACK, VGA_RED, VGA_BLUE, VGA_GREEN, VGA_FUCHSIA, VGA_YELLOW, VGA_AQUA};
int  bsize = 4;
//*******************************************************************************************************
int analogPin = 1; // определяем входной аналоговый пин
//VGA_BLACK, VGA_WHITE, VGA_RED, VGA_GREEN, VGA_BLUE, VGA_SILVER, VGA_GRAY,
//VGA_MAROON, VGA_YELLOW, VGA_OLIVE, VGA_LIME, VGA_AQUA, VGA_TEAL, VGA_NAVY,
// VGA_FUCHSIA, VGA_PURPLE, VGA_TRANSPARENT-прозрачный.
#define BIRD_BG 0xB5D6
#define WHITE 0xFFFF
#define BLACK 0x0000
#define  RED 0xF800
#define BLUE 0x001F
#define GREEN 0x07E0
#define YELLOW 0xFFE0
#define MAGENTA 0xF81F
#define CYAN 0x881f
#define ORANGE 0xfbc0
#define GRAY 0xB5D6

#define BARDO 0xFC6F
int arrPins[] = {GRAY, VGA_BLUE, VGA_GREEN, MAGENTA, VGA_AQUA, YELLOW, VGA_RED, BARDO};

#define MaxX 7//кол-во кубиков по горизонтали
#define MaxY 16 //кол-во кубиков по вертикали +3 невидимых
#define SmeX 148// смещение стакана по горизонтали
#define SmeY 20//// смещение стакана по вертикали
#define LL 320
#define interval 320
#define razmer 36 // размер квадратика
#define NumCol 6 // количество цветов квадратиков
#define MaxLevel 8 // макс. кол-во уровней
#define NextLevel 20 // через сколько столбиков повышать уровень

int MasSt[MaxX][MaxY], MasTmp[MaxX][MaxY], MasOld[MaxX][MaxY], fignext[3];
int Level = 1, dx, dy, OldLevel, tr, flfirst = 1; // flfirst=? сменить для обнуления рекорда
uint16_t MasCol[] = {WHITE, BLACK, RED, BLUE, GREEN, YELLOW, MAGENTA, VGA_AQUA};
unsigned long TimeOfPush, Counter, Score = 0, TScore = 0, Record = 0, OldRecord, OldScore, myrecord;
word tempspeed;
bool fl, Demo = true, myfl = false, Arbeiten = false, FlNew, FlZ = false, gmov = false;
int16_t VAL, Mp, x, y;
int16_t mmm [4][2] = {{ -1, 0}, {0, -1}, {1, 0}, {0, 1}};
word MasSpeed[MaxLevel] = {500, 450, 400, 350, 300, 250, 200, 100}; // задержки уровней
bool valBtnL, valBtnR, valBtnT, valBtnPause, valBtnD;                                   // Объявляем  переменные для хранения состояния кнопок.
const  uint32_t tmrKeyHold      = 400;                                                // Определяем время в мс после которого нажатая кнопка будет считаться удерживаемой (залипание при нажатии кнопки).
bool exit_menu = 0;
void     ViewStacan         (void);
void     Touch_Init         (void);
void     gameover         (void);
//  void     GetNext         (void);
//   void    but         (void);
// void     ProcDemo         (void);
// void     NewGame         (void);
//void mydelay(int md);
// bool figmove(int dx, int dy);
//***********************************************************************************************************

//           BIRDUINO

//****************************************************************************************************
//#include "flappy_title.h"    // the latest version
//#include "bird05.h"   // the latest version
//#include "pillar01.h" // first version
//#include "pillar_end.h"
//#include "bottom_deco.h"
//#define BIRD_BMP_X 34
//#define BIRD_BMP_Y 24
#define BORD_BMP_X 68
#define BORD_BMP_Y 48
#define FLAPPY_TITLE_X 190
#define FLAPPY_TITLE_Y 51
#define BOTTOM_DECO_X 600
#define PILLAR_BMP_X 55
#define PILLAR_BMP_Y 1
#define PILLAR_END_BMP_X 55
#define PILLAR_END_BMP_Y 20
extern unsigned short pillar_end[0x44C];
//extern unsigned short pillar[0x37];
extern unsigned short pillar[0x6E];
extern unsigned short icon[0x25DA];
extern unsigned short bottom_deco[0x258];
extern unsigned short bird[0x330];
extern unsigned short bord[0xCC0];
extern unsigned short udar[0xCC0];
#define BIRD_BG 0x7639 // first value from the bird header file
#define TFTHEIGHT 800
#define TFTWIDTH 480
#define TEXT_POSITION_LEFT 50
#define TEXT_POSITION_CENTER 110
#define BOTTOM_AREA_Y 405
#define BOTTOM_AREA_BG_COLOR 0x// 221,216,150
#define BOTTOM_LINE_1_COLOR
// Floppy Bird
#define PILLAR_GAP 100 // pixels дырка в воротах
#define BIRD_X PILLAR_BMP_X // from the pillar header file
#define MOV_RATE_X0 3 // starting moving rate  стартовая скорость
#define FALL_RATE_Y 3 // starting falling rate

static int   yP = 100;

static int xP;

static int  yB;
static int movingRate, fallRateInt, steps;
static uint32_t fallRate;
static int score, level;
static int lastSpeedUpScore, highscore;
//static int screenPressed;
static boolean screenPressed, gameStarted, paused;
static uint32_t crt_millis, prev_millis;

static char s[250]; // for sprintf
//static void drawTitle(void);
int life = 3; // жизни
/*****************************************************************************/
static int tick;
/*****************************************************************************/
//********* TETRIS ***********************************************************
int arrPins1[] = {GRAY, CYAN , GREEN, MAGENTA, VGA_BLUE, YELLOW, ORANGE, VGA_RED};
int figcol = 0; // цвет фигуры
int figcol1 = 0; // цвет фигуры стола    //

#define         pinSeed   A0                                                          // Номер аналогового входа значения которого будут использованы для выбора случайной точки входа в последовательность псевдослучайных чисел, для корректной работы функции random().
#define         GAME_OFF  0                                                           // Одно из состояний игры (будет храниться в переменной state).
#define         GAME_ON   1                                                           // Одно из состояний игры (будет храниться в переменной state).
#define         GAME_OVER 2
/* Определяем настраиваемые значения: */                              //
const  uint16_t sumToNewLevel   = 20;                                                 // Определяем количество фигур которое нужно набрать для перехода на новый уровень.
const  uint16_t startTime       = 1000;                                               // Определяем начальное время в мс с которым фигура опускается на одну клетку игрового стола (начальная скорость игры).
const  uint16_t changeTimeLevel = 10;                                                 // Определяем значение в мс на которое уменьшается время опускания фигуры с каждым новым уровнем (увеличение скорости).
//const  uint32_t tmrKeyHold      = 400;                                                // Определяем время в мс после которого нажатая кнопка будет считаться удерживаемой (залипание при нажатии кнопки).
const  uint32_t  scrBoundary     = 400;//68;                                                 // Определяем границу отделяющую левую и правую части экрана.
const  uint32_t  newCubeSize     = 20;//6;                                                  // Определяем размер клеток в пикселях для поля отображения будущих фигур.
const  uint32_t  tableCubeSize   = 30;//3;                                                  // Определяем размер клеток в пикселях для игрового стола.
/* Объявляем массивы и переменные: */
const  uint32_t  Xsm = 137;
const  uint32_t  Ysm = 15;
const  uint32_t  tableRows       = 14;//(         480-3) / (tableCubeSize+1);                // Определяем количество строк    на игровом столе (зависит от размера клеток игрового стола). Количество = (высота экрана     - 3 линии) / (высота клеток игрового стола + 1 разделительная линия).
const  uint32_t  tableCols       = 10; // (scrBoundary-4) / (tableCubeSize+1);                // Определяем количество столбцов на игровом столе (зависит от размера клеток игрового стола). Количество = (ширина до границы - 4 линии) / (ширина клеток игрового стола + 1 разделительная линия).
uint32_t tableArray        [tableRows];                                        // Объявляем  массив клеток игрового стола. Каждый элемент массива - это строки игрового стола, а каждый бит это клетка на игровом столе (0-пуста, 1-закрашена).
uint8_t  figureArray       [6];                                                // Объявляем  массив для хранения вида движущейся фигуры.    |  Каждый элемент массивов figureArray и figureArrayNew - это строки фигуры, в которых биты 4-0 являются флагами наличия кубиков в столбцах стоки (0-нет, 1-есть).
uint8_t  figureArrayNew    [6];                                                // Объявляем  массив для хранения вида будущей фигуры.       |  Последний элемент массивов figureArray и figureArrayNew - это флаг запрещающий поворот фигуры (0-разрешено, 1-запрещено).
int8_t  figurePos         [4];                                                // Объявляем  массив позиции движущейся фигуры на игровом столе (в клетках). [0]: отступ слева, [1]: отступ сверху, [2]: начальный отступ новой фигуры слева, [3]: начальный отступ новой фигуры сверху.
uint8_t  state;                                                                // Объявляем  переменную для хранения текущего состояния игры: GAME_OFF, GAME_ON, GAME_OVER.
uint32_t sumfig;                                                               // Объявляем  счётчик количества созданных фигур:  0-4294967296.
uint8_t  level1;                                                                // Объявляем  счётчик текущего уровня игры:        1-99.
uint32_t points;                                                               // Объявляем  счётчик набранного количества балов: 0-99999.
uint32_t tmrShift;                                                             // Объявляем  переменную для хранения времени следующего сдвига фигуры вниз.
//   bool     valBtnL, valBtnR, valBtnT, valBtnD,valBtnPause;                                   // Объявляем  переменные для хранения состояния кнопок.
/* Объявляем функции: */                                              //
void     getKeys          (void);                                              // Объявляем  функцию получения состояния всех кнопок в переменные valBtnL, valBtnR, valBtnT, valBtnD.
void     showWelcome      (void);                                              // Объявляем  функцию прорисовки анимированного приветствия.
void     showGameScreen   (void);                                              // Объявляем  функцию прорисовки игрового поля.
void     showFigure       (bool, bool, int);                                        // Объявляем  функцию прорисовки или затирания фигуры (аргументы: флаг [1-фигура на игровом столе, 0-будущая фигура], флаг [1-прорисовать фигуру, 0-затереть фигуру]).
void     showTable        (void);                                              // Объявляем  функцию прорисовки всех кубиков в клетках игрового стола.
bool     createNewFigure  (void);                                              // Объявляем  функцию создания будущей фигуры. Функция возвращает false если вставить ранее созданную будущую фигуру на игровой стол не удается (завершение игры).
void     turnFigure       (bool, uint8_t = 1);                                 // Объявляем  функцию поворота фигуры на 90° по часовой стрелке (аргументы: флаг [1-фигура на игровом столе, 0-будущая фигура], количество поворотов будущей фигуры на 90° по часовой стрелке).
bool     shiftFigure      (uint8_t);                                           // Объявляем  функцию сдвига фигуры на одну клетку игрового стола. Если возвращает false если сдвиг невозможен. (аргументы: 1 - влево, 2 - вправо, 3 - вниз, иначе - без сдвига).
bool     checkFigure      (void);                                              // Объявляем  функцию проверки корректности положения фигуры на игровом столе (перед её отрисовкой). Если положение фигуры некорректно, то функция вернёт false.
bool     checkTable       (void);                                              // Объявляем  функцию проверки полностью заполненных строк на игровом столе (функцию требуется вызывать до создания новой фигуры на игровом столе). Если на игровом столе есть полностью заполненные строки, то функция вернёт true.
uint8_t  deletTableRows   (void);                                              // Объявляем  функцию удаления полностью заполненных строк на игровом столе (функцию требуется вызывать до создания новой фигуры на игровом столе). Функция возвращает количество удалённых строк с игрового стола.
//
/******ZMEYKA***********************************************************************/
extern unsigned short apple[0x384];
extern unsigned short zmeygol[0x384];
extern unsigned short zmeygol1[0x384];
extern unsigned short zmeygol2[0x384];
extern unsigned short zmeygol3[0x384];
extern unsigned short zmeytelo[0x384];

/* Объявление переменных  */
int Tail[115];                                                                        // Массив тела змейки.
int Choice;                                                                           // Переменная выбора движения.
int nTail;                                                                            // Переменная количества элементов в змейке.
int CoreX;                                                                            // Переменная X-координаты квадратика.
int CoreY;                                                                            // Переменные Y-координаты квадратика.
int xz;                                                                                // Переменная X-координаты движения.
int yz;                                                                                // Переменная Y-координаты движения.
int EndX;                                                                             // Переменная X-координаты последнего элемента массива.
int EndY;                                                                             // Переменная Y-координаты последнего элемента массива.
int del = 600;                                                                            // Переменная задержки.
int ycor;                                                                             // Дополнительная переменная Y-координаты с которой строится и выводится завершающаяся змейка.
int aTail;                                                                            // Дополнительная переменная количества элементов в змейке.
int Xk = 30;
int Yk = 10;
int grad = 0;
int dispx, dispy, text_y_center;
/* Объявление функций  */
void ShowSnake();                                                                     // Функция вывода всей змейки на экран после выигрыша или проигрыша.
void SplashScreen();                                                                  // Функция вывода заставки игры на экран.
void GameOver();                                                                      // Функция завершения игры.
void SpeedControl();                                                                  // Функция регулировки скорости.
void MoveControl();                                                                   // Функция движения змейки и выбора направления.

//*************************************************************************************
void setup() {
  pinMode(led, OUTPUT);
  Serial.begin(9600);       // скорость обмена по уарт
  Serial1.begin(9600);
  // put your setup code here, to run once:
  //  pinMode(21, OUTPUT);
  //  digitalWrite(21, HIGH);//RD ITDB50
  pinMode(7, OUTPUT);
  // br=constbr+brightness;
  analogWrite(7, 200);//яркость экрана

  pinMode(14, OUTPUT);
  digitalWrite(14, HIGH); //reset esp8266
  pinMode(15, OUTPUT);
  digitalWrite(15, LOW);

  myGLCD.InitLCD();
  myGLCD.setFont(BigFont);
  myTimer.setInterval(1000);   // запуск в режиме интервала 500 мс
  //*************************************************************************************
  uint32_t crt_millis = millis();
  uint32_t prev_millis = crt_millis;
  dispx = myGLCD.getDisplayXSize();
  dispy = myGLCD.getDisplayYSize();
  text_y_center = (dispy / 2) - 6;
  myTouch.InitTouch();
  myTouch.setPrecision(PREC_MEDIUM);

  if (!sd.begin(SD_CHIP_SELECT, SPI_HALF_SPEED)) {
    Serial.println(F("Card failed, or not present"));

  }
  else
  {

    Serial.println(F("Card initialised."));
  }



}

void loop()
{
  myGLCD.clrScr();
  //  char fname440[] = "SO11/SO100100.RAW";
  // myFiles.load(0, 0, 440, 440, fname440, 32, 0);// draw 440x440 raw (32*buffer) (non inverted colour)
  myFiles.load(0, 0, 800, 480, "play/11.raw" , 32, 0);

  myGLCD.setColor(0, 0, 155);
  myGLCD.fillRect(0, 450, 800, 480); //команд строка



  myGLCD.setColor(250, 0, 0);
  myGLCD.fillRect(20, 20, 70, 70);

  myGLCD.setColor(250, 250, 0);
  myGLCD.fillRect(20, 90, 70, 140);

  myGLCD.setColor(250, 0, 250);
  myGLCD.fillRect(20, 160, 70, 210);

  myGLCD.setColor(0, 0, 250);
  myGLCD.fillRect(20, 230, 70, 280);

  myGLCD.setColor(0, 250, 250);
  myGLCD.fillRect(20, 300, 70, 350);

  myGLCD.setColor(0, 250, 0);
  myGLCD.fillRect(20, 370, 70, 420);



  myGLCD.setColor(250, 200, 0);
  myGLCD.fillRect(120, 20, 170, 70);//x,y,xkon ykon
  myGLCD.setColor(200, 200, 0);
  myGLCD.fillRect(120, 90, 170, 140);//x,y,xkon ykon
  myGLCD.setColor(250, 150, 150);
  myGLCD.fillRect(120, 160, 170, 210);//x,y,xkon ykon

  myGLCD.drawBitmap (639, 370, 160, 80,  cl);//часы
  myGLCD.drawRoundRect (639, 370, 799, 450); //Clok
  kalendar();//календарь
  ntp();
  kalendardat();//дата месяц год

  while (1)
  {
    if (myTimer.isReady())
    {
      s1++;
      if (s1 > 59) {
        s1 = 0;
        m1++;
        if (m1 > 59) {
          h1++;
          m1 = 0;
          if (h1 > 23)h1 = 0;
        }
      }
      clc() ;
    }



    if (myTouch.dataAvailable())
    {
      myTouch.read();
      xt = myTouch.getX();
      yt = myTouch.getY();
      if ((xt >= 20) && (xt <= 70)) // Upper row
      {
        if ((yt >= 20) && (yt <= 70)) // Button: 1
        {
          columns();
        }
        if ((yt >= 90) && (yt <= 140)) // Button: 2
        {
          birduino();
        }
        if ((yt >= 160) && (yt <= 210)) // Button: 3
        {
          tetris();
        }
        if ((yt >= 230) && (yt <= 280)) // Button: 4
        {
          paint();
        }
        if ((yt >= 300) && (yt <= 350)) // Button: 5
        {
          foto();
        }
        if ((yt >= 370) && (yt <= 420)) // Button: 5
        {
          zmeyka();
        }
      }
      if ((xt >= 120) && (xt <= 170)) // Upper row
      {
        if ((yt >= 20) && (yt <= 70)) // serial1
        {
          serial();
        }
        if ((yt > 90) && (yt <= 140)) //read serial1
        {
          readserial();
        }
        if ((yt > 160) && (yt <= 210)) //readprognoz
        {
          readprognoz();
        }
      }
      delay(200);
    }
  }
}


bool figmove(int dx, int dy)
{ bool fff = false;

  if (x + dx < 0 || x + dx > MaxX - 1) return (false); // попытка выйти за стенки стакана
    if (dx != 0) if (MasSt[x + dx][y + dy + 2] == 0) return (true); else return (false);
  if (dy > 0) // падение вниз
  { if (y + dy + 2 > MaxY - 1 || MasSt[x + dx][y + dy + 2] > 0) // либо на дне, либо на квадрате
    { if (y < 3) gameover();
      else fff = true;
    } else
    { for (byte i = 0; i < 3; i++) MasSt[x][y + 2 - i + dy] = MasSt[x][y + 2 - i];
      MasSt[x][y] = 0;
      y = y + dy;
    }
    if (fff) {
      MyScore();
      GetNext();
    }
    ViewStacan();
  }
  return (true);
}
//================================================
