#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mqtt_api.h"



static const char* OPT_SEND = "MQTTAsync_sendMessage";
static const char* OPT_SUB = "MQTTAsync_subscribe";
static const char* OPT_UNSUB = "MQTTAsync_unsubscribe";
static MQTTAsync s_Client;
static int s_mqttStop = 0;
static int s_cloudStatus = 0;

int kk_get_cloud_status(void){
	return s_cloudStatus;
}
/*Connect lost callback*/
static void connlost(void *context, char *cause)
{
	if(context == NULL || cause == NULL)
	{
		ERROR_PRINT("PARAM ERROR\n");
		s_mqttStop = 1;
		return;
	}
	MQTTAsync client = (MQTTAsync)context;
	MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
	int rc;

	INFO_PRINT("\nConnection lost\n");
	INFO_PRINT("cause: %s\n", cause);
	s_cloudStatus = 0;
	KK_Send_CloudState(s_cloudStatus);
	conn_opts.keepAliveInterval = 20;
	conn_opts.cleansession = 1;
	if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
	{
		ERROR_PRINT("Failed to start connect, return code %d\n", rc);
		s_mqttStop = 1;
	}
}

void onDisconnectFailure(void* context, MQTTAsync_failureData* response)
{
	WARNING_PRINT("Disconnect failed\n");
	s_mqttStop = 1;
}

void onDisconnect(void* context, MQTTAsync_successData* response)
{
	WARNING_PRINT("Successful disconnection\n");
	s_mqttStop = 1;
}

