#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include "arduino_secrets.h"

#define SENSOR_PIN A0
#define TRIGER_PIN D6
#define LASER_PIN D5
#define LED_PIN D4

#define KEY_LENGTH 8
#define TIME_OF_DEATH 5000
#define SEUIL_OF_DEATH 800

IPAddress broadcast = IPAddress(230, 185, 192, 108);
const int port = 41848;

char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

WiFiUDP udp;

String localId;
String serverId = String("Server");
char separateur[] = ":";
char packetBuffer[256]; //buffer to hold incoming packet

bool isAlive = true;
int tmpOfDeath = 0;



void setup()
{
  pinMode(SENSOR_PIN, INPUT);
  pinMode(TRIGER_PIN, INPUT);
  pinMode(LASER_PIN, OUTPUT);
  pinMode(LED_PIN, OUTPUT);
  
  Serial.begin(115200);
  Serial.println("Startup");

	// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
  WiFi.mode(WIFI_STA);
	WiFi.begin(ssid, pass);
 
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  Serial.print("broadcast address : ");
  Serial.print(broadcast);
  Serial.print(":");
  Serial.println(port);
  udp.beginMulticast(WiFi.localIP(), broadcast, port);

  /* initialize random seed: */
  srand(time(0));
  localId = hexaGenerator(KEY_LENGTH);

  sendMsg("CONNECT");
}

void loop()
{
	if (isAlive)
	{
		shootLaser();
		chestState();
	}
	else
	{
		respawn();
	}

	//Serial.println( analogRead( SENSOR_PIN ) );
	parseData();
}



void setDead(bool state){
	if (state) {
		digitalWrite(LASER_PIN, LOW);
		digitalWrite(LED_PIN, HIGH);
		isAlive = false;
	} else {
		digitalWrite(LED_PIN, LOW);
		tmpOfDeath = 0;
		isAlive = true;
	}
	
}

void respawn()
{
	if (tmpOfDeath < TIME_OF_DEATH)
	{
		tmpOfDeath++;
		delay(1);
	}
	else
	{
		setDead(false);
	}
}

void chestState()
{
	if (analogRead(SENSOR_PIN) > SEUIL_OF_DEATH)
	{
		sendMsg("HIT");
		setDead(true);
	}
}

void shootLaser()
{
	if (digitalRead(TRIGER_PIN) == HIGH)
	{
		digitalWrite(LASER_PIN, HIGH);
	}
	else
	{
		digitalWrite(LASER_PIN, LOW);
	}
}



void parseData()
{
	int packetSize = udp.parsePacket();
	if (packetSize)
	{
		int len = udp.read(packetBuffer, 255);
		if (len > 0)
		{
			packetBuffer[len] = 0;
		}

		printData(packetSize);

		String token = String(strtok(packetBuffer, separateur));
		if (token == localId)
		{
			token = strtok(NULL, separateur);
			if (token == serverId)
			{
				token = strtok(NULL, separateur);
				if (token == "SERVER_TEST")
				{
					sendMsg("TEST_RECEIVED");
				}
				else if (token == "PING")
				{
					sendMsg("PONG");
					setDead(true);
				}
			}
		}
	}
}

void printData(int packetSize)
{
	Serial.print("Received packet of size ");
	Serial.println(packetSize);

	Serial.print("From ");
	IPAddress remoteIp = udp.remoteIP();
	Serial.print(remoteIp);
	Serial.print(", port ");
	Serial.println(udp.remotePort());

	Serial.println("Contents : ");
	Serial.println(packetBuffer);
}

void sendMsg(String msg)
{
	String str = serverId;
	str.concat(separateur);
	str.concat(localId);
	str.concat(separateur);
	str.concat(msg);
	sendUDP(str);
}


void sendUDP(String string) {

  Serial.print("sendUDP : ");
  Serial.println(string);

  // convert string to char array
  char msg[255];
  string.toCharArray(msg,255);

  udp.beginPacketMulticast(broadcast, port, WiFi.localIP());
  udp.write(msg);
  udp.endPacket();
  delay(100);
}

String hexaGenerator(int length)
{
	int val = rand();
	char hex[length];
	itoa(val, hex, 16);
	String result = String(hex);
	Serial.print("\nEquivalent Hex Byte: ");
	Serial.println(result);
	return result;
}

void diagWifiStatus()
{
	/**
	 * Return value available : 
  	 * 0 : WL_IDLE_STATUS when Wi-Fi is in process of changing between statuses
  	 * 1 : WL_NO_SSID_AVAIL in case configured SSID cannot be reached
  	 * 3 : WL_CONNECTED after successful connection is established
  	 * 4 : WL_CONNECT_FAILED if connection failed
  	 * 6 : WL_CONNECT_WRONG_PASSWORD if password is incorrect
  	 * 7 : WL_DISCONNECTED if module is not configured in station mode
  	 */
	Serial.printf("Connection status: %d\n", WiFi.status());
}
