package protocolP2P;
import protocolP2P.Payload;
import tools.HostItem;
import java.util.ArrayList;
import java.util.List;
import localException.InternalError;
import localException.SizeError;
import localException.ProtocolError;
import localException.TransmissionError;
import tools.BytesArrayTools;

/** Representation of payload for discover response.
 * @author	Louis Royer
 * @author	Flavien Haas
 * @author	JS Auge
 * @version	1.0
 */
public class DiscoverResponse extends Payload {

	private List<HostItem> hostList;
	private String filename;
	private static final int FILENAME_SIZE_POSITION = PAYLOAD_START_POSITION;
	private static final int FILENAME_POSITION = FILENAME_SIZE_POSITION + 4;

	/** Constructor with filename (typically used by tracker). If filename is null, it is initialized with "".
	 * @param filename	Name of the file related to the server list.
	 * @param hostList	List of servers
	 * @throws	InternalError
	 */
	public DiscoverResponse(String filename, List<HostItem> hostList) throws InternalError {
		super(RequestResponseCode.DISCOVER_RESPONSE);
		this.filename = filename;
		this.hostList = hostList;
	}

	/** Constructor (typically used by server) with a byte[] parameter containing the Packet received.
	 * @param packet	the full Packet received
	 * @throws	SizeError
	 * @throws	InternalError
	 * @throws	ProtocolError
	 * @throws	TransmissionError
	 */
	protected DiscoverResponse(byte[] packet) throws SizeError, ProtocolError, InternalError, TransmissionError {
		super(packet);
		int size = getPayloadSize(packet);
		/* Read filename size */
		int filenameSize = BytesArrayTools.readInt(packet, FILENAME_SIZE_POSITION);

		/* Read filename */
		filename = BytesArrayTools.readString(packet, FILENAME_POSITION, filenameSize);

		// TODO
		hostList = new ArrayList<>();
		int i = FILENAME_POSITION + filenameSize;
		while(i<size) {
			int port = BytesArrayTools.readInt16Bits(packet, i);
			i += 2;
			String hostname = BytesArrayTools.readString(packet, i, "\n");
			i += hostname.length() + 1; // 1 for the "\n"
			hostList.add(new HostItem(hostname, port));
		}
	}

	/** Returns a byte[] containing Packet with padding.
	 * This Packet is still incomplete and should not be send directly.
	 * ProtocolP2PPacket will use this method to generate the complete Packet.
	 * @return Packet with padding
	 * @throws	InternalError
	 */
	protected byte[] toPacket() throws InternalError {
		int filenameSize = filename.length();
		int hostListSize = 0;
		for (HostItem hostItem: hostList) {
			hostListSize += (2 + hostItem.getHostname().length() + 1);
		} 
		// compute total size
		int size = FILENAME_POSITION + filename.length() + hostListSize;
		byte[] packet = new byte[size]; // java initialize all to zero
		// set request/response code
		packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue;
		// set Payload size
		setPayloadSize(size - PAYLOAD_START_POSITION, packet);
		// write filename size
		BytesArrayTools.write(packet, FILENAME_SIZE_POSITION, filenameSize);
		// write filename
		BytesArrayTools.write(packet, filename, FILENAME_POSITION);

		int i = FILENAME_POSITION + filename.length();
		// write hostList
		for(HostItem hostItem: hostList) {
			try {
				BytesArrayTools.write16Bits(packet, i, hostItem.getPort());
				i+=2;
				String hostname = hostItem.getHostname() + "\n";
				BytesArrayTools.write(packet, hostname, i);
				i+=hostname.length();
			} catch (SizeError e) {
				throw new InternalError();
			}
		}
		return packet;
	}

	/** HostList getter.
	 * @return	hostList
	 */
	public List<HostItem> getHostList() {
		return hostList;
	}

	/** Filename getter.
	 * @return	filename
	 */
	public String getFilename() {
		return filename;
	}
}
