#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <Wire.h>
#include <Adafruit_FT6206.h>
#include <DallasTemperature.h>
#include <OneWire.h>

#define TFT_DC 9
#define TFT_CS 10
#define Auger_IN1 7
#define Auger_IN2 6
#define Pully_IN1 4
#define Pully_IN2 5
#define Temp1 2
#define Heater 3
#define Fan 8

OneWire oneWire(Temp1);
DallasTemperature sensors(&oneWire);
DeviceAddress temp1;

// The FT6206 uses hardware I2C (SCL/SDA)
Adafruit_FT6206 ctp = Adafruit_FT6206();
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

int PLA[] = {125, 100, 90, 50}; // temp, auger speed, pull speed, Fan speed
int ABS[] = {230, 90, 100, 100};
int other1[] = {0, 0, 0, 0};
int other2[] = {0, 0, 0, 0};
int other3[] = {0, 0, 0, 0};
int other4[] = {0, 0, 0, 0};

const String FILTYPE_PLA = "PLA";
const String FILTYPE_ABS = "ABS";
const String FILTYPE_OTHER1 = "other1";
const String FILTYPE_OTHER2 = "other2";
const String FILTYPE_OTHER3 = "other3";
const String FILTYPE_OTHER4 = "other4";

String StatText;
String LastStatText;
String Filtype = "Blank";
byte Page = 0;
bool Start = false;
bool Startflag = false;
bool Hlight = false;
bool Preheat = false;
bool Preheatflag = false;
bool EmerStop = false;
bool EmerStopflag = false;
bool PageMenuflag = false;
unsigned long Hlighttimeout = 5000;
unsigned long lastTouchTime;
unsigned long TempReadTimer = 10000;
unsigned long TempReadTime = millis();
float temp = 0.0;
float Prevtemp;

void setup() {
  pinMode(Auger_IN1, OUTPUT);
  pinMode(Auger_IN2, OUTPUT);
  pinMode(Pully_IN1, OUTPUT);
  pinMode(Pully_IN2, OUTPUT);
  pinMode(Heater, OUTPUT);
  pinMode(Fan, OUTPUT);

  Serial.begin(115200);
  tft.begin();
  sensors.begin();

  if (!ctp.begin(40)) {  // pass in 'sensitivity' coefficient
    Serial.println("Couldn't Start FT6206 touchscreen controller");
    while (1);
  }

  Page0();
}

void loop() {
  Touch();

  if (EmerStop && !EmerStopflag){
    StatText = "EmerStop";
    tftStatText();
    AllOff();
    EmerStopflag = true;
  }

  if (Preheat && !EmerStop) {
    if (!Preheatflag) {
      analogWrite(Heater, getFiltypeArray(Filtype)[0]);
      StatText = "PreHeating";
      tftStatText();
      Preheatflag = true;
      GetTemp();
    }else if (Preheat && Preheatflag && !PageMenuflag){
      GetTemp();
    }

    if (temp >= getFiltypeArray(Filtype)[0]) {
      Preheat = false;
      Preheatflag = false;
    }
  }

  if (Start && !Preheat && !EmerStop) {
    if (!Startflag){
    StatText = "Extruding";
    tftStatText();
    startExtrusion();
    GetTemp();
    Startflag = true;
    }else if (Start && Startflag){
      GetTemp();
  }else {
    stopExtrusion();
  }
  }

  if (Page == 0 && Hlight && (millis() - lastTouchTime > Hlighttimeout)) {
    clearHlight();
    Filtype = "Blank";
  }
}
//---------------------------------------------------------------------------
void AllOff(){
  digitalWrite(Auger_IN1, LOW);
  analogWrite(Auger_IN2, 0);
  digitalWrite(Pully_IN1, LOW);
  analogWrite(Pully_IN2, 0);
  digitalWrite(Fan, LOW);
  analogWrite(Heater, 0);
  Start = false;
  Startflag = false;
  Preheat = false;
  Preheatflag = false;
}

void startExtrusion() {
  digitalWrite(Auger_IN1, HIGH);
  analogWrite(Auger_IN2, map(getFiltypeArray(Filtype)[1], 0, 255, 0, 100));
  digitalWrite(Pully_IN1, HIGH);
  analogWrite(Pully_IN2, map(getFiltypeArray(Filtype)[2], 0, 255, 0, 100));
  digitalWrite(Fan, HIGH);
  //analogWrite(Fan, map(getFiltypeArray(Filtype)[3], 0, 255, 0, 100));
}

