#include <LiquidCrystal_I2C.h>
#include <SevSeg.h>

// lcd
LiquidCrystal_I2C lcd(0x27, 16, 2);

// sevsegs
SevSeg sevsegPontos1;
SevSeg sevsegPontos2;
SevSeg sevsegSets1;
SevSeg sevsegSets2;

bool troca;  // bool que checa se houve troca de lados

// encoder
byte clk = 2;
byte dt = 3;
byte sw = 4;

byte dtValue;

bool escolhido;
String modalidade = "";

// partida
byte pontos1;
byte pontos2;
byte sets1;
byte sets2;

bool tiebreak;

int ganhador;

byte grau[8]={
  B01110,
  B01010,
  B01010,
  B01110,
  B00000,
  B00000,
  B00000,
  B00000,
};

void setup()
{
  Serial.begin(9600);

  initLcd();
  initEncoder();
  initDisplay();

}

void loop()
{
  display();

  pontuacao();

  if (digitalRead(sw) == LOW) // botão do meio do encoder
  {
    resetarPartida();
  }
}



void initLcd()
{
  lcd.init();
  lcd.backlight();

  lcd.createChar(1,grau);

  lcd.setCursor(4, 0);
  lcd.print("Encoder:");
  lcd.setCursor(0, 1);
  lcd.print("<-Quadra|Areia->");
}


void readEncoder() {
  int dtValue = digitalRead(dt);
  if (dtValue == LOW)
  {
    modalidade = "Quadra"; // Clockwise
  }
  if (dtValue == HIGH)
  {
    modalidade = "Areia"; // Counterclockwise
  }

  escolhido = true;
}

void initEncoder()
{
  pinMode(clk, INPUT);
  pinMode(dt, INPUT);
  pinMode(sw, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(clk), readEncoder, FALLING);

  while (escolhido == false)
  {
    delay(25);
  }

  lcd.clear();
  lcd.setCursor(2, 0);
  lcd.println("Modalidade:");
  lcd.setCursor(8 - sizeof(modalidade) / 2, 1);
  lcd.print(modalidade);
  delay(2000);
  lcd.clear();
  lcd.setCursor(7,0);
  lcd.print(String(sets1 + sets2 + 1)+"\1");
  lcd.setCursor(7,1);
  lcd.print("Set");
  delay(30000);
}

void resetarPartida()
{
  pontos1 = 0;
  pontos2 = 0;
  sets1 = 0;
  sets2 = 0;

  modalidade = "";

  escolhido = false;

  digitalWrite(5, LOW);
  digitalWrite(6, LOW);

  Serial.println("Partida Resetada");

  initLcd();
  initEncoder();
}

void placar() {
  lcd.clear();
  lcd.setCursor(3,0);
  lcd.print("Time 1: " + String(pontos1));
  lcd.setCursor(3,1);
  lcd.print("Time 2: " + String(pontos2));
}

void pontuacao()
{
  if (digitalRead(11) == 1 || digitalRead(10) == 1 || digitalRead(9) == 1 || digitalRead(8) == 1 || digitalRead(7) == 1)
  {
    if (!troca)
    {
      if (digitalRead(11) == 1)
      {
        pontos1--;
        digitalWrite(5, LOW);
        digitalWrite(6, LOW);
        Serial.println("P-1: " + String(pontos1));
        placar();
      }
      else if (digitalRead(10) == 1)
      {
        pontos1++;
        digitalWrite(6, HIGH);
        digitalWrite(5, LOW);
        Serial.println("P-1: " + String(pontos1));
        placar();
      }
      else if (digitalRead(9) == 1)
      {
        pontos2--;
        digitalWrite(5, LOW);
        digitalWrite(6, LOW);
        Serial.println("P-2: " + String(pontos2));
        placar();
      }
      else if (digitalRead(8) == 1)
      {
        pontos2++;
        digitalWrite(5, HIGH);
        digitalWrite(6, LOW);
        Serial.println("P-2: " + String(pontos2));
        placar();
      }
    }
    else if (troca)
    {
      if (digitalRead(11) == 1)
      {
        pontos2--;
        digitalWrite(5, LOW);
        digitalWrite(6, LOW);
        Serial.println("P-2: " + String(pontos2));
        placar();
      }
      else if (digitalRead(10) == 1)
      {
        pontos2++;
        digitalWrite(6, HIGH);
        digitalWrite(5, LOW);
        Serial.println("P-2: " + String(pontos2));
        placar();
      }
      else if (digitalRead(9) == 1)
      {
        pontos1--;
        digitalWrite(5, LOW);
        digitalWrite(6, LOW);
        Serial.println("P-1: " + String(pontos1));
        placar();
      }
      else if (digitalRead(8) == 1)
      {
        pontos1++;
        digitalWrite(5, HIGH);
        digitalWrite(6, LOW);
        Serial.println("P-1: " + String(pontos1));
        placar();
      }
    }

    if (digitalRead(7) == 1)
    {
      pontos1 = 0;
      pontos2 = 0;
      sets1 = 0;
      sets2 = 0;

      digitalWrite(5, LOW);
      digitalWrite(6, LOW);

      Serial.println("Pontos Resetados");
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Pontos Resetados");
    }

    modalidadeDeJogo();

    delay(150);
  }
}

