package communication;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.EnumMap;
import java.util.Map;

import communication.messages.Message;
import error.UnknownAddressException;

/**
 * Class to handle the sending of messages
 */
public class MessageSender {

	private DatagramSocket socket;
	private static Map<Port, InetAddress> portAddressMap = new EnumMap<>(Port.class);

	/**
	 * Construct a message sender
	 *
	 * @throws SocketException if the socket could not be opened
	 */
	public MessageSender() throws SocketException {
		socket = new DatagramSocket();
	}

	/**
	 * Pair a InetAddress to a Port, for easy usage
	 * @param port
	 * @param address
	 */
	public static void setAddress(Port port, InetAddress address) {
		portAddressMap.put(port, address);
	}

	/**
	 * Send a message to the specified address and port
	 *
	 * @param message
	 * @param port which component to send the message to
	 * @throws IOException
	 * @throws UnknownAddressException
	 */
	public <T extends Message> void sendMessage(T message, Port port) throws IOException, UnknownAddressException {
		byte[] data = messageToByteArray(message);
		if (!portAddressMap.containsKey(port)) {
			throw new UnknownAddressException("Unknown address");
		}
		socket.send(new DatagramPacket(data, data.length, portAddressMap.get(port), port.getPortNumber()));
	}

	/**
	 * Convert a message to byte array
	 *
	 * @param message
	 * @return byte array
	 * @throws IOException
	 */
	private <T extends Message> byte[] messageToByteArray(T message) throws IOException {
		ByteArrayOutputStream b = new ByteArrayOutputStream();
		ObjectOutputStream o = new ObjectOutputStream(b);
		o.writeObject(message);
		return b.toByteArray();
	}
}
