package omq.supervisor;

import java.util.Map;
import java.util.Set;

import omq.common.broker.RemoteBroker;
import omq.exception.RetryException;

import org.apache.log4j.Logger;

import com.rabbitmq.client.AMQP.Queue.DeclareOk;
import com.rabbitmq.client.Channel;

public class SupervisorThread extends Thread {
	private static final Logger logger = Logger.getLogger(SupervisorThread.class.getName());

	private long sleep;
	private SupervisorImpl supervisor;
	private Map<String, OmqSettings> objectSettings;

	public SupervisorThread(SupervisorImpl supervisor, long sleep) {
		this.sleep = sleep;
		this.supervisor = supervisor;
		this.objectSettings = supervisor.getObjectSettings();
	}

	@Override
	public void run() {
		while (true) {
			try {
				Set<String> keys = objectSettings.keySet();
				for (String reference : keys) {
					checkObject(reference);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}

			try {
				Thread.sleep(sleep);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	private void checkObject(String reference) throws Exception {
		OmqSettings settings = objectSettings.get(reference);

		int minObjects = settings.getMinNumberObjects();
		int maxMessages = settings.getMaxNumQueued();
		int minMessages = settings.getMinNumQueued();

		Channel channel = supervisor.getBroker().getChannel();
		DeclareOk dok = channel.queueDeclarePassive(reference);

		int numObjects = getNumObjects(reference);
		int numMessages = dok.getMessageCount();

		System.out.println("Num Consumers: " + numObjects + ", num Messages: " + numMessages);

		if (maxMessages < numMessages || numObjects < minObjects) {
			logger.info("SPAWN TIME!!");
			supervisor.spawnObject(settings, numObjects);
		} else if (numMessages < minMessages && minObjects < numObjects) {
			logger.info("Unbinding object!!!");
			supervisor.unbindObject(settings, numObjects);
		}
	}

	private int getNumObjects(String reference) {
		int num = 0;
		for (RemoteBroker broker : supervisor.getBrokers()) {
			try {
				if (broker.hasObject(reference)) {
					num++;
				}
			} catch (RetryException e) {
				e.printStackTrace();
			}
		}
		return num;
	}
}
