package madynes.flowoid.exporter;

import android.annotation.SuppressLint;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.HashMap;

public class TemplateFlowSet implements Exportable {
	
	/** RFC3954 5.2 > FlowSet ID */
	private final short flowSetID = 0;
	
	/** RFC3954 5.2 > format */
    private final short headerSize = 4;
	private HashMap<Integer, TemplateRecord> templateRecords;
	
	public static class TemplateNotFoundException extends Exception {
		private static final long serialVersionUID = 1L;
		private final String message = "Template not found. You MUST register it before!";

		public String getMessage() {
			return message;
		}
	}
	
	/**
	 * Defines a template FlowSet.
	 * See RFC3954 5.2.
	 */
	@SuppressLint("UseSparseArrays")
	public TemplateFlowSet() {
		templateRecords = new HashMap<Integer, TemplateRecord>();
	}
	
	/**
	 * Registers a template record in order to have access to it when the
	 * data records will be created.
	 * 
	 * @param id arbitrary key associated to this template to retrieve it later
	 * (e.g. the Template ID)
	 * @param templateRecord template record to register
	 */
	public void registerTemplateRecord(int id, TemplateRecord templateRecord) {
		templateRecords.put(id, templateRecord);
	}
	
	/**
	 * Returns a template record previously registered.
	 * 
	 * @param id arbitrary key (e.g. Template ID)
	 * @return corresponding template
	 * @throws TemplateNotFoundException launched if this template never was registered
	 */
	public TemplateRecord getRegistredTemplateRecord(int id) throws TemplateNotFoundException {
		if(!templateRecords.containsKey(id))
			throw new TemplateNotFoundException();
			
		return templateRecords.get(id);
	}
	
	/**
	 * Returns this template FlowSet ID, corresponding to the type of record accepted.
	 * 
	 * @return FlowSet ID.
	 */
	public short getFlowSetID() {
		return flowSetID;
	}
	
	/**
	 * Returns the number of template records registered for this FlowSet. 
	 * 
	 * @return number of template records
	 */
	public short getCount() {
		return (short) templateRecords.size();
	}
	
	@Override
	public short getTotalLength() {
		short length = 0;
		
		for(int id : templateRecords.keySet()) {
			length += templateRecords.get(id).getTotalLength();
		}
		
		return (short) (headerSize + length);
	}

	@Override
	public ArrayList<Byte> toBytes() {
		ArrayList<Byte> bytes = new ArrayList<Byte>();
		
    	ByteBuffer headers = ByteBuffer.allocate(headerSize);
    	headers.order(ByteOrder.BIG_ENDIAN);
    	
    	headers.putShort(getFlowSetID());
    	headers.putShort(getTotalLength());
    	
    	for(byte b : headers.array()) {
    		bytes.add((Byte) b);
    	}
		
		for(int id : templateRecords.keySet()) {
			bytes.addAll(templateRecords.get(id).toBytes());
		}
		
		return bytes;
	}
}
