/*
 * mqtt.c
 *
 *  Created on: 2018Äê6ÔÂ26ÈÕ
 *      Author: Think
 */
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>

#include "MQTTAsync.h"
#include "CJSON.h"
#include "mqtt.h"
#include "at_command.h"
#include "user_config.h"

// MQTT parameters define
#if 1		///normal url
#define MQTT_SERVER_DEFAULT       "10.8.144.33"		//"192.168.10.91"	//"120.27.235.39:1883"
#define MQTT_CLIENTID_DEFAULT     "ED_BT"
#define MQTT_TOPIC_DEFAULT        "ED/WTG301/18070001/Data"
#define MQTT_TOPIC_PRTF			   "ED/%s/%s/Data"
#else
#define MQTT_SERVER_DEFAULT       "192.168.10.91"		//"192.168.10.91"	//"120.27.235.39:1883"
#define MQTT_CLIENTID_DEFAULT     "ED_BT"
#define MQTT_TOPIC_DEFAULT        "ED/WTG301/18070001/Data"
#define MQTT_TOPIC_PRTF			   "ED/%s/%s/Data"
#endif

#define MQTT_QOS                  1
#define MQTT_TIMEOUT              10000L
#define MQTT_USERNAME             "witcd"				//"chris";		//"witcd"
#define MQTT_PASSWORD             "Witium37774020"		//"jinxin208";			//"Witium37774020"
#define MQTT_SSL_CA               "/home/WT2416/collector/certs/emq-ca.crt"
#define MQTT_SSL_CLIENT_CERT      "/home/WT2416/collector/certs/witium-client.crt"
#define MQTT_SSL_CLIENT_KEY       "/home/WT2416/collector/certs/witium-client.pem"

#define MQTT_THREAD_WAIT_TIMEOUT	500

#define MAX_MQTT_URL_SIZE         64
#define MAX_MQTT_URL_HEAD_SIZE    8
#define MQTT_TCP                  "tcp://"
#define MQTT_SSL                  "ssl://"



/*******************************************************************
 * GLOBAL VARIABLES
 ********************************************************************/

char gateway_CONFIG_MQTT_SERVER[MAX_MQTT_URL_SIZE - MAX_MQTT_URL_HEAD_SIZE] = MQTT_SERVER_DEFAULT;
char Gateway_serialNumber[GATEWAY_MAX_SN_LEN] = "WTG301-18070001";
bool gateway_CONFIG_MQTT_ENABLE = true;
bool gateway_CONFIG_MQTT_SSL_ENABLE = false;
char gateway_CONFIG_MQTT_CACRT[64] = MQTT_SSL_CA;
char gateway_CONFIG_MQTT_CLIENTCRT[64] = MQTT_SSL_CLIENT_CERT;
char gateway_CONFIG_MQTT_CLIENTKEY[64] = MQTT_SSL_CLIENT_KEY;

/*******************************************************************
 * LOCAL VARIABLES
 ********************************************************************/

static MQTTAsync mqttClient = NULL;
static MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
//static MQTTAsync_disconnectOptions disc_opts = MQTTAsync_disconnectOptions_initializer;
//static MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
static MQTTAsync_SSLOptions sslopts = MQTTAsync_SSLOptions_initializer;
volatile MQTTAsync_token deliveredToken = 0;

static char mqttServerUrl[MAX_MQTT_URL_SIZE] = {0};
static char mqttClientID[32] = MQTT_CLIENTID_DEFAULT;
static char mqttDataTopic[32] = MQTT_TOPIC_DEFAULT;

static int finished = 1;


extern POST_DATA_TYPE_ENUM Ciss_get_post_data_type(void);

/*******************************************************************
 * LOCAL FUNCTIONS
 ********************************************************************/

static void updateMqttDataTopic(const char *serialNum)
{
	char model[8] = {0};
	char sn[12] = {0};
	char *buf = NULL;


	if(((strlen(m_cfg_val.gw_module) > 0)
		&&(strlen(m_cfg_val.gw_sn) > 0)))
	{
		printf("gw info = %s, %s !\r\n", m_cfg_val.gw_module, m_cfg_val.gw_sn);
		sprintf(mqttDataTopic, MQTT_TOPIC_PRTF,
				m_cfg_val.gw_module, m_cfg_val.gw_sn);
	}
	else
	{
		strncpy(sn, "18070001", 8);
		strncpy(model, "WTG301", 6);
		sprintf(mqttDataTopic, MQTT_TOPIC_PRTF,
				model, sn);
	}




}

static void connlost(void *context, char *cause)
{
	MQTTAsync client = (MQTTAsync)context;
	int rc;

	printf("\nConnection lost\n");
	printf("     cause: %s\n", cause);

	printf("Reconnecting\n");
	conn_opts.keepAliveInterval = 20;
	conn_opts.cleansession = 1;
	if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
	{
		printf("Failed to start connect, return code %d\n", rc);
	    finished = 1;
	}
}

