#include <Ethernet.h>
 
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 10, 0, 1, 111 };
 
short l[4] = {2,3,4,5};
int selectButton = 6;
boolean selectPressed = false;
int confirmButton = 7;
//short l[9] = { 8, 9, 10, 5, 6, 7, 2, 3, 4};
boolean p1[9];
boolean p2[9];
boolean field[9];
//boolean checkLed[9];
char box[9];
short turn = 0;
short turns = 0;
int p2select = 0;
boolean p2done = false;
boolean inGame = false;
int val = 0;
int val2 = 0;
char c;
//int p1timer = 0;
//int p2timer = 0;
 
 
int port = 80;
 
Server server(23);
 
void setup() {
  Ethernet.begin(mac, ip);
  server.begin();
  for(int i = 0; i < 4; i++) {
    int led = l[i];
    pinMode(led, OUTPUT);
    digitalWrite(led, LOW);
  }
  pinMode(selectButton, INPUT);
  pinMode(confirmButton, INPUT);
}
 
void loop() {
  val = digitalRead(selectButton);
  val2 = digitalRead(confirmButton);
  Client client = server.available();
  if (client) {
    //printWelcome(client);
    c = client.read();
  }
 
    if(inGame) {
      if(turns < 9) {
        if(turn == 1) {
          if(isNumber()) {
            if(!field[getNumber()]) {
              field[getNumber()] = true;
              p1[getNumber()] = true;
              turn = 2;
              turns++;
            } else client.print("Field is taken!\r\n");
            displayField(client);
          }
        }
 
        if(turn == 2){
          if(!selectPressed){
            if(val == HIGH) {
              delay(50);
              selectPressed = true;
              p2select++;
              if(p2select == 9) p2select = 0;
              showBin(p2select);
              //client.print("button pressed\r\n");
            } 
          }
          if(p2done) {
            p2select = 0;
            p2done = false;
          }
 
          if(selectPressed && (val == LOW)) selectPressed = false;
 
          if(val2 == HIGH) {
            if(!field[p2select]) {
              field[p2select] = true;
              p2[p2select] = true;
              turn = 1;
              turns++;
              blinkLeds(1);
              p2done = true;
            } else {
              blinkLeds(3);
            }
          }
        }
        checkWinner(client);
      } else {
        checkWinner(client);
      }
    } else {
      if(isNumber()) {
        inGame = true;
        turn = 1;
      }
    }
  //ledField(box);
  free(&val);
}
 
// Function to send the menu to the client.
void printWelcome(Client cl){
  cl.print("\r\nWelcome to the tic-tac-toe server.\r\n");
 
}
 
boolean isNumber() {
  boolean retVal = false;
  if(c == '0') retVal = true;
  if(c == '1') retVal = true;
  if(c == '2') retVal = true;
  if(c == '3') retVal = true;
  if(c == '4') retVal = true;
  if(c == '5') retVal = true;
  if(c == '6') retVal = true;
  if(c == '7') retVal = true;
  if(c == '8') retVal = true;
  return retVal;
}
 
short getNumber() {
  short retVal = 0;
  if(c == '0') retVal = 0;
  if(c == '1') retVal = 1;
  if(c == '2') retVal = 2;
  if(c == '3') retVal = 3;
  if(c == '4') retVal = 4;
  if(c == '5') retVal = 5;
  if(c == '6') retVal = 6;
  if(c == '7') retVal = 7;
  if(c == '8') retVal = 8;
  return retVal;
}
 
void displayField(Client cl) {
  for(int i = 0; i < 9; i++) {
    if(field[i]) {
      if(p1[i]) box[i] = 'X';
      else box[i] = 'O';
    } else {
      box[i] = '-';
    }
  }
  short cnt = 0;
  for(int i = 0; i < 3; i++) {
    for(int j = 0; j < 3; j++) {
      cl.print(box[cnt]);
      cnt++;
    }
    cl.print("\r\n");
  }
}
 
