package homeNetworkServices.homeControl;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;

import nino.base.NetworkRepository;
import nino.base.NinoConf;
import nino.homeControl.Room;
import nino.homeControl.function.LightControl;
import nino.homeControl.function.TrafficPriorityFunction;
import nino.homeControl.gadget.Light;
import nino.homeControl.gadget.Sensor;
import nino.homeControl.property.LightStatus;
import nino.homeControl.property.Priority;
import nino.homeControl.property.SensorStatus;
import nino.homeControl.property.SensorType;
import nino.homeControl.property.TrafficClass;
import nino.homeControl.property.Vacation;
import nino.network.address.Address;
import nino.network.function.Function;
import nino.network.ressource.NetworkRessource;

/**
 * Class for the HomeControl Web Service with Axis2.
 * 
 * @author Benjamin Ernst <b.ernst@tu-bs.de>
 */
public class HomeControlService {

	private static String ONT = "http://becks.ibr.cs.tu-bs.de:8888/axis/Ontologies/ninoHomeNetwork.owl";

	private URL ontURL;

	/**
	 * Creates a new Instance of HomecontroService.
	 */
	public HomeControlService() {
		try {
			String url = this.getInf();
			if (url != null)
				this.ontURL = new URL(url);
			else
				this.ontURL = new URL(ONT);

		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Gets the first Light found in the desired Room.
	 * 
	 * @return Light located in the Room, if found.
	 */
	public Light getLight(Room room) {
		NetworkRepository ninoRep = new NetworkRepository(this.ontURL);
		ArrayList<Light> lights = ninoRep.getLights();
		for (int i = 0; i < lights.size(); i++) {
			Light l = lights.get(i);
			Room r = l.getIsInRoom();
			if (room.equals(r))
				return l;
		}
		return null;
	}

	/**
	 * Gets the first Sensor found in the desired Room, that is of the right Type.
	 * 
	 * @return Sensor located in the Room, if found.
	 */
	public Sensor getSensor(Room room, SensorType stype) {
		NetworkRepository ninoRep = new NetworkRepository(this.ontURL);
		ArrayList<Sensor> sensors = ninoRep.getSensors();
		for (int i = 0; i < sensors.size(); i++) {
			Sensor s = sensors.get(i);
			SensorType st = s.getHasSensorType();
			Room r = s.getIsInRoom();
			if ((stype.equals(st)) && (room.equals(r)))
				return s;
		}
		return null;
	}

	/**
	 * Gets the NetworkRessources which have the given Function.
	 * 
	 * @param func
	 *            Function that the Ressource must have.
	 * @return List of NetworkRessources.
	 */
	public ArrayList<NetworkRessource> getNRsByFunction(TrafficPriorityFunction func) {
		NetworkRepository ninoRep = new NetworkRepository(this.ontURL);
		ArrayList<NetworkRessource> nrs = ninoRep.getNetworkRessources(func.getRdfType());

		return nrs;
	}

	/**
	 * Generates a Configuration for an given Time-Period.
	 * 
	 * @param vac
	 *            The TimePeriod for the Configuration.
	 * @param conf
	 *            Configuration for the TimePeriod.
	 * @return Configuration with TimePeriod.
	 */
	public String setVacationConf(Vacation vac, NinoConf conf) {
		String begin = this.packConf(vac.getBegin(), "Begin");
		String end = this.packConf(vac.getEnd(), "End");

		String sv = this.packConf((begin + end + conf.getNetConf()), "SetVacation");

		String ninoConf = this.packConf(sv, "NinoConf");
		return ninoConf;
	}

	/**
	 * Generates an Configuration for a TrafficClass-Priorotisation.
	 * 
	 * @param nrs
	 *            NetworkRessources that need to be configured.
	 * @param tc
	 *            The TrafficClass to prioritize.
	 * @param prio
	 *            The Priority of the Traffic-Class
	 * @return Configuration.
	 */
	public String setTrafficClassPriority(ArrayList<NetworkRessource> nrs, TrafficClass tc, Priority prio) {
		String out = "";
		for (int i = 0; i < nrs.size(); i++) {
			NetworkRessource nr = nrs.get(i);

			String ip = "";
			ArrayList<Address> adrs = nr.getHasAddress();
			for (int k = 0; k < adrs.size(); k++) {
				Address adr = adrs.get(k);
				if (adr.isIPv4Address()) {
					ip = adr.asIPv4Address().getAddressValue();
				}
			}
			ip = this.packConf(ip, "IP");
			String name = this.packConf(nr.getName(), "Name");
			String domain = this.packConf(nr.getBelongsToDomain().get(0).getName(), "Domain");
			String netRes = this.packConf((ip + name + domain), "NetworkRessource");

			String trafficClass = this.packConf(tc.getTClass(), "TrafficClass");
			String priority = this.packConf(prio.getPriorityVal(), "Prority");
			String setTraffic = this.packConf(netRes + trafficClass + priority, "SetTrafficClassPriority");

			out = out + setTraffic;
		}

		String ninoConf = this.packConf(out, "NinoConf");
		return ninoConf;

	}

	/**
	 * Gets the NetworkRessource (HomeControlServer) which Controls the Light.
	 * 
	 * @return NetworkRessource.
	 */
	public NetworkRessource getHCS(Light light) {
		// System.out.println("[HCS]: getHCS(): Hier sind wir" + light);
		NetworkRepository ninoRep = new NetworkRepository(this.ontURL);
		ArrayList<NetworkRessource> netRes = ninoRep.getNetworkRessources(LightControl.URI);
		// for all NetworkRessources
		for (int i = 0; i < netRes.size(); i++) {
			NetworkRessource nr = netRes.get(i);
			ArrayList<Function> functions = nr.getHasFunction();
			// for all Functions of a NetworkRessource
			for (int k = 0; k < functions.size(); k++) {
				Function f = functions.get(k);
				if (f.isLightControl()) {
					LightControl lc = f.asLightControl();
					ArrayList<Light> lights = lc.getcontrols();
					// for all Lights with the Function (LightControl) of a NetworkRessource
					for (int g = 0; g < lights.size(); g++) {
						Light l = lights.get(g);
						if (light.equals(l))
							return nr;
					}
				}
			}
		}
		return null;
	}

	/**
	 * Gets the URL of the Repository.
	 * 
	 * @return the ontURL
	 */
	public URL getOntURL() {
		return ontURL;
	}

	/**
	 * Sets the URL of the Repository.
	 * 
	 * @param ontURL
	 *            the ontURL to set
	 */
	public void setOntURL(URL ontURL) {
		this.ontURL = ontURL;
	}

	/**
	 * Generates a Configuration for Light that is triggered by a Sensor.
	 * 
	 * @param light
	 *            Light to switch.
	 * @param lstat
	 *            Status the Light should be switched in.
	 * @param sensor
	 *            Sensor to trigger.
	 * @param sstat
	 *            SensorStatus that should be triggerd.
	 * @param hcs
	 *            The NetworkRessource which control the Light.
	 * @return Configuration.
	 */
	public String switchLightbySensor(Light light, LightStatus lstat, Sensor sensor, SensorStatus sstat, NetworkRessource hcs) {
		// create Configuration
		String ip = "";
		ArrayList<Address> adrs = hcs.getHasAddress();
		for (int i = 0; i < adrs.size(); i++) {
			Address adr = adrs.get(i);
			if (adr.isIPv4Address()) {
				ip = adr.asIPv4Address().getAddressValue();
			}
		}
		ip = this.packConf(ip, "IP");
		String name = this.packConf(hcs.getName(), "Name");
		String domain = this.packConf(hcs.getBelongsToDomain().get(0).getName(), "Domain");
		String nr = this.packConf((ip + name + domain), "NetworkRessource");

		String li = this.packConf(light.getName(), "Light");
		String ls = "off";
		if (lstat.getisOn())
			ls = "on";
		ls = this.packConf(ls, "LStat");
		String switchL = this.packConf(li + ls, "SwitchLight");

		String se = this.packConf(sensor.getName(), "Sensor");
		String ss = "off";
		if (sstat.getisOn())
			ss = "on";
		ls = this.packConf(ls, "SStat");
		String triggS = this.packConf(se + ss, "TriggerSensor");

		String lc = this.packConf(nr + switchL + triggS, "LightControl");

		String ninoConf = this.packConf(lc, "NinoConf");
		return ninoConf;
	}

	/**
	 * Method to pack a Value in Tags
	 * 
	 * @param s
	 *            Value
	 * @param pack
	 *            Tag
	 * @return Taged Value
	 */
	private String packConf(String s, String pack) {
		s = "<" + pack + ">" + s + "</" + pack + ">";
		return s;
	}

	/**
	 * Reads the config-file located in the same folder as the "HomeControlService.aar". It reads the URL of the NetworkRepository
	 * 
	 * @return URL of the NetworkRepository as String
	 */
	private String getInf() {

		String conf = null;
		try {
			int len;
			byte[] b = new byte[10000];
			InputStream is = this.getClass().getClassLoader().getResourceAsStream("HomeControlService.conf");
			len = is.read(b);
			conf = new String(b, 0, len);
			conf.trim();
			int i = conf.indexOf("<HomeControlServiceConf>");
			if (i < 0)
				throw new IOException();
			int k = conf.indexOf("</HomeControlServiceConf>");
			conf = conf.substring(i + 24, k);
			i = conf.indexOf("<NetworkRepositoryURL>");
			if (i < 0)
				throw new IOException();
			k = conf.indexOf("</NetworkRepositoryURL>");
			conf = conf.substring(i + 22, k);
			i = conf.indexOf("http");
			if (i < 0)
				throw new IOException();
			k = conf.indexOf(".owl");
			conf = conf.substring(i, k + 4);

		} catch (IOException e) {
			System.out.println("Error Reading ");
		}

		return conf;

	}

}