static int msgarrvd(void *context, char *topicName, int topicLen, MQTTAsync_message *message)
{
    int i;
    char* payloadptr;

    printf("Message arrived\n");
    printf("     topic: %s\n", topicName);
    printf("   message: ");

    payloadptr = message->payload;
    for(i=0; i<message->payloadlen; i++)
    {
        putchar(*payloadptr++);
    }
    putchar('\n');
    MQTTAsync_freeMessage(&message);
    MQTTAsync_free(topicName);
    return 1;
}

//static void onDisconnect(void* context, MQTTAsync_successData* response)
//{
//	printf("Successful disconnection\n");
//	//disc_finished = 1;
//}
//
//static void onSubscribe(void* context, MQTTAsync_successData* response)
//{
//	printf("Subscribe succeeded\n");
//	//subscribed = 1;
//}
//
//static void onSubscribeFailure(void* context, MQTTAsync_failureData* response)
//{
//	printf("Subscribe failed, rc %d\n", response ? response->code : 0);
//	finished = 1;
//}

static void onSendSuccess(void* context, MQTTAsync_successData* response)
{
	//printf("Send sendMessage successfully\n");
}

static void onConnectFailure(void* context, MQTTAsync_failureData* response)
{
	MQTTAsync client = (MQTTAsync)context;
	int rc = -1;

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

	conn_opts.keepAliveInterval = 20;
	conn_opts.cleansession = 1;
	if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
	{
		printf("Failed to start connect, return code %d\n", rc);
	    finished = 1;
	}
}

static void onConnect(void* context, MQTTAsync_successData* response)
{
//	MQTTAsync client = (MQTTAsync)context;
//	MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
//	MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
//	int rc = -1;

	finished = 0;
	printf("Mqtt server connect successfully\n");

//	opts.onSuccess = onSendSuccess;
//	opts.context = client;
//
//	pubmsg.payload = "PAYLOAD";
//	pubmsg.payloadlen = strlen("PAYLOAD");
//	pubmsg.qos = MQTT_QOS;
//	pubmsg.retained = 0;
//	deliveredToken = 0;
//
//	if ((rc = MQTTAsync_sendMessage(client, mqttDataTopic, &pubmsg, &opts)) != MQTTASYNC_SUCCESS)
//	{
//		LOG_printf(LOG_ERROR, "Failed to start sendMessage, return code %d\n", rc);
//	}
}

/*!
 Initialize mqtt service.

 Public function defined in mqtt.h
 */
void Mqtt_init(void)
{
	int rc = -1;

	if (CONFIG_MQTT_ENABLE == false)
		return;

	/* Create mqtt clientID */
	strcat(mqttClientID, Gateway_serialNumber);

	/* Update mqtt data topic by serial number */
	updateMqttDataTopic(Gateway_serialNumber);

	/* Clear and set mqtt server url. */
	memset(mqttServerUrl, 0, MAX_MQTT_URL_SIZE);
	strcpy(mqttServerUrl, CONFIG_MQTT_SSL_ENABLE ? MQTT_SSL : MQTT_TCP);
	strcat(mqttServerUrl, CONFIG_MQTT_SERVER);
	printf("Prepare to connect MQTT server: %s\r\n",
			mqttServerUrl);

	/* Create Mqtt client */
	MQTTAsync_create(&mqttClient, mqttServerUrl, mqttClientID, MQTTCLIENT_PERSISTENCE_NONE,
			NULL);

	MQTTAsync_setCallbacks(mqttClient, mqttClient, connlost, msgarrvd, NULL);

	/* Set connection options */
	conn_opts.keepAliveInterval = 20;
	conn_opts.cleansession = 1;
	conn_opts.onSuccess = onConnect;
	conn_opts.onFailure = onConnectFailure;
	conn_opts.context = mqttClient;
	conn_opts.username = "witcd";					//"witcd";
	conn_opts.password = "Witium37774020";				//"Witium37774020";
	conn_opts.automaticReconnect = 1;

	printf("MQTT client: %s\r\n", mqttClient);

	if (CONFIG_MQTT_SSL_ENABLE == true)
	{
		printf("MQTT SSL enabled\r\n");
		sslopts.trustStore = CONFIG_MQTT_CACRT;
		sslopts.keyStore = CONFIG_MQTT_CLIENTCRT;
		sslopts.privateKey = CONFIG_MQTT_CLIENTKEY;
		sslopts.sslVersion = MQTT_SSL_VERSION_TLS_1_2;
		sslopts.enableServerCertAuth = 0; // Disable server certificate for ssl.
		conn_opts.ssl = &sslopts;
		printf("MQTT SSL cacrt: %s\r\n", sslopts.trustStore);
		printf("MQTT SSL clientcrt: %s\r\n", sslopts.keyStore);
		printf("MQTT SSL clientkey: %s\r\n", sslopts.privateKey);
	}

	if ((rc = MQTTAsync_connect(mqttClient, &conn_opts)) != MQTTASYNC_SUCCESS)
	{
		printf("Failed to connect, return code %d\n", rc);
	  //exit(EXIT_FAILURE);
	}
	else
	{
		printf("MQTT connect!!!\n");
	}
}

extern Ciss_data_struct m_dev;

