package org.etsi.its.codec.adapter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;

import org.etsi.its.codec.IEnumConverter;
import org.etsi.its.codec.adapter.IType;
import org.etsi.its.codec.adapter.IValue;

/**
 * This class provides the methods to manage a list of TLV elements
 */
public class TLVs implements IValue {

	/**
	 * The list of the TLV elements
	 */
	private LinkedList<IType> _typeIds;

	/**
	 * The current index in the list parsing operation
	 */
	private int _idx;

	/**
	 * Constructor
	 */
	public TLVs() {
		this(null);
	}

	/**
	 * Constructor
	 * @param typeIds The list of the TLV elements
	 */
	public TLVs(LinkedList<IType> typeIds) {
		_typeIds = typeIds;
		_idx = -1;
	}

	/**
	 * This method provides a reference to the list of the TLV elements
	 * @return A reference to the list of the TLV elements
	 */
	@Override
	public Object getValue() {
		return _typeIds;
	}

	/**
	 * This methods provides the first element from the list <code>_typeIds</code>
	 * @return The first element from the list, null if the list is empty
	 */
	@Override
	public IType getFirstType() {
		if ((_typeIds == null) || (_typeIds.size() == 0)) {
			return null;
		}
		
		_idx = 0;
		return _typeIds.get(_idx);
	}

	/**
	 * This methods provides the next element from the list <code>_typeIds</code> if it is available
	 * @return The next element from the list, null if the end of the list was reached
	 */
	@Override
	public IType getNextType() {
		_idx += 1;
		
		if (_idx >= _typeIds.size()) {
			return null;
		}
		
		return _typeIds.get(_idx);
	}

	/**
	 * This methods provides the previous element from the list <code>_typeIds</code> if it is available
	 * @return The previous element from the list, null if the end of the list was reached
	 */
	@Override
	public IType getPrevType() {
		_idx -= 1;
		
		if ((_idx < 0) || (_idx >= _typeIds.size())) {
			return null;
		}
		
		return _typeIds.get(_idx);
	}

	/**
	 * This method provides the value of the specified type identifier
	 * @param typeId The type identifier to be retrieved
	 * @return The type value
	 */
	@Override
	public IType getType(IEnumConverter typeId) {
		// Sanity check
		if (_typeIds.isEmpty()) {
			return null;
		}
		
		Iterator<IType> iter = _typeIds.iterator();
		do {
			IType item = iter.next();
			if (item.getTypeId() == typeId)
				return item; // Found
		} while (iter.hasNext());

		return null; // Not found
	} // End of method getType

	/**
	 * This method is used to add a new TLV element in the list
	 * @param typeId The type identifier of the TLV element
	 * @param value The type value of the TLV element
	 * @throws IOException Signals that an I/O exception of some sort has occurred
	 */
	public void AddTLV(IEnumConverter typeId, byte [] value) throws IOException {
		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
		if (value.length != 0) { // Value if any, otherwise _typeIds.get(typeId).size() == 0
			buffer.write(value);
		}
		_typeIds.add(new TLV(typeId, buffer));
	} // End of method AddTLV

} // End of class TLVs