void modalidadeDeJogo()
{
  if (modalidade == "Quadra")
  {
    if (tiebreak == true)
    {
      desempate();

      // troca de quadra
      if ((pontos1 == 8 || pontos2 == 8) && troca == false)
      {
        troca = true;
        lcd.clear();
        lcd.setCursor(1,0);
        lcd.print("Troca de lados");
        delay(30000);
      }
    }
    else if (pontos1 >= 25 || pontos2 >= 25)
    {
      if (pontos1 - pontos2 >= 2)
      {
        pontos1 = 0;
        pontos2 = 0;

        ganhador = 1;

        sets1++;
        digitalWrite(5, LOW);
        digitalWrite(6, LOW);
        Serial.println("S-1: " + String(sets1));
        ganhouSet();
      }
      else if (pontos2 - pontos1 >= 2)
      {
        pontos1 = 0;
        pontos2 = 0;

        ganhador = 2;

        sets2++;
        digitalWrite(5, LOW);
        digitalWrite(6, LOW);
        Serial.println("S-2: " + String(sets2));
        ganhouSet();
      }
    }
  }
  else // areia
  {
    if (tiebreak == true)
    {
      desempate();

      // troca de areia
      if ((pontos1 + pontos2) % 7 == 0)
      {
        troca = !troca;
        lcd.clear();
        lcd.setCursor(1,0);
        lcd.print("Troca de lados");
        delay(30000);
      }
    }
    else if (pontos1 >= 21 || pontos2 >= 21)
    {
      if (pontos1 - pontos2 >= 2)
      {
        pontos1 = 0;
        pontos2 = 0;  

        ganhador = 1;

        sets1++;
        digitalWrite(5, LOW);
        digitalWrite(6, LOW);
        Serial.println("S-1: " + String(sets1));
        ganhouSet();
      }
      else if (pontos2 - pontos1 >= 2)
      {
        pontos1 = 0;
        pontos2 = 0;

        ganhador = 2;

        sets2++;
        digitalWrite(5, LOW);
        digitalWrite(6, LOW);
        Serial.println("S-2: " + String(sets2));
        ganhouSet();
      }
    }
  }

  checarSets();

}

void initDisplay()
{
  pinMode(6, OUTPUT);
  pinMode(5, OUTPUT);
  // informações compartilhadas entre todos os sevsegs
  byte segmentPins[] = {22, 23, 24, 25, 26, 27, 28};
  bool resistorsOnSegments = false;
  byte hardwareConfig = COMMON_ANODE;
  bool updateWithDelays = true; // Default 'false' is Recommended
  bool leadingZeros = true; // Use 'true' if you'd like to keep the leading zeros
  bool disableDecPoint = true; // Use 'true' if your decimal point doesn't exist or isn't connected
  //sevseg.setBrightness(90);

  // informações dos placares de pontos
  byte numDigitsPontos = 2;

  // informações dos placares de set
  byte numDigitsSets = 1;

  // sevseg dos pontos da equipe 1
  byte digitPinsPontos1[] = {18, 19};

  sevsegPontos1.begin(hardwareConfig, numDigitsPontos, digitPinsPontos1, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros, disableDecPoint);

  // sevseg dos pontos da equipe 2
  byte digitPinsPontos2[] = {14, 15};

  sevsegPontos2.begin(hardwareConfig, numDigitsPontos, digitPinsPontos2, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros, disableDecPoint);

  // sevseg dos sets da equipe 2
  byte digitPinsSets1[] = {17};

  sevsegSets1.begin(hardwareConfig, numDigitsSets, digitPinsSets1, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros, disableDecPoint);

  // sevseg dos sets da equipe 1
  byte digitPinsSets2[] = {16};

  sevsegSets2.begin(hardwareConfig, numDigitsSets, digitPinsSets2, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros, disableDecPoint);
}