/*
void ledField(char box[]) {
  //if((p1timer == 10000) || (p2timer == 100000)) {
    for(int i = 0; i < 9 ; i++) {      
      if(box[i] == 'X') {
        int led = l[i];
        toggleLed(led);
      }
    } 
    //if(p1timer == 10000) p1timer = 0;
    //if(p2timer == 100000) p2timer = 0;
    //p1timer++;
    //p2timer++;
  //}
}
 
void toggleLed(int led) {
  delay(100);
  if(checkLed[led]) {
    digitalWrite(led, LOW);
    checkLed[led] = false;
  } else {
    digitalWrite(led, HIGH);
    checkLed[led] = true;
  }
}
*/
 
void showBin(int num) {
  boolean row[4];
  if(num == 0) {
    row[0] = false;
    row[1] = false;
    row[2] = false;
    row[3] = false;
  }
 if(num == 1) {
    row[0] = true;
    row[1] = false;
    row[2] = false;
    row[3] = false;
  }
 if(num == 2) {
    row[0] = false;
    row[1] = true;
    row[2] = false;
    row[3] = false;
  }
 if(num == 3) {
    row[0] = true;
    row[1] = true;
    row[2] = false;
    row[3] = false;
  }
 if(num == 4) {
    row[0] = false;
    row[1] = false;
    row[2] = true;
    row[3] = false;
  }
 if(num == 5) {
    row[0] = true;
    row[1] = false;
    row[2] = true;
    row[3] = false;
  }
 if(num == 6) {
    row[0] = false;
    row[1] = true;
    row[2] = true;
    row[3] = false;
  }
 if(num == 7) {
    row[0] = true;
    row[1] = true;
    row[2] = true;
    row[3] = false;
  }
 if(num == 8) {
    row[0] = false;
    row[1] = false;
    row[2] = false;
    row[3] = true;
  } 
 
 for(int i = 0; i < 4; i++){
    if (row[i]) digitalWrite(l[i], HIGH);
    else digitalWrite(l[i], LOW);
  }
}
 
void winner(short winner, Client cl) {
  inGame = false;
  turn = 0;
  if (winner == 1) cl.print("You win!\r\n");
  else {
  showBin(1);delay(400);
  showBin(2);delay(400);
  showBin(4);delay(400);
  showBin(8);delay(400);
  showBin(4);delay(400);
  showBin(2);delay(400);
  showBin(1);delay(400);
  blinkLeds(5);}
}
 
void blinkLeds(int times) {
  times *= 2;
  boolean ledsOn = false;
  for(int i = 0; i < times; i++){
    delay(400);
    for(int j = 0; j < 4; j++){
      if(ledsOn) digitalWrite(l[j], LOW);
      else digitalWrite(l[j], HIGH);
    }
    if(ledsOn) ledsOn = false;
    else ledsOn = true;
  }
}
 
void checkWinner(Client cl) {
  if(
  (p1[0] && p1[1] && p1[2]) ||
  (p1[3] && p1[4] && p1[5]) ||
  (p1[6] && p1[7] && p1[8]) ||
  (p1[0] && p1[3] && p1[6]) ||
  (p1[1] && p1[4] && p1[7]) ||
  (p1[2] && p1[5] && p1[8]) ||
  (p1[0] && p1[4] && p1[8]) ||
  (p1[2] && p1[4] && p1[6]) 
  ) winner(1, cl);  
 
  if(
  (p2[0] && p2[1] && p2[2]) ||
  (p2[3] && p2[4] && p2[5]) ||
  (p2[6] && p2[7] && p2[8]) ||
  (p2[0] && p2[3] && p2[6]) ||
  (p2[1] && p2[4] && p2[7]) ||
  (p2[2] && p2[5] && p2[8]) ||
  (p2[0] && p2[4] && p2[8]) ||
  (p2[2] && p2[4] && p2[6]) 
  ) winner(2, cl);
}