package de.fernunihagen.dna.jkn.scalephant.network.routing;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.fernunihagen.dna.jkn.scalephant.distribution.membership.DistributedInstance;

public class RoutingHeader {
	
	/**
	 * Is this a routed or a direct package?
	 */
	protected boolean routedPackage;
	
	/**
	 * The hop of the package
	 */
	protected short hop;
	
	/**
	 * The hops for this package
	 */
	protected List<DistributedInstance> routingList;

	/**
	 * The flag for direct packages
	 */
	public final static byte DIRECT_PACKAGE = 0x00;
	
	/**
	 * The flag for routed packages
	 */
	public final static byte ROUTED_PACKAGE = 0x01;

	/**
	 * The separator char for the host / hop list
	 */
	public final static String SEPARATOR_CHAR = ",";
	
	/**
	 * The Logger
	 */
	private final static Logger logger = LoggerFactory.getLogger(RoutingHeader.class);

	
	public RoutingHeader() {
	
	}
	
	public RoutingHeader(final boolean routedPackage) {
		this.routedPackage = routedPackage;
	}

	public RoutingHeader(final boolean routedPackage, final short hop, final List<DistributedInstance> routingList) {
		this.routedPackage = routedPackage;
		this.hop = hop;
		this.routingList = routingList;
	}
	
	public RoutingHeader(final boolean routedPackage, final short hop, final String routingList) {
		this.routedPackage = routedPackage;
		this.hop = hop;
		setRoutingList(routingList);
	}

	@Override
	public String toString() {
		return "RoutingHeader [routedPackage=" + routedPackage + ", hop=" + hop + ", routingList=" + routingList + "]";
	}

	/**
	 * Is this a routed or a direct package
	 * @return
	 */
	public boolean isRoutedPackage() {
		return routedPackage;
	}

	/**
	 * Set routed flag
	 * @param routedPackage
	 */
	public void setRoutedPackage(final boolean routedPackage) {
		this.routedPackage = routedPackage;
	}

	/**
	 * Get the current hop
	 * @return
	 */
	public short getHop() {
		return hop;
	}

	/**
	 * Set the current hop
	 * @param hop
	 */
	public void setHop(final short hop) {
		this.hop = hop;
	}

	/**
	 * Get the list with hops
	 * @return
	 */
	public List<DistributedInstance> getRoutingList() {
		return routingList;
	}

	/**
	 * Set the list with hops
	 * @param routingList
	 */
	public void setRoutingList(final List<DistributedInstance> routingList) {
		this.routingList = routingList;
	}
	
	/**
	 * Set the list with hops (as string list)
	 * @param stringRoutingList
	 */
	public void setRoutingList(final String stringRoutingList) {
		
		routingList.clear();
		
		// Routing list is empty
		if(stringRoutingList == null || stringRoutingList.length() == 0) {
			return;
		}
		
		final String[] parts = stringRoutingList.split(SEPARATOR_CHAR);
		
		
		for(final String hop : parts) {
			try {
				final DistributedInstance distributedInstance = new DistributedInstance(hop);
				routingList.add(distributedInstance);
			} catch(IllegalArgumentException e) {
				logger.warn("Unable to parse as distributed instance: " + hop);
			}
		}
	}
	
	/**
	 * Get the hop list as string list
	 * @return
	 */
	public String getRoutingListAsString() {
		final StringBuilder sb = new StringBuilder();
		for(final DistributedInstance distributedInstance : routingList) {
			if(sb.length() != 0) {
				sb.append(SEPARATOR_CHAR);
			}
			sb.append(distributedInstance.getStringValue());
		}
		return sb.toString();
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + hop;
		result = prime * result + (routedPackage ? 1231 : 1237);
		result = prime * result + ((routingList == null) ? 0 : routingList.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		RoutingHeader other = (RoutingHeader) obj;
		if (hop != other.hop)
			return false;
		if (routedPackage != other.routedPackage)
			return false;
		if (routingList == null) {
			if (other.routingList != null)
				return false;
		} else if (!routingList.equals(other.routingList))
			return false;
		return true;
	}
	
}

@@ -54,16 +54,44 @@
 uting;%0A%0A
+import java.util.ArrayList;%0A
 import j
@@ -105,16 +105,16 @@
 l.List;%0A
-
 %0Aimport 
@@ -483,16 +483,22 @@
 otected 
+final 
 List%3CDis
@@ -526,16 +526,55 @@
 tingList
+ = new ArrayList%3CDistributedInstance%3E()
 ;%0A%0A%09/**%0A
@@ -1285,35 +1285,40 @@
 this.routingList
- = 
+.addAll(
 routingList;%0A%09%7D%0A
@@ -1304,32 +1304,33 @@
 dAll(routingList
+)
 ;%0A%09%7D%0A%09%0A%09public R
@@ -2433,22 +2433,56 @@
 List
- = routingList
+.clear();%0A%09%09this.routingList.addAll(routingList)
 ;%0A%09%7D

Make routing list final