package bdi4jade.examples.undo;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.PropertyConfigurator;

import bdi4jade.examples.undo.domain.CO;
import bdi4jade.examples.undo.goal.MonitorCOGoal;
import bdi4jade.examples.undo.plan.AnswerRequestPlanBody;
import bdi4jade.examples.undo.plan.NotifyAbnormalCOPlanBody;
import bdi4jade.examples.undo.plan.request.RequestDeviceClosePlanBody;
import bdi4jade.examples.undo.plan.request.RequestDeviceLockPlanBody;
import bdi4jade.examples.undo.plan.request.RequestDeviceOffPlanBody;
import bdi4jade.examples.undo.plan.request.RequestDeviceOnPlanBody;
import bdi4jade.examples.undo.plan.request.RequestDeviceOpenPlanBody;
import bdi4jade.examples.undo.plan.request.RequestDeviceShutdownPlanBody;
import bdi4jade.examples.undo.plan.request.RequestDeviceTakeOffPlanBody;
import bdi4jade.examples.undo.plan.request.RequestDeviceUnlockPlanBody;
import bdi4jade.plan.DefaultPlan;
import jade.BootProfileImpl;
import jade.core.ProfileImpl;
import jade.lang.acl.MessageTemplate;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
import jade.wrapper.PlatformController;

/**
 * @author jgfaccin
 *
 */
public class Runner {

	public static void main(String[] args) {
		PropertyConfigurator.configure(Runner.class.getResource("log4j.properties"));
		Runner runner = new Runner();
		runner.run();
	}

	private final Log log;
	private ProfileImpl bootProfile;
	private jade.core.Runtime runtime;
	private PlatformController controller;

	private SmartHomeAgent alarmAgent;
	private SmartHomeAgent detectorAgent;
	private SmartHomeAgent doorsAgent;
	private SmartHomeAgent fansAgent;
	private SmartHomeAgent lightsAgent;
	private SmartHomeAgent managerAgent;
	private SmartHomeAgent valveAgent;
	private SmartHomeAgent windowsAgent;

	public Runner() {
		this.log = LogFactory.getLog(this.getClass());

		List<String> params = new ArrayList<String>();
		params.add("-gui");
		params.add("-detect-main:false");

		this.bootProfile = new BootProfileImpl(params.toArray(new String[0]));
		this.runtime = jade.core.Runtime.instance();
		this.controller = runtime.createMainContainer(bootProfile);

		setupAgents();

		ArrayList<SmartHomeAgent> agents = new ArrayList<>();
		agents.add(alarmAgent);
		agents.add(detectorAgent);
		agents.add(doorsAgent);
		agents.add(fansAgent);
		agents.add(lightsAgent);
		agents.add(managerAgent);
		agents.add(valveAgent);
		agents.add(windowsAgent);

		initializeAgents(agents);
	}

	private void initializeAgents(ArrayList<SmartHomeAgent> agents) {
		for (SmartHomeAgent agent : agents) {
			try {
				AgentController ac = ((AgentContainer) controller).acceptNewAgent(agent.getCustomName(), agent);
				ac.start();
			} catch (Exception e) {
				System.out.println(e);
			}
		}
	}
	
	public void run() {
		this.detectorAgent.addGoal(new MonitorCOGoal());
		CO co = CO.getInstance();
		Thread gas = new Thread(co);
		gas.start();
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		co.setLeaking(true);

	}

	private void setupAgents() {
		this.detectorAgent = new SmartHomeAgent("DETECTOR");
		this.detectorAgent.getCapability().getPlanLibrary()
				.addPlan(new DefaultPlan(MonitorCOGoal.class, NotifyAbnormalCOPlanBody.class));

		this.alarmAgent = new SmartHomeAgent("ALARM");
		this.alarmAgent.getCapability().getPlanLibrary()
				.addPlan(new DefaultPlan(
						MessageTemplate.or(MessageTemplate.MatchContent(RequestDeviceTakeOffPlanBody.MSG_CONTENT),
								MessageTemplate.MatchContent(RequestDeviceShutdownPlanBody.MSG_CONTENT)),
						AnswerRequestPlanBody.class));

		this.lightsAgent = new SmartHomeAgent("LIGHTS");
		this.lightsAgent.getCapability().getPlanLibrary()
				.addPlan(new DefaultPlan(
						MessageTemplate.or(MessageTemplate.MatchContent(RequestDeviceOnPlanBody.MSG_LIGHTS_CONTENT),
								MessageTemplate.MatchContent(RequestDeviceOffPlanBody.MSG_LIGHTS_CONTENT)),
						AnswerRequestPlanBody.class));

		this.doorsAgent = new SmartHomeAgent("DOORS");
		this.doorsAgent.getCapability().getPlanLibrary()
				.addPlan(new DefaultPlan(
						MessageTemplate.or(MessageTemplate.MatchContent(RequestDeviceUnlockPlanBody.MSG_CONTENT),
								MessageTemplate.MatchContent(RequestDeviceLockPlanBody.MSG_CONTENT)),
						AnswerRequestPlanBody.class));

		this.windowsAgent = new SmartHomeAgent("WINDOWS");
		this.windowsAgent.getCapability().getPlanLibrary()
				.addPlan(new DefaultPlan(
						MessageTemplate.or(MessageTemplate.MatchContent(RequestDeviceOpenPlanBody.MSG_WINDOWS_CONTENT),
								MessageTemplate.MatchContent(RequestDeviceClosePlanBody.MSG_WINDOWS_CONTENT)),
						AnswerRequestPlanBody.class));

		this.fansAgent = new SmartHomeAgent("FANS");
		this.fansAgent.getCapability().getPlanLibrary()
				.addPlan(new DefaultPlan(
						MessageTemplate.or(MessageTemplate.MatchContent(RequestDeviceOnPlanBody.MSG_FANS_CONTENT),
								MessageTemplate.MatchContent(RequestDeviceOffPlanBody.MSG_FANS_CONTENT)),
						AnswerRequestPlanBody.class));

		this.valveAgent = new SmartHomeAgent("VALVE");
		this.valveAgent.getCapability().getPlanLibrary()
				.addPlan(new DefaultPlan(
						MessageTemplate.or(MessageTemplate.MatchContent(RequestDeviceOpenPlanBody.MSG_VALVE_CONTENT),
								MessageTemplate.MatchContent(RequestDeviceClosePlanBody.MSG_VALVE_CONTENT)),
						AnswerRequestPlanBody.class));

		this.managerAgent = new SmartHomeAgent("MANAGER");
		ManagementCapability managementCapability = new ManagementCapability(managerAgent, alarmAgent.getCustomName(), detectorAgent.getCustomName(),
				doorsAgent.getCustomName(), fansAgent.getCustomName(), lightsAgent.getCustomName(),
				valveAgent.getCustomName(), windowsAgent.getCustomName());
		this.managerAgent.setCapability(managementCapability);

	}

}
