package model;

import java.awt.Color;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ConnectException;
import java.net.Socket;
import java.net.UnknownHostException;

import model.state.PlayState;

public class NetworkConnection {
	private static final int port = 1234;
	private static final String address = "localhost";
	private DataOutputStream dout;
	private DataInputStream din;
	private Thread receivethread;
	private PlayState play;
	private Socket server;

	// Connection to the server
	public NetworkConnection(PlayState play) {
		this.play = play;
		play.setOverlayText("Waiting for other players..");
	}

	// Try to connect to the server
	public void connect(String name) throws UnknownHostException, IOException {
		if (checkConnection()) {
			throw new IOException("Already connected!");
		}
		try {
			server = new Socket(address, port);
			dout = new DataOutputStream(server.getOutputStream());
			din = new DataInputStream(server.getInputStream());
			dout.writeUTF(name);
		} catch (ConnectException e) {
			play.setOverlayText("Can't connect to the server \n Press ESC to return to the mainmenu");
			System.err.println("Can't connect to the server");
			throw new IOException("Can't connect to the server");
		}
		receivethread = new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					receiveMessage();
				}
			}
		});
		receivethread.start();
	}

	// Check if the connection already exists
	public boolean checkConnection() {
		if (dout == null)
			return false;
		try {
			dout.write(0);
		} catch (IOException e) {
			return false;
		}
		return true;
	}

	// Receive a message from the server and decode it
	private void receiveMessage() {
		try {
			String message = din.readUTF();
			String[] messagesplit = message.split("\\|"); // 2
			switch (messagesplit[0]) {
			case "1": // New Match
				play.newMatch(messagesplit[1], messagesplit[2]);
				break;
			case "2": // Update message
				messagesplit = message.split(",");

				// Update players
				String[] playersplit = messagesplit[0].split("\\|");
				play.updatePlayerInfo(Integer.parseInt(playersplit[1]), Integer.parseInt(playersplit[2]), Integer.parseInt(playersplit[3]), Integer.parseInt(playersplit[4]), play.getPlayer1());
				play.updatePlayerInfo(Integer.parseInt(playersplit[5]), Integer.parseInt(playersplit[6]), Integer.parseInt(playersplit[7]), Integer.parseInt(playersplit[8]), play.getPlayer2());

				// Update Balls
				String[] ballsplit = messagesplit[1].split("\\|");
				if (ballsplit.length / 4 != play.getBalls().size()) {
					play.getBalls().clear();
				}
				for (int i = 0; i < ballsplit.length / 4; i++) {
					play.getBall(i).updateInfo(Integer.parseInt(ballsplit[(i * 4) + 0]), Integer.parseInt(ballsplit[(i * 4) + 1]), Color.decode(ballsplit[(i * 4) + 3]), Integer.parseInt(ballsplit[(i * 4) + 2]));
				}

				// Update lines
				String[] linesplit = messagesplit[2].split("\\|");
				play.updateLines(Integer.parseInt(linesplit[0]), Integer.parseInt(linesplit[1]), Integer.parseInt(linesplit[2]), Integer.parseInt(linesplit[3]), Integer.parseInt(linesplit[4]), Integer.parseInt(linesplit[5]));

				// Update time
				play.setTimeleftpercent(Integer.parseInt(messagesplit[3]));
				break;
			case "3": // Overlay text
				play.setOverlayText(messagesplit[1]);
				break;
			case "4": // Chat Message
				play.addChatMessage(messagesplit[1]);
				break;
			}

		} catch (IOException e) {
			play.setOverlayText("Connection to the server closed \n Press ESC to return to the mainmenu");
			play.stopMatch();
			System.err.println("Connection to the server closed");
			receivethread.stop();
		}

	}

	// Send control request to server
	public void sendInput(int direction, int shoot) {
		sendMessage("1|" + direction + "|" + shoot);
	}

	// Send chat message to server
	public void sendChatMessage(String str) {
		sendMessage("2|" + str);
	}

	// Close connection to server and stop the thread
	public void close() throws IOException {
		receivethread.stop();
		din.close();
		dout.close();
		server.close();
	}

	// Send a message
	private void sendMessage(String m) {
		try {
			dout.writeUTF(m);
		} catch (IOException | NullPointerException e) {
			System.err.println("Connection to server closed");
		}
	}
}