void stopExtrusion() {
  digitalWrite(Auger_IN1, LOW);
  analogWrite(Auger_IN2, 0);
  digitalWrite(Pully_IN1, LOW);
  analogWrite(Pully_IN2, 0);
  analogWrite(Heater, 0);
  // keep fan on to help cool heater??
}

void tftStatText() {
  tft.setTextSize(3);
  tft.setCursor(34, 215);
  tft.setTextColor(0x0);
  tft.print(LastStatText);
  tft.setCursor(34,215);
  tft.setTextColor(0xFFFF);
  tft.print(StatText);
  Serial.print(StatText);
  LastStatText = StatText;
}

void GetTemp() {
   //if (millis() - TempReadTime > TempReadTimer) {
    sensors.requestTemperatures();
    temp = sensors.getTempCByIndex(0);
    tftTemp();
  //}
}

void tftTemp() {
  if (Prevtemp != temp) {
    tft.setTextSize(2);
    tft.setCursor(10, 286);
    tft.setTextColor(0x0);
    tft.print(Prevtemp);
    tft.setCursor(10, 286);
    tft.setTextColor(0xFFFF);
    tft.print(temp);
    Serial.print(temp);
    Prevtemp = temp;
  }
}

void tftEmerStop(){
    tft.fillRect(7, 12, 228, 200, 0xA800);
    tft.setTextSize(4);
    tft.setCursor(17, 27);
    tft.print("EMERGANCY");
    tft.setCursor(52, 73);
    tft.print("STOPED");
    tft.setCursor(24, 113);
    tft.print("CLICK TO");
    tft.setCursor(47, 167);
    tft.print("RETURN");
}

// Function to get the array associated with the current Filtype
int* getFiltypeArray(String type) {
  if (type == FILTYPE_PLA) return PLA;
  if (type == FILTYPE_ABS) return ABS;
  if (type == FILTYPE_OTHER1) return other1;
  if (type == FILTYPE_OTHER2) return other2;
  if (type == FILTYPE_OTHER3) return other3;
  if (type == FILTYPE_OTHER4) return other4;
  return nullptr;
}

void Touch() {
  delay(10);
  if (!ctp.touched()) {
    return;
  }

  TS_Point p = ctp.getPoint();
  lastTouchTime = millis();

  p.x = map(p.x, 0, 240, 240, 0);
  p.y = map(p.y, 0, 320, 320, 0);

  Serial.print("("); Serial.print(p.x);
  Serial.print(", "); Serial.print(p.y);
  Serial.println(")");

  if (Page == 0 && !PageMenuflag) {
    handleTouchOnPage0(p.x, p.y);
  } else if (Page == 1 && !PageMenuflag) {
    handleTouchOnPage1(p.x, p.y);
  }else if (Page == 1 && EmerStop){
    handleTouchEmerStop(p.x, p.y);
  }else if (PageMenuflag)
  handleTouchMenu(p.x, p.y);
}

void handleTouchMenu(int x, int y){
  if (isWithinBox(x,y, 56, 99, 192, 182)){
      PageMenuflag = false;
      if (Page == 0){
        Page0();
      }else if (Page == 1){
        Page1();
      }
}
}

void handleTouchOnPage0(int x, int y) {
  if (isWithinBox(x, y, 12, 105, 105, 144)) {
    Filtype = FILTYPE_PLA;
    highlightBox(12, 105, 93, 39);
  } else if (isWithinBox(x, y, 136, 105, 229, 144)) {
    Filtype = FILTYPE_ABS;
    highlightBox(136, 103, 93, 39);
  } else if (isWithinBox(x, y, 12, 164, 105, 203)) {
    Filtype = FILTYPE_OTHER1;
    highlightBox(12, 164, 93, 39);
  } else if (isWithinBox(x, y, 136, 164, 229, 203)) {
    Filtype = FILTYPE_OTHER2;
    highlightBox(136, 164, 93, 39);
  } else if (isWithinBox(x, y, 12, 228, 105, 266)) {
    Filtype = FILTYPE_OTHER3;
    highlightBox(12, 230, 93, 39);
  } else if (isWithinBox(x, y, 136, 228, 229, 266)) {
    Filtype = FILTYPE_OTHER4;
    highlightBox(136, 231, 93, 39);
  } else if (isWithinBox(x, y, 3, 3, 60, 24)){
    PageMenu();
  }

  if (Filtype != "Blank" && isWithinBox(x, y, 56, 279, 192, 320)) {
    Page = 1;
    Start = true;
    Preheat = true;
    Page1();
  }
}