cJSON* Ciss_mqtt_build_msg(void)
{
	cJSON* root	= NULL;
	//cJSON* dataArry = NULL;
	cJSON* accArry = NULL;
	cJSON* groArry = NULL;
	cJSON* magArry = NULL;
	cJSON* datRoot = NULL;
	cJSON* rDataArry = NULL;


	root = cJSON_CreateObject();
	rDataArry = cJSON_CreateObject();
	datRoot = cJSON_CreateObject();
	//dataArry = cJSON_CreateArray();
	accArry = cJSON_CreateArray();
	groArry = cJSON_CreateArray();
	magArry = cJSON_CreateArray();
	rDataArry = cJSON_CreateArray();


	///acc
	cJSON_AddItemToArray(accArry, cJSON_CreateNumber(m_dev.motion_data.Acc_x));
	cJSON_AddItemToArray(accArry, cJSON_CreateNumber(m_dev.motion_data.Acc_y));
	cJSON_AddItemToArray(accArry, cJSON_CreateNumber(m_dev.motion_data.Acc_z));
	///gro
	cJSON_AddItemToArray(groArry, cJSON_CreateNumber(m_dev.motion_data.Gro_x));
	cJSON_AddItemToArray(groArry, cJSON_CreateNumber(m_dev.motion_data.Gro_y));
	cJSON_AddItemToArray(groArry, cJSON_CreateNumber(m_dev.motion_data.Gro_z));
	///mag
	cJSON_AddItemToArray(magArry, cJSON_CreateNumber(m_dev.motion_data.Mag_x));
	cJSON_AddItemToArray(magArry, cJSON_CreateNumber(m_dev.motion_data.Mag_y));
	cJSON_AddItemToArray(magArry, cJSON_CreateNumber(m_dev.motion_data.Mag_z));

	//data value
	//cJSON_AddNumberToObject(datRoot, "mode", m_dev.dev_mod);
	cJSON_AddNumberToObject(datRoot, "ts", m_dev.send_tim);	///need ms



	if(Ciss_get_post_data_type() == POST_DATA_EVIRMENT)
	{
		/*
		cJSON_AddNullToObject(datRoot, "acc");
		cJSON_AddNullToObject(datRoot, "gyroslist");
		cJSON_AddNullToObject(datRoot, "mag");
		*/
		cJSON_AddNumberToObject(datRoot, "temp", m_dev.evr_data.temp);
		cJSON_AddNumberToObject(datRoot, "humid", m_dev.evr_data.humid);
		cJSON_AddNumberToObject(datRoot, "press", m_dev.evr_data.pressure);
		cJSON_AddNumberToObject(datRoot, "light", m_dev.evr_data.light);
		cJSON_AddNumberToObject(datRoot, "noise", m_dev.evr_data.noise);
	}
	else
	{
		cJSON_AddItemToObjectCS(datRoot, "acc", accArry);
		cJSON_AddItemToObjectCS(datRoot, "gyroslist", groArry);
		cJSON_AddItemToObjectCS(datRoot, "mag", magArry);
		/*
		cJSON_AddNullToObject(datRoot, "temp");
		cJSON_AddNullToObject(datRoot, "humid");
		cJSON_AddNullToObject(datRoot, "press");
		cJSON_AddNullToObject(datRoot, "light");
		cJSON_AddNullToObject(datRoot, "noise");
		*/
	}

	cJSON_AddStringToObject(root, "type", "ciss");
	cJSON_AddStringToObject(root, "sn", m_dev.dev_sn);
	cJSON_AddItemToArray(rDataArry, datRoot);
	cJSON_AddItemToObjectCS(root, "data", rDataArry);


	return root;
}

/*!
 Application task processing.

 Public function defined in mqtt.h
 */


void Mqtt_process(void)
{
	MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
	MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
	int rc = -1;
	//Gateway_devdata_t *pMsg = NULL;

	if (CONFIG_MQTT_ENABLE == false)
	{
		usleep(1000000); // sleep 1s
		return;
	}

	//pMsg = Gateway_MSG_LIST_remove(MQTT_THREAD_WAIT_TIMEOUT);
	//if ((pMsg != NULL) && (MQTTAsync_isConnected(mqttClient) == true)
		//	&& (pMsg->object != NULL))
	if(MQTTAsync_isConnected(mqttClient) == true)
	{
		cJSON* root = Ciss_mqtt_build_msg();
		char *msgData = cJSON_PrintUnformatted(root);

		printf("MQTT send: %s\r\n", msgData);

		if (true)
		{
			pubmsg.payload = msgData;
			pubmsg.payloadlen = strlen(msgData);
			pubmsg.qos = MQTT_QOS;
			pubmsg.retained = 0;

			opts.onSuccess = onSendSuccess;
			opts.context = mqttClient;

			deliveredToken = 0;

			if ((rc = MQTTAsync_sendMessage(mqttClient, mqttDataTopic, &pubmsg, &opts))
					!= MQTTASYNC_SUCCESS)
			{
				printf("Failed to start sendMessage, return code %d\n", rc);
				//exit(EXIT_FAILURE);
			}
			free(msgData);
		}

		cJSON_Delete(root);
		root = NULL;
	}
}
