package tools;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.Socket;
import java.net.DatagramSocket;
import java.net.UnknownHostException;
import java.io.IOException;

/** Class to store hostnames + ports
* @author	Louis Royer
* @author	Flavien Haas
* @author	JS Auge
* @version	1.0
*/
public class HostItem {
	private String hostname;
	private int port;
	private Socket tcpSocket;
	private DatagramSocket udpSocket;
	private InetAddress inetAddress;

	/** Constructor with hostname and port
	 * @param hostname	Hostname
	 * @param port	Port
	 */
	public HostItem(String hostname, int port) {
		this.port = port;
		this.hostname = hostname;
	}

	/** Get TCP Socket.
	 * @return	TCP Socket
	 */
	public Socket getTCPSocket() {
		try {
			return tryGetTCPSocket();
		} catch (SocketException e) {
			System.err.println("getTCPSocket error: No TCP socket available.");
			System.exit(-1);
		} catch (UnknownHostException e) {
			System.err.println("getTCPSocket error: Unknown host (" + this + ").");
			System.exit(-1);
		} catch (IOException e) {
			System.err.println("getTCPSocket error: Cannot create TCP socket (" + this + ").");
			System.exit(-1);
		}
		return null; // java compiler is stupid and doesn't know about System.exit
	}

	/** Get TCP Socket.
	 * @return	TCP Socket
	 * @throws	SocketException
	 * @throws	UnknownHostException
	 * @throws	IOException
	 */
	public Socket tryGetTCPSocket() throws SocketException, UnknownHostException, IOException {
		if (tcpSocket == null || tcpSocket.isClosed()) {
			tcpSocket = new Socket(InetAddress.getByName(hostname), port);
		}
		return tcpSocket;
	}

	/** Closes tcp socket
	 */
	public void closeTCPSocket() {
		if (tcpSocket != null) {
			try {
				tcpSocket.close();
			} catch (IOException e2) {
				System.err.println("Error: cannot close socket");
			}
		}
		tcpSocket = null;
	}

	/** Get UDP Socket
	 * return	UDP Socket
	 */
	public DatagramSocket getUDPSocket() {
		try {
			return tryGetUDPSocket();
		} catch (SocketException e) {
			System.err.println("getUDPSocket error: No UDP socket available." );
			System.exit(-1);
		} catch (UnknownHostException e) {
			System.err.println("getUDPSocket error: Unknown host (" + this + ").");
			System.exit(-1);
		}
		return null; // java compiler is stupid and doesn't know about System.exit
	}

	/** Get UDP Socket.
	 * @return	UDP Socket
	 * @throws	SocketException
	 * @throws	UnknownHostException
	 */
	public DatagramSocket tryGetUDPSocket() throws SocketException, UnknownHostException {
		if (udpSocket == null || udpSocket.isClosed()) {
			udpSocket = new DatagramSocket();
			udpSocket.connect(InetAddress.getByName(hostname), port);
		}
		return udpSocket;
	}

	/** Closes udp socket
	 */
	public void closeUDPSocket() {
		if (udpSocket != null) {
			udpSocket.close();
		}
		udpSocket = null;
	}

	/** Getter for hostname */
	public String getHostname() {
		return hostname;
	}

	/** Getter for port */
	public int getPort() {
		return port;
	}

	/** To string
	 * @return	String representation
	 */
	public String toString() {
		return getHostname() + " (port " + getPort() + ")";
	}

	/** Override of equals method
	 * @param other	Object to test equality with
	 * @return	true if equals
	 */
	public boolean equals(Object other) {
		boolean result = false;
		if (other instanceof HostItem) {
			HostItem that = (HostItem) other;
			result = this.getHostname().equals(that.getHostname()) && this.getPort() == that.getPort();
		}
		return result;
	}

	/** Override of hashCode method
	 * @return	a hash code for this object.
	 */
	public int hashCode() {
		return hostname.hashCode() ^ port;
	}

	/** Get InetAddress associated to this HostItem.
	 * @return	InetAddress
	 */
	public InetAddress getInetAddress() {
		if (inetAddress == null) {
			try {
				inetAddress = InetAddress.getByName(getHostname());
			} catch (UnknownHostException e) {
				System.err.println("getInetAddress error: Unknown host (" + this + ").");
				System.exit(-1);
			}
		}
		return inetAddress;
	}

	/** Constructor from Socket.
	 * @param s	socket
	 */
	public HostItem(Socket s) {
		tcpSocket = s;
		inetAddress = s.getInetAddress();
		hostname = inetAddress.getCanonicalHostName();
		port = s.getPort();
	}

	
}