void handleTouchOnPage1(int x, int y) {
  if (isWithinBox(x, y, 56, 99, 192, 182)) {
    Filtype = "Blank";
    Start = false;
    Startflag = false;
    Preheat = false;
    Preheatflag = false;
    Page = 0;
    Page0();
  }else if(isWithinBox(x, y, 164, 6, 232, 55)){
  AllOff();
  EmerStop = true;
  tftEmerStop();
  }else if (isWithinBox(x, y, 3, 3, 60, 24)){
    PageMenu();
  }
}

void handleTouchEmerStop(int x, int y){
  if (isWithinBox(x, y, 7, 12, 288, 200)){
    EmerStop = false;
    Filtype = "Blank";
    Page = 0;
    Page0(); 
  }
}

bool isWithinBox(int x, int y, int x1, int y1, int x2, int y2) {
  return x >= x1 && x <= x2 && y >= y1 && y <= y2;
}

void highlightBox(int x, int y, int width, int height) {
  if (Hlight) {
    clearHlight();
  }
  tft.drawRect(x, y, width, height, 0x57EA);
  Hlight = true;
}

void clearHlight() {
  tft.drawRect(12, 230, 93, 39, 0xFFFF);
  tft.drawRect(136, 103, 93, 39, 0xFFFF);
  tft.drawRect(12, 164, 93, 39, 0xFFFF);
  tft.drawRect(136, 164, 93, 39, 0xFFFF);
  tft.drawRect(12, 105, 93, 39, 0xFFFF);
  tft.drawRect(136, 231, 93, 39, 0xFFFF);
  Hlight = false;
}

void Page0() {
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(0xFFFF);
  tft.setTextSize(3);
  tft.setCursor(72, 8);
  tft.print("Select");
  tft.setCursor(51, 38);
  tft.print("Filament");
  tft.setCursor(85, 67);
  tft.print("Type");
  tft.drawRect(12, 230, 93, 39, 0xFFFF);
  tft.drawRect(136, 103, 93, 39, 0xFFFF);
  tft.drawRect(12, 164, 93, 39, 0xFFFF);
  tft.drawRect(136, 164, 93, 39, 0xFFFF);
  tft.drawRect(12, 105, 93, 39, 0xFFFF);
  tft.drawRect(136, 231, 93, 39, 0xFFFF);
  tft.drawRect(56, 279, 140, 41, 0xFFFF);
  tft.setCursor(78, 290);
  tft.print("Start");
  tft.setTextSize(2);
  tft.setCursor(170, 117);
  tft.print("ABS");
  tft.setCursor(44, 118);
  tft.print("PLA");
  tft.setCursor(24, 177);
  tft.print("Other1");
  tft.setCursor(148, 177);
  tft.print("Other2");
  tft.setCursor(22, 243);
  tft.print("Other3");
  tft.setCursor(148, 245);
  tft.print("Other4");
  tft.drawRect(3, 3, 57, 21, 0xFFFF);
  tft.setTextSize(2);
  tft.setCursor(8, 7);
  tft.print("MENU");
}

void Page1() {
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(0xFFFF);
  tft.setTextSize(3);
  tft.setCursor(72, 9);
  tft.print("Page");
  tft.setCursor(105, 40);
  tft.print("1");
  tft.drawRect(50, 99, 144, 83, 0xFFFF);
  tft.setCursor(69, 135);
  tft.print("Return");
  tft.setTextSize(2);
  tft.setCursor(105, 285);
  tft.print(getFiltypeArray(Filtype)[0]);
  tft.setCursor(87, 285);
  tft.print("/");
  if (Preheatflag){
  tft.setCursor(10, 286);
  tft.setTextColor(0xFFFF);
  tft.print(Prevtemp);
  }else{
  tft.setCursor(10, 286);
  tft.setTextColor(0xFFFF);
  tft.print("0");
  Prevtemp = 0;
  }
  tft.setTextSize(2);
  tft.setCursor(173, 10);
  tft.print("EMER");
  tft.setCursor(173, 40);
  tft.print("STOP");
  tft.drawRect(164, 6, 69, 55, 0xA800);
  tft.drawRect(3, 3, 57, 21, 0xFFFF);
  tft.setTextSize(2);
  tft.setCursor(8, 7);
  tft.print("MENU");
}

void PageMenu(){
  tft.fillScreen(ILI9341_BLACK);
  tft.drawRect(50, 99, 144, 83, 0xFFFF);
  tft.setCursor(69, 135);
  tft.print("Return");
  PageMenuflag = true;
}
Heater
Fan
Pully
Auger