package protocolP2P;
import protocolP2P.Payload;
import protocolP2P.RequestResponseCode;
import localException.TransmissionError;
import localException.ProtocolError;
import localException.InternalError;
import localException.SizeError;
import tools.BytesArrayTools;
import tools.HostItem;

/** Representation of payload for load request.
 * @author	Louis Royer
 * @author	Flavien Haas
 * @author	JS Auge
 * @version	1.0
 */
public class LoadRequest extends Payload {
	private String filename;
	private long maxSizePartialContent;
	private long offset;
	private HostItem hostItem;
	static final private int OFFSET_POSITION = PAYLOAD_START_POSITION;
	static final private int MAX_SIZE_PARTIAL_CONTENT_POSITION = OFFSET_POSITION + 8;
	static final private int FILENAME_SIZE_POSITION = MAX_SIZE_PARTIAL_CONTENT_POSITION + 8;
	static final private int FILENAME_POSITION = FILENAME_SIZE_POSITION + 4;

	/** Constructor (typically used by the client) with a filename parameter.
	 * @param filename	name of the file to download. Must not be empty.
	 * @param offset	offset of the bloc
	 * @param maxSizePartialContent	partial content in response should not excess this size, but this can be less (by example if endoffile is reached or server doesn't have the full block requested)
	 * @param hostItem	hostItem used by the client to register on the tracker
	 * @throws	InternalError
	 */
	public LoadRequest(String filename, long offset, long maxSizePartialContent, HostItem hostItem) throws InternalError {
		super(RequestResponseCode.LOAD_REQUEST);
		/* assert to help debugging */
		assert filename.length() != 0 : "Payload size of LoadRequest must not be empty";
		if (filename.length() == 0) {
			throw new InternalError();
		}
		this.filename = filename;
		this.maxSizePartialContent = maxSizePartialContent;
		this.offset = offset;
		this.hostItem = hostItem;
	}

	/** 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 LoadRequest(byte[] packet) throws TransmissionError, SizeError, ProtocolError, InternalError {
		super(packet);
		/* assert to help debugging */
		assert requestResponseCode == RequestResponseCode.LOAD_REQUEST : "LoadRequest subclass is incompatible with this Packet, request/response code must be checked before using this constructor";
		/* InternalErrorException */
		if (requestResponseCode!= RequestResponseCode.LOAD_REQUEST) {
			throw new InternalError();
		}
		/* Read offset */
		offset = BytesArrayTools.readLong(packet, OFFSET_POSITION);

		/* Read maxSizePartialContent */
		maxSizePartialContent = BytesArrayTools.readLong(packet, MAX_SIZE_PARTIAL_CONTENT_POSITION);

		/* Read filename */
		int size = BytesArrayTools.readInt(packet, FILENAME_SIZE_POSITION);
		filename = BytesArrayTools.readString(packet, FILENAME_POSITION, size);

		/* Read hostItem */
		int portPosition = FILENAME_POSITION + size;
		int hostnameStartPosition = portPosition + 2;
		int hostnameSize = getPayloadSize(packet) - hostnameStartPosition + PAYLOAD_START_POSITION;
		hostItem = new HostItem(BytesArrayTools.readString(packet, hostnameStartPosition, hostnameSize), BytesArrayTools.readInt16Bits(packet, portPosition));
	}

	/** 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 {
		// compute size
		int filenameSize = filename.length();
		String hostname = hostItem.getHostname();
		int size = FILENAME_POSITION + filenameSize + 2 + hostname.length();
		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 - OFFSET_POSITION, packet);
		// Write offset
		BytesArrayTools.write(packet, OFFSET_POSITION, offset);
		// Write maxSizePartialContent
		BytesArrayTools.write(packet, MAX_SIZE_PARTIAL_CONTENT_POSITION, maxSizePartialContent);
		// Write filenameSize
		BytesArrayTools.write(packet, FILENAME_SIZE_POSITION, filenameSize);
		// Write filename
		BytesArrayTools.write(packet, filename, FILENAME_POSITION);
		// Write hostitem
		int portPosition = FILENAME_POSITION + filenameSize;
		try {
			BytesArrayTools.write16Bits(packet, portPosition, hostItem.getPort());
			BytesArrayTools.write(packet, hostname, portPosition + 2);
			return packet;
		} catch (SizeError e) {
			throw new InternalError();
		}
	}

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

	/** offset getter.
	 * @return	offset
	 */
	public long getOffset() {
		return offset;
	}

	/** maxSizePartialContent getter.
	 * @return	maxSizePartialContent
	 */
	public long getMaxSizePartialContent() {
		return maxSizePartialContent;
	}

	/** hostItem getter.
	 * @return	hostItem
	 */
	public HostItem getHostItem() {
		return hostItem;
	}
}
