package tracker;
import tools.Logger;
import tools.LogLevel;
import java.net.DatagramSocket;
import protocolP2P.ProtocolP2PPacketUDP;
import protocolP2P.ProtocolP2PPacket;
import protocolP2P.RequestResponseCode;
import protocolP2P.Payload;
import protocolP2P.Register;
import protocolP2P.Unregister;
import tools.HostItem;
import java.util.ArrayList;
import java.util.List;
import java.io.IOException;
import java.net.SocketException;
import exception.LocalException;
import java.util.Map;
import java.util.HashMap;
import protocolP2P.DiscoverRequest;
import protocolP2P.DiscoverResponse;
import protocolP2P.FileList;
import localException.InternalError;
import remoteException.EmptyDirectory;
import java.net.InetAddress;
import java.net.UnknownHostException;
import tracker.TrackerManagement;

/** Tracker management implementation with udp
 * @author	Louis Royer
 * @author	Flavien Haas
 * @author	JS Auge
 * @version	1.0
 */
public class TrackerManagementUDP extends TrackerManagement {
	private DatagramSocket socket;
	/** Constructor with port and logger.
	 * @param tracker	hostitem of the tracker.
	 * @param logger	Logger object
	 */
	public TrackerManagementUDP(HostItem tracker, Logger logger) {
		super(tracker, logger);
		try {
			socket = new DatagramSocket(tracker.getPort(), tracker.getInetAddress());
		} catch (SocketException e) {
			logger.writeUDP("Error: cannot listen on " + tracker, LogLevel.Error);
			System.exit(-1);
		}
	}

	/** Implementation of runnable. This methods allows to run the tracker.
	 */
	public void run() {
		logger.writeUDP("Tracker successfully started", LogLevel.Info);
		while(!stop) {
			try {
				ProtocolP2PPacketUDP<?> pd = new ProtocolP2PPacketUDP<>((Object)socket);
				handleRequest(pd);
			} catch (IOException e) {
				logger.writeUDP(e, LogLevel.Warning);
			} catch (LocalException e) {
				logger.writeUDP(e, LogLevel.Warning);
			}
		}
	}
	
	/** Implementation of writeLog
	 * @param text	Text to log
	 * @param logLevel	level of logging
	 */
	protected void writeLog(String text, LogLevel logLevel) {
		logger.writeUDP(text, logLevel);
	}

	/** Implementation of writeLog
	 * @param e	exception to log
	 * @param logLevel	level of logging
	 */
	protected void writeLog(Exception e, LogLevel logLevel) {
		logger.writeUDP(e, logLevel);
	}

	/** Create packets
	 * @param payload	Payload
	 */
	protected < T extends Payload > ProtocolP2PPacket<T> createProtocolP2PPacket(T payload) {
		return (ProtocolP2PPacket<T>)new ProtocolP2PPacketUDP<T>(payload);
	}

	
	/** Getter for HostItem socket
	 * @param hostItem	HostItem
	 */
	protected Object getHostItemSocket(HostItem hostItem) {
		return (Object)hostItem.getUDPSocket();
	}

	/** Close HostItem socket
	 * @param hostItem	HostItem
	 */
	protected void closeHostItemSocket(HostItem hostItem) {
		hostItem.closeUDPSocket();
	}
}
