// Path: Source/src/de/tum/in/www1/jReto/packet/Packet.java
// public interface Packet {
// 	public ByteBuffer serialize();
// }
// 
// Path: Source/src/de/tum/in/www1/jReto/packet/PacketType.java
// public enum PacketType {		
// 	UNKNOWN(0),
// 	
// 	// Routing Layer
// 	LINK_HANDHAKE(1),
// 	ROUTING_HANDSHAKE(2),
// 	LINK_STATE(3),
// 	FLOODED_PACKET(4),
// 	ROUTED_CONNECTION_ESTABLISHED_CONFIRMATION(5),
// 	
// 	// Connectivity
// 	MANAGED_CONNECTION_HANDSHAKE(10),
// 	CLOSE_REQUEST(11),
// 	CLOSE_ANNOUNCE(12),
// 	CLOSE_ACKNOWLEDGE(13),
// 	
// 	// Data transmission
// 	TRANSFER_STARTED(20),
// 	DATA_PACKET(21),
// 	CANCELLED_TRANSFER(22),
// 	PROGRESS_INFORMATION(23);
// 	
// 	private static final Map<Integer, PacketType> intToTypeMap = new HashMap<Integer, PacketType>();
// 	static {
// 	    for (PacketType type : PacketType.values()) {
// 	        intToTypeMap.put(type.value, type);
// 	    }
// 	}
// 	
// 	private final int value;
// 	
// 	PacketType(int value) {
// 		this.value = value;
// 	}
// 	public static PacketType fromRaw(int value) {
// 		PacketType result = intToTypeMap.get(value);
// 		if (result == null) result = PacketType.UNKNOWN;
// 		return result;
// 	}
// 	public static PacketType fromData(ByteBuffer data) {
// 		if (data.remaining() < 4) {
// 			System.err.println("Insufficient data to get packet type.");
// 			return PacketType.UNKNOWN;
// 		}
// 		
// 		int value = data.getInt();
// 		data.rewind();
// 		PacketType type = PacketType.fromRaw(value);
// 		
// 		if (type == PacketType.UNKNOWN) {
// 			System.err.println("Read unknown type, value was: "+value);
// 		}
// 		
// 		return type;
// 	}
// 	public int toRaw() {
// 		return this.value;
// 	}
// }
// 
// Path: Source/src/de/tum/in/www1/jReto/routing/packets/FloodingPacket.java
// public class FloodingPacket implements Packet {
// 	public final static PacketType TYPE = PacketType.FLOODED_PACKET;
// 	public final static int MINIMUM_LENGTH = Constants.PACKET_TYPE_SIZE + Constants.INT_SIZE + Constants.UUID_SIZE;
// 	
// 	public final UUID originIdentifier;
// 	public final int sequenceNumber;
// 	public final ByteBuffer payload;
// 	
// 	public FloodingPacket(UUID originIdentifier, int sequenceNumber, ByteBuffer payload) {
// 		if (payload.remaining() == 0) {
// 			System.err.println("Warning: Created FloodingPacket with 0 length payload.");
// 		}
// 		
// 		this.originIdentifier = originIdentifier;
// 		this.sequenceNumber = sequenceNumber;
// 		this.payload = payload;
// 	}
// 	
// 	public static FloodingPacket deserialize(ByteBuffer data) {
// 		DataReader reader = new DataReader(data);
// 		if (!DataChecker.check(reader, TYPE, MINIMUM_LENGTH)) return null;
// 		
// 		return new FloodingPacket(reader.getUUID(), reader.getInt(),  reader.getRemainingData());
// 	}
// 	public ByteBuffer serialize() {
// 		this.payload.rewind(); // Maybe someone from outside accessed the buffer and didn't rewind it
// 		DataWriter data = new DataWriter(MINIMUM_LENGTH + this.payload.remaining());
// 		data.add(TYPE);
// 		data.add(this.originIdentifier);
// 		data.add(this.sequenceNumber);
// 		data.add(this.payload);
// 		this.payload.rewind(); // Make sure someone from outside can use the buffer without rewinding first
// 		return data.getData();
// 	}
// }


import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import de.tum.in.www1.jReto.packet.Packet;
import de.tum.in.www1.jReto.packet.PacketType;
import de.tum.in.www1.jReto.routing.packets.FloodingPacket;
package de.tum.in.www1.jReto.routing;



