package net.onrc.onos.ofcontroller.bgproute;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;

import com.google.common.net.InetAddresses;

public class Prefix {
	private final int MAX_BYTES = 4;
	
	private final int prefixLength;
	private final byte[] address;
	
	//For verifying the arguments and pretty printing
	private final InetAddress inetAddress;
	
	public Prefix(byte[] addr, int prefixLength) {
		if (addr == null || addr.length != MAX_BYTES || 
				prefixLength < 0 || prefixLength > MAX_BYTES * Byte.SIZE) {
			throw new IllegalArgumentException();
		}

		address = canonicalizeAddress(addr, prefixLength);
		this.prefixLength = prefixLength;
		
		try {
			inetAddress = InetAddress.getByAddress(address);
		} catch (UnknownHostException e) {
			throw new IllegalArgumentException();
		}
	}

	public Prefix(String strAddress, int prefixLength) {
		byte[] addr = null;
		addr = InetAddresses.forString(strAddress).getAddress();
				
		if (addr == null || addr.length != MAX_BYTES || 
				prefixLength < 0 || prefixLength > MAX_BYTES * Byte.SIZE) {
			throw new IllegalArgumentException();
		}
		
		address = canonicalizeAddress(addr, prefixLength);
		this.prefixLength = prefixLength;
		
		try {
			inetAddress = InetAddress.getByAddress(address);
		} catch (UnknownHostException e) {
			throw new IllegalArgumentException();
		}
	}
	
	private byte[] canonicalizeAddress(byte[] address, int prefixLength) {
		byte[] result = new byte[address.length];
		
		if (prefixLength == 0) {
			for (int i = 0; i < MAX_BYTES; i++) {
				result[i] = 0;
			}
			
			return result;
		}
		
		result = Arrays.copyOf(address, address.length);
		
		//Set all bytes after the end of the prefix to 0
		int lastByteIndex = (prefixLength - 1) / Byte.SIZE;
		for (int i = lastByteIndex; i < MAX_BYTES; i++) {
			result[i] = 0;
		}
		
		byte lastByte = address[lastByteIndex];
		byte mask = 0;
		byte msb = (byte) 0x80;
		int lastBit = (prefixLength - 1) % Byte.SIZE;
		for (int i = 0; i < Byte.SIZE; i++) {
			if (i <= lastBit) {
				mask |= (msb >> i);
			}
		}

		result[lastByteIndex] = (byte) (lastByte & mask);
		
		return result;
	}

	public int getPrefixLength() {
		return prefixLength;
	}
	
	public byte[] getAddress() {
		return address;
	}
	
	@Override
	public boolean equals(Object other) {
		if (other == null || !(other instanceof Prefix)) {
			return false;
		}
		
		Prefix otherPrefix = (Prefix) other;
		
		return (Arrays.equals(address, otherPrefix.address)) &&
				(prefixLength == otherPrefix.prefixLength);
	}
	
	@Override
	public int hashCode() {
		int hash = 17;
		hash = 31 * hash + prefixLength;
		hash = 31 * hash + Arrays.hashCode(address);
		return hash;
	}
	
	@Override
	public String toString() {
		return inetAddress.getHostAddress() + "/" + prefixLength;
	}
	
	public String printAsBits() {
		String result = "";
		for (int i = 0; i < address.length; i++) {
			byte b = address[i];
			for (int j = 0; j < Byte.SIZE; j++) {
				byte mask = (byte) (0x80 >>> j);
				result += ((b & mask) == 0)? "0" : "1";
				if (i*Byte.SIZE+j == prefixLength-1) {
					return result;
				}
			}
			result += " ";
		}
		return result.substring(0, result.length() - 1);
	}
}
