import java.io.IOException;
import java.util.Date;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.json.JSONException;
import org.json.JSONObject;

public class SubscribeCallback implements MqttCallback{
	
	private Antifurto client;
	private Publisher publisher;
	private String nomeInterruttore; 
	private String nomeOutputSuono;
	private Esecutore esec;
	private Automa automa;
	
	public SubscribeCallback(Antifurto client, Publisher publisher, String nomeInterruttore, String nomeOutputSuono, Esecutore esec, Automa automa) {
		this.client = client;
		this.publisher = publisher;
		this.nomeInterruttore = nomeInterruttore;
		this.nomeOutputSuono = nomeOutputSuono;
		this.esec = esec;
		this.automa = automa;
	}

	@Override
	public void connectionLost(Throwable arg0) {
		boolean retry = true;
		final Date d = new Date();
		Date d2 = new Date();
		long time = Math.abs(d2.getTime()-d.getTime());
		while(retry & (time<600000)) {
			try {
				client.startClient(esec, publisher);
				retry = false;
			} catch (MqttException e) {
				d2 = new Date();
				time = Math.abs(d2.getTime()-d.getTime());
			}
		}
		if(time>=600000) {
			System.out.println("Tentativo di riconnessione fallito");
			System.exit(1);
		}
	}

	
	@Override
	public void deliveryComplete(IMqttDeliveryToken arg0) {
		// Nessuna operazione
		
	}
	

	@Override
	public void messageArrived(String topic, MqttMessage message) throws Exception {
		System.out.println("nuovo: "+topic+" ; "+message.toString());
		if(topic.equals("to/all")) {
			System.out.println("MESSAGGIO MQTT = "+message.toString());
			if(message.toString().equals("{request:description}"))
				sendDescription("from/"+Antifurto.getMqttTree()+"/antifurto/description");
			if(message.toString().equals("{request:status}"))
				sendMyState("from/"+Antifurto.getMqttTree()+"/antifurto");
		}
		else {
			if(topic.equals("rpc/"+Antifurto.getMqttTree()+"/antifurto")) // DA FARE: capire quale messaggio voglio ricevere per poi pubblicare il mio stato
				// DA FARE: vedi foto foglio Alfredo
				sendMyState("from/"+Antifurto.getMqttTree()+"/antifurto"); // CONTROLLA SE VA BENE PUBBLICARE LO STATO SU QUESTO TOPIC O SE IL TOPIC DEVE ESSERE UN'ALTRO. NOTA: NON POSSO PUBBLICARE SULLO STESSO TOPIC CHE HO SOTTOSCRITTO
			else {
				JSONObject msgJson = new JSONObject(message.toString());
				
				if(topic.equals("from/"+Antifurto.getMqttTree()+"/gpio/"+nomeOutputSuono)) {
					int newStatus = -1;
					if(msgJson.has("status"))
						newStatus = msgJson.getInt("status");
					else {
						if(msgJson.has("event"))
							newStatus = msgJson.getInt("event");
					}
					handleStateMsgFromOutputSuono(newStatus);
				}
				else {
					int event = msgJson.getInt("event");
					if(event==1) {
						// e' stato premuto l'interruttore / il sensore di movimento ha rilevato qualcuno
						if(topic.equals("from/"+Antifurto.getMqttTree()+"/gpio/"+nomeInterruttore))
							handleStateMsgFromInterruttore();
						else {
							// il topic sara' from/gruppo2/luci/gpio/IN0  dove IN0 e' un sensore di movimento
							String[] t = topic.split("/");
							handleMovimento(t[4]);
						}
					}
				}				
			}
		}	
		
	}
	

	
	private synchronized void handleStateMsgFromInterruttore() throws JSONException, IOException {
		automa.changeStatoInterruttore();
		if(automa.getStatoInterruttore().equals("off")) {
			publisher.aggiungiComando("to/"+Antifurto.getMqttTree()+"/gpio/"+nomeOutputSuono, "{cmd:0}"); 
			esec.reset();
		}
		publisher.aggiungiComando("from/"+Antifurto.getMqttTree()+"/antifurto", "{\"event\": {\"antifurto\":\""+automa.getStatoInterruttore()+"\",\"allarme\":\""+automa.getStatoSuono()+"\"}}");
	}
	
	
	private synchronized void handleStateMsgFromOutputSuono(int newStatus) throws JSONException, IOException {
		if(newStatus!=-1) {
			String statusOnOff = automa.converter(newStatus); // lo stato e' della forma "on" oppure "off"
			if(! statusOnOff.equals(automa.getStatoSuono()) ) {
				automa.aggiornaStatoSuono(statusOnOff);
				publisher.aggiungiComando("from/"+Antifurto.getMqttTree()+"/antifurto", "{\"event\": {\"antifurto\":\""+automa.getStatoInterruttore()+"\",\"allarme\":\""+automa.getStatoSuono()+"\"}}");
			}
		}
	}
	

	
	
	private void handleMovimento(String nomeSensore) {
		if(automa.getStatoInterruttore().equals("on"))
			esec.aggiungiVal(automa.getDelta(nomeSensore));
	}
	
	private void sendMyState(String topic) throws MqttException {
		publisher.aggiungiComando(topic, "{\"status\":"+automa.getStatoAutoma()+"}"); 		
	}
	
	private void sendDescription(String topic) {
		// DA FARE: guardare quale descrizione manda netmon, archiver, meter,... e confrontare l'implementazione di questo metodo
		String key = topic.replaceFirst("/description", "");
		String msg = "{\""+key+"\":[\"statoAntifurto\":\"" + automa.getStatoInterruttore()+"]"+"}";
//		
//		//DA FARE quali IN uso, quali Out uso, statoSuono, valore, soglia, statoInterruttore
//		[{"statoAntifurto":"on"},
//		    {"allarme":"on"},
//		    {"valore":5},
//		    {"soglia":1000},
//		    {"interruttore":"IN0"},
//		    {"sensoreDiMovimento":"IN1"},
//		    {"sensoreDiMovimento":"IN2"},
//		    {"sensoreDiMovimento":"IN3"},
//		    {"sensoreSuono":"OUT3"},]
//		publisher.aggiungiComando(topic, msg); 
	}
	

}