/**
* The FloodingPacketManager implements the Flooding algorithm used to distribute packets through the network.
* When a packet is received, and it or a newer one has been seen before, it is discarded. This is accomplished by storing the last seen sequence number 
* for each sender.
* If the packet is new, it is forwarded to all direct neighbors of the local peer.
*/
public class FloodingPacketManager {
	public static interface PacketHandler {
// Path: Source/src/de/tum/in/www1/jReto/packet/Packet.java
// public interface Packet {
// 	public ByteBuffer serialize();
// }
// 
// Path: Source/src/de/tum/in/www1/jReto/packet/PacketType.java
// public enum PacketType {		
// 	UNKNOWN(0),
// 	
// 	// Routing Layer
// 	LINK_HANDHAKE(1),
// 	ROUTING_HANDSHAKE(2),
// 	LINK_STATE(3),
// 	FLOODED_PACKET(4),
// 	ROUTED_CONNECTION_ESTABLISHED_CONFIRMATION(5),
// 	
// 	// Connectivity
// 	MANAGED_CONNECTION_HANDSHAKE(10),
// 	CLOSE_REQUEST(11),
// 	CLOSE_ANNOUNCE(12),
// 	CLOSE_ACKNOWLEDGE(13),
// 	
// 	// Data transmission
// 	TRANSFER_STARTED(20),
// 	DATA_PACKET(21),
// 	CANCELLED_TRANSFER(22),
// 	PROGRESS_INFORMATION(23);
// 	
// 	private static final Map<Integer, PacketType> intToTypeMap = new HashMap<Integer, PacketType>();
// 	static {
// 	    for (PacketType type : PacketType.values()) {
// 	        intToTypeMap.put(type.value, type);
// 	    }
// 	}
// 	
// 	private final int value;
// 	
// 	PacketType(int value) {
// 		this.value = value;
// 	}
// 	public static PacketType fromRaw(int value) {
// 		PacketType result = intToTypeMap.get(value);
// 		if (result == null) result = PacketType.UNKNOWN;
// 		return result;
// 	}
// 	public static PacketType fromData(ByteBuffer data) {
// 		if (data.remaining() < 4) {
// 			System.err.println("Insufficient data to get packet type.");
// 			return PacketType.UNKNOWN;
// 		}
// 		
// 		int value = data.getInt();
// 		data.rewind();
// 		PacketType type = PacketType.fromRaw(value);
// 		
// 		if (type == PacketType.UNKNOWN) {
// 			System.err.println("Read unknown type, value was: "+value);
// 		}
// 		
// 		return type;
// 	}
// 	public int toRaw() {
// 		return this.value;
// 	}
// }
// 
// Path: Source/src/de/tum/in/www1/jReto/routing/packets/FloodingPacket.java
// public class FloodingPacket implements Packet {
// 	public final static PacketType TYPE = PacketType.FLOODED_PACKET;
// 	public final static int MINIMUM_LENGTH = Constants.PACKET_TYPE_SIZE + Constants.INT_SIZE + Constants.UUID_SIZE;
// 	
// 	public final UUID originIdentifier;
// 	public final int sequenceNumber;
// 	public final ByteBuffer payload;
// 	
// 	public FloodingPacket(UUID originIdentifier, int sequenceNumber, ByteBuffer payload) {
// 		if (payload.remaining() == 0) {
// 			System.err.println("Warning: Created FloodingPacket with 0 length payload.");
// 		}
// 		
// 		this.originIdentifier = originIdentifier;
// 		this.sequenceNumber = sequenceNumber;
// 		this.payload = payload;
// 	}
// 	
// 	public static FloodingPacket deserialize(ByteBuffer data) {
// 		DataReader reader = new DataReader(data);
// 		if (!DataChecker.check(reader, TYPE, MINIMUM_LENGTH)) return null;
// 		
// 		return new FloodingPacket(reader.getUUID(), reader.getInt(),  reader.getRemainingData());
// 	}
// 	public ByteBuffer serialize() {
// 		this.payload.rewind(); // Maybe someone from outside accessed the buffer and didn't rewind it
// 		DataWriter data = new DataWriter(MINIMUM_LENGTH + this.payload.remaining());
// 		data.add(TYPE);
// 		data.add(this.originIdentifier);
// 		data.add(this.sequenceNumber);
// 		data.add(this.payload);
// 		this.payload.rewind(); // Make sure someone from outside can use the buffer without rewinding first
// 		return data.getData();
// 	}
// }


// Path: Source/src/de/tum/in/www1/jReto/routing/FloodingPacketManager.java
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import de.tum.in.www1.jReto.packet.Packet;
import de.tum.in.www1.jReto.packet.PacketType;
import de.tum.in.www1.jReto.routing.packets.FloodingPacket;

package de.tum.in.www1.jReto.routing;



/**
* The FloodingPacketManager implements the Flooding algorithm used to distribute packets through the network.
* When a packet is received, and it or a newer one has been seen before, it is discarded. This is accomplished by storing the last seen sequence number 
* for each sender.
* If the packet is new, it is forwarded to all direct neighbors of the local peer.
*/
public class FloodingPacketManager {
	public static interface PacketHandler {
		Set<PacketType> getHandledPacketTypes();