package cz.vutbr.feec.session.ping;

import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;

import org.apache.log4j.Logger;

import cz.vutbr.feec.session.ping.Ping.Pinger;

/**
 * The Class RttMeasurement. Is able to measure RTT to a single IP address.
 */
public class RttMeasurement implements Runnable {

	private static Logger logger = Logger.getLogger(RttMeasurement.class
			.getName());

	private final InetAddress address;
	private final int id;
	private final int count;

	private double result = Double.POSITIVE_INFINITY;
	private boolean succeed = false;

	public RttMeasurement(InetAddress address, int id, int count) {
		this.address = address;
		this.id = id;
		this.count = count;
	}

	public void run() {
		logger.debug("Rtt measurement started: " + address + " id:" + id
				+ " count:" + count);
		try {
			Pinger ping;
			String hostname = address.getHostName();
			String hostaddr = address.getHostAddress();

			if (address instanceof Inet6Address)
				ping = new Ping.PingerIPv6(id);
			else
				ping = new Ping.Pinger(id);

			IPingEchoReplyListener ltnr = new PingEchoReplyListener(hostname);
			ping.setEchoReplyListener(ltnr);

			logger.debug("PING " + hostname + " (" + hostaddr + ") "
					+ ping.getRequestDataLength() + "("
					+ ping.getRequestPacketLength() + ") bytes of data).");

			ping.sendEchoRequest(address, count);

			for (int j = 0; j < count; ++j) {
				ping.receiveEchoReply();
			}

			ping.close();
			succeed = true;
			logger.debug("Rtt measurement finished (success): " + address
					+ " id:" + id + " count:" + count + ", "
					+ "MINIMAL RTT VALUE:"
					+ ((PingEchoReplyListener) ltnr).getMinRtt());
			result = ((PingEchoReplyListener) ltnr).getMinRtt();
		} catch (IOException e) {
			logger.debug("Rtt measurement failed  " + address + " id:" + id
					+ " count:" + count + ". "+e);
			succeed = false;
		} catch (InterruptedException e) {
			logger.debug("Rtt measurement failed  " + address + " id:" + id
					+ " count:" + count + ". "+e);
		}
	}

	/**
	 * Gets the measured values.
	 * 
	 * @return the result
	 */
	public double getResult() {
		return result;
	}

	/**
	 * Succeeded.
	 * 
	 * @return true, if successful
	 */
	public boolean succeeded() {
		return succeed;
	}
}
