package com.fca.uconnect.global;

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

import com.amazonaws.services.iot.client.AWSIotException;
import com.amazonaws.services.iot.client.AWSIotMessage;
import com.amazonaws.services.iot.client.AWSIotMqttClient;
import com.amazonaws.services.iot.client.AWSIotQos;
import com.amazonaws.services.iot.client.AWSIotTopic;
import com.fca.uconnect.global.GlobalUconnectControl.UconnectAny;
import com.fca.uconnect.global.GlobalUconnectControl.UconnectMessage;
import com.fca.uconnect.global.GlobalUconnectExtRemoteOp.RemoteDoorRequest;
import com.fca.uconnect.global.GlobalUconnectExtRemoteOp.RemoteDoorRequest.CommandEnum;
import com.fca.uconnect.global.GlobalUconnectExtRemoteOp.RemoteOperationRequest;
import com.fca.uconnect.global.GlobalUconnectExtRemoteOp.RemoteOperationRequest.ActionEnum;
import com.fca.uconnect.global.GlobalUconnectExtRemoteOp.RemoteOperationResponse;
import com.fca.uconnect.global.GlobalUconnectExtRemoteOp.RemoteOperationStatus;
import com.google.protobuf.ByteString;
import com.google.protobuf.ExtensionRegistry;
import com.google.protobuf.InvalidProtocolBufferException;

public class SDPExampleForRemoteOp {
	private String clientId; // The clientId is unique to the device and obtained from the client X.509 certificate CN.
	private ByteString sessionId; // The sessionId is assigned by the SDP to maintain a session independent of connection protocols.
	private AWSIotMqttClient mqttClient; // The mqtt client object from the AWS IoT client library.
	private int messageId; // The messageId is a sequential number incremented and assigned to each message sent from the client.
	private AWSIotTopic iotTopic; // The Topic object to subscribe for inbound messages.
	private ExtensionRegistry extRegistry; // Google protocol buffers extension registry instance.
	private List<UconnectAny> messages;
	private Semaphore semaphore;//The semaphore object is used to wait for a response.
	public SDPExampleForRemoteOp() {
		extRegistry = ExtensionRegistry.newInstance();
		extRegistry.add(GlobalUconnectExtRemoteOp.remoteOperationResponse);
		extRegistry.add(GlobalUconnectExtRemoteOp.remoteOperationStatus);
	}
	public List<UconnectAny> process() {

		mqttClient = new AWSIotMqttClient("endpoint", clientId, "awsAccessKeyId", "awsSecretAccessKey");
 		if (mqttClient == null) {
 			System.out.println("Error init mqtt client.");
 			System.exit(0);
 		}
		try {			
			mqttClient.connect();						
			iotTopic = new AWSIotTopic("/RO/#",AWSIotQos.QOS1){
				public void onMessage(AWSIotMessage msg) {
					UconnectMessage msgIn = null;
					try {
						msgIn = UconnectMessage.parseFrom(msg.getPayload(),extRegistry);
					} catch (InvalidProtocolBufferException e) {					
					}
					//  sync response
				 	//Acknowledging Remote OperationRequest
					if (msgIn.getMessages(0).hasExtension(GlobalUconnectExtRemoteOp.remoteOperationResponse)) {							
						RemoteOperationResponse roAckMsg = msgIn.getMessages(0).getExtension(GlobalUconnectExtRemoteOp.remoteOperationResponse);
						if(messages==null)
							messages = new ArrayList<UconnectAny>();
						messages.add(msgIn.getMessages(0));
						semaphore.unlock();
			
					// async status response after SUBSCRIBE Remote operation request
					if (msgIn.getMessages(0).hasExtension(GlobalUconnectExtRemoteOp.remoteOperationStatus)) {							
						RemoteOperationStatus roStatusmsg = msgIn.getMessages(0).getExtension(GlobalUconnectExtRemoteOp.remoteOperationStatus);
					}	
				}	
			}};
			mqttClient.subscribe(iotTopic);
		} catch (AWSIotException e) {
			System.out.println("Caught Exception "+e);
			e.printStackTrace();
		}
		try {
			sendMessage(getRemoteDoorsMsg(ActionEnum.SUBSCRIBE, CommandEnum.UNLOCK_ALL_DOORS, 0));
			this.semaphore.lock();
		} catch (AWSIotException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return messages;
	}
public UconnectMessage getRemoteDoorsMsg( RemoteOperationRequest.ActionEnum action, RemoteDoorRequest.CommandEnum command, int delay) {
	messageId++;
	RemoteOperationRequest ro = RemoteOperationRequest.newBuilder()
			.setAction(action)
			.setRemoteDoorRequest(
			 RemoteDoorRequest.newBuilder()
			 .setCommand(command))
			.build();
	UconnectMessage msg = UconnectMessage.newBuilder()
			.setTimestamp(System.currentTimeMillis())
			.setMessageId(messageId)
			.addMessages(UconnectAny.newBuilder().setExtension(GlobalUconnectExtRemoteOp.remoteOperationRequest,ro))
			.build();
	return msg;		
}

	private void sendMessage(Object msgIn) throws AWSIotException {
		UconnectMessage msg = (UconnectMessage)msgIn;
		final byte[] msgOut =  msg.toByteArray(); 
			new Thread(new Runnable() {
			    @Override
			public void run() {
			try {						
				AWSIotMessage message = new 
						MessagePublisherListener(clientId+"/RO/",AWSIotQos.QOS1,msgOut);
				mqttClient.publish(message);

			} catch (AWSIotException e) {
				System.out.println("Caught Exception "+e);
							e.printStackTrace();
						}		    	
				    }
				}).start();
			}
	
	public static void main(String[] args) {
		SDPExampleForRemoteOp client = new SDPExampleForRemoteOp();
		client.process();
	}

}

	