void onSendFailure(void* context, MQTTAsync_failureData* response)
{
	if(context == NULL || response == NULL)
	{
		ERROR_PRINT("PARAM ERROR\n");
		return;
	}

	MQTTAsync client = (MQTTAsync)context;
	MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer;
	int rc;

	WARNING_PRINT("Message send failed token %d error code %d\n", response->token, response->code);
	opts.onSuccess = onDisconnect;
	opts.onFailure = onDisconnectFailure;
	opts.context = client;
	if ((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS)
	{
		ERROR_PRINT("Failed to start disconnect, return code %d\n", rc);
	}
}

void onSend(void* context, MQTTAsync_successData* response)
{
	if(response == NULL)
	{
		ERROR_PRINT("PARAM ERROR\n");
		return;
	}
	INFO_PRINT("Message with token value %d delivery confirmed\n", response->token);
}


void onConnectFailure(void* context, MQTTAsync_failureData* response)
{
	s_mqttStop = 1;
	if(response == NULL)
	{
		ERROR_PRINT("PARAM ERROR\n");
		return;
	}

	WARNING_PRINT("Connect failed, rc %d\n", response ? response->code : 0);

}


void onConnect(void* context, MQTTAsync_successData* response)
{
	INFO_PRINT("Successful connection\n");
	s_cloudStatus = 1;
	KK_Send_CloudState(s_cloudStatus);
}


int messageArrived(void* context, char* topicName, int topicLen, MQTTAsync_message* message)
{
	/* not expecting any messages */
	//INFO_PRINT("onMessageArrived topic:%s,message length:%d.\n",topicName,message->payloadlen);
	//INFO_PRINT("payload:%s,\n",message->payload);
	KK_MQTT_RecvMsg(topicName,message->payload);
	MQTTAsync_freeMessage(&message);
	MQTTAsync_free(topicName);
	return 1;
}

static void mqttTraceCallback(enum MQTTASYNC_TRACE_LEVELS level, char *message)
{
	//printf("mqttTraceCallback level:%d,msg:%s.\n",level,message);
}
static void onDeliveryComplete(void* context, MQTTAsync_token token)
{
	//INFO_PRINT("onDeliveryComplete,token:%d \n",token);
}
static void onConnectBuild(void *context, char *cause)
{
	int rc = 0;
	INFO_PRINT("onConnectBuild:%s \n",cause);
	rc = KK_Client_Gateway_Subscribe();
	if(rc != 0)
	{
		ERROR_PRINT("KK_MQTT_SubTopic ERROR rc = %d\n",rc);
	}
}
static void onDisConnected(void *context, MQTTProperties* properties,enum MQTTReasonCodes reasonCode)
{
	INFO_PRINT("onDisConnected,maybe kicked by broker.\n");
}

static void onOptSuccess(void* context, MQTTAsync_successData* response)
{
	if(strcmp((char *)context,OPT_SEND)==0)
	{
		INFO_PRINT("MQTTAsync_sendMessage success,return token:%d,msg length:%d \n",
		           response->token,response->alt.pub.message.payloadlen);

	}
	else if(strcmp((char *)context,OPT_SUB)==0)
	{
		INFO_PRINT("MQTTAsync_subscribe success,return token:%d \n",response->token);
	}
	else if(strcmp((char *)context,OPT_UNSUB)==0)
	{
		INFO_PRINT("MQTTAsync_unsubscribe success,return token:%d \n",response->token);
	}
}
static void onOptFail(void* context,  MQTTAsync_failureData* response)
{
	if(strcmp((char *)context,OPT_SEND)==0)
	{
		WARNING_PRINT("MQTTAsync_sendMessage fail,token:%d,code:%d,msg:%s \n",
		              response->token,response->code,response->message);
	}
	else if(strcmp((char *)context,OPT_SUB)==0)
	{
		WARNING_PRINT("MQTTAsync_subscribe fail,return token:%d \n",response->token);
	}
	else if(strcmp((char *)context,OPT_UNSUB)==0)
	{
		WARNING_PRINT("MQTTAsync_unsubscribe fail,return token:%d \n",response->token);
	}
}
static void mqtt_set_callbacks(void)
{
	MQTTAsync_setConnectionLostCallback(s_Client,NULL,connlost);
	MQTTAsync_setMessageArrivedCallback(s_Client,NULL,messageArrived);
	MQTTAsync_setDeliveryCompleteCallback(s_Client,NULL,onDeliveryComplete);
	MQTTAsync_setConnected(s_Client,NULL,onConnectBuild);
	MQTTAsync_setDisconnected(s_Client,NULL,onDisConnected);

}
void KK_Get_MqttClient(MQTTAsync *pClient)
{
	if(pClient != NULL)
	{
		*pClient = s_Client;
	}
}

MQTTAsync KK_MQTT_Connect(void)
{
	int rc = 0;
	MQTTAsync_createOptions opts  = MQTTAsync_createOptions_initializer;
	MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
	MQTTAsync_setTraceCallback(mqttTraceCallback);
	opts.MQTTVersion = MQTTVERSION_3_1_1;
	char mac[16]={0};
	char clientBuf[20] = {0};
	HAL_Get_mac(mac);
	sprintf(clientBuf, CLIENTID, mac);
	if ((rc = MQTTAsync_createWithOptions(&s_Client, ADDRESS, clientBuf, MQTTCLIENT_PERSISTENCE_NONE, NULL,&opts)) != MQTTASYNC_SUCCESS)
	{
		ERROR_PRINT("Failed to create client object, return code %d\n", rc);
		return NULL;
	}
	/*Set the mqtt callback*/
	mqtt_set_callbacks();

	conn_opts.keepAliveInterval = 60;
	conn_opts.connectTimeout = CONNECT_TIMEOUT;
	conn_opts.automaticReconnect = AUTO_CONN;
	conn_opts.minRetryInterval = 1;
	conn_opts.maxRetryInterval = 32;
	conn_opts.username = USRNAME;
	conn_opts.password = PASSWORD;
	conn_opts.cleansession = 1;
	conn_opts.onSuccess = onConnect;
	conn_opts.onFailure = onConnectFailure;
	conn_opts.context = s_Client;
	if ((rc = MQTTAsync_connect(s_Client, &conn_opts)) != MQTTASYNC_SUCCESS)
	{
		ERROR_PRINT("Failed to start connect, return code %d\n", rc);
		return NULL;
	}
	return s_Client;
}

int KK_MQTT_SubTopic(char *topicName)
{
	INFO_PRINT("to subtopic:%s \n",topicName);

	MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
	int rc;

	opts.onSuccess = onOptSuccess;
	opts.onFailure = onOptFail;
	opts.context = (void*)OPT_SUB;

	if ((rc = MQTTAsync_subscribe(s_Client,topicName, QOS, &opts)) != MQTTASYNC_SUCCESS)
	{
		ERROR_PRINT("Failed to start subscribe, return code:%d.\n", rc);
		return -1;
	}
	return 0;
}

int KK_MQTT_SendMsg(char *topicName,const char *payload)
{
	MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
	MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
	int rc;

	opts.onSuccess = onOptSuccess;
	opts.onFailure = onOptFail;
	opts.context =  (void*)OPT_SEND;

	pubmsg.payload = (void*)payload;
	pubmsg.payloadlen = strlen(payload);
	pubmsg.qos = QOS;
	pubmsg.retained = 0;

	INFO_PRINT("mqtt send payload :%s.\n",payload);

	if ((rc = MQTTAsync_sendMessage(s_Client, topicName, &pubmsg, &opts)) != MQTTASYNC_SUCCESS)
	{
		ERROR_PRINT("Failed to start sendMessage, return code:%d.\n", rc);
		return -1;
	}
	return rc;
}
int KK_MQTT_RecvMsg(const char *topicName,const char *payload)
{
	if(topicName == NULL || payload ==NULL)
	{
		ERROR_PRINT("PARAM ERROR\n");
		return -1;
	}
	KK_Sendto_DevData(topicName,payload);
	return 0;
}

int KK_MQTT_UnsubTopic(const char *topicName)
{
	INFO_PRINT("to unsubtopic:%s \n",topicName);

	MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
	int rc;

	opts.onSuccess = onOptSuccess;
	opts.onFailure = onOptFail;
	opts.context = (void*)OPT_UNSUB;

	if ((rc = MQTTAsync_unsubscribe(s_Client,topicName,&opts)) != MQTTASYNC_SUCCESS)
	{
		ERROR_PRINT("Failed to start unubscribe, return code:%d.\n", rc);
		return -1;
	}
	return rc;
}