void display()
{
  if (!troca)
  {
    sevsegPontos1.setNumber(pontos1);
    sevsegPontos2.setNumber(pontos2);

    sevsegSets1.setNumber(sets1);
    sevsegSets2.setNumber(sets2);
  }
  else
  {
    sevsegPontos1.setNumber(pontos2);
    sevsegPontos2.setNumber(pontos1);

    sevsegSets1.setNumber(sets2);
    sevsegSets2.setNumber(sets1);
  }

  sevsegPontos1.refreshDisplay();
  sevsegPontos2.refreshDisplay();
  sevsegSets1.refreshDisplay();
  sevsegSets2.refreshDisplay();
}


void vitoria() {
  lcd.clear();
  lcd.setCursor(2,0);
  lcd.print("Fim de jogo!");
  lcd.setCursor(1,1);
  lcd.print("Time ");
  lcd.setCursor(6,1);
  lcd.print(ganhador);
  lcd.setCursor(8,1);
  lcd.print("Venceu");
  resetarPartida();
}

void checarSets()
{
  if (modalidade == "Quadra")
  {
    if (sets1 == 3)
    {
      Serial.println("A equipe 1 venceu!!!");
      vitoria();
    }
    else if (sets2 == 3)
    {
      Serial.println("A equipe 2 venceu!!!");
      vitoria();
    }
    else if (sets1 == 2 && sets2 == 2)
    {
      tiebreak = true;
      Serial.println("tiebreak");
    }
  }
  else
  {
    if (sets1 == 2)
    {
      Serial.println("A equipe 1 venceu!!!");
      vitoria();
    }
    else if (sets2 == 2)
    {
      Serial.println("A equipe 2 venceu!!!");
      vitoria();
    }
    else if (sets1 == 1 && sets2 == 1)
    {
      tiebreak = true;
      Serial.println("tiebreak");
    }
  }
}

void desempate()
{
  if (pontos1 >= 15 || pontos2 >= 15)
  {
    if (pontos1 - pontos2 >= 2)
    {
      Serial.println("A equipe 1 venceu!!!");
      vitoria();
    }
    else if (pontos2 - pontos1 >= 2)
    {
      Serial.println("A equipe 2 venceu!!!");
      vitoria();
    }
  }
}

void ganhouSet() {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Ganhador do set:");
  lcd.setCursor(5,1);
  lcd.print("Time ");
  lcd.setCursor(10,1);
  lcd.print(ganhador);
  delay(15000);
  contaSets();
}

void contaSets() {
  if (modalidade == "Quadra")
  {
    if (sets1+sets2 < 3) {
      lcd.clear();
      lcd.setCursor(7,0);
      lcd.print(String(sets1 + sets2 + 1)+"\1");
      lcd.setCursor(7,1);
      lcd.print("Set");
      delay(15000);
    } else if(sets1+sets2 == 4) {
      lcd.clear();
      lcd.setCursor(4,0);
      lcd.print("Tiebreak");
      delay(30000);
    }
  }
  else {// areia 
    if (sets1+sets2 < 2){
      lcd.clear();
      lcd.setCursor(7,0);
      lcd.print(String(sets1 + sets2 + 1)+"\1");
      lcd.setCursor(7,1);
      lcd.print("Set");
      delay(15000);
    } else if(sets1+sets2 == 2) {
      lcd.clear();
      lcd.setCursor(4,0);
      lcd.print("Tiebreak");
      delay(30000);
    }
  }
}