/*
 * curlApi.c
 *
 *  Created on: 2021/6/1
 *      Author: foluswen
 */
#include 	<sys/time.h>
#include 	<sys/timeb.h>
#include    <sys/types.h>
#include    <sys/stat.h>
#include 	<sys/types.h>
#include 	<sys/ioctl.h>
#include 	<sys/socket.h>
#include 	<sys/ipc.h>
#include 	<sys/shm.h>
#include 	<sys/shm.h>
#include 	<sys/mman.h>
#include 	<linux/wireless.h>
#include 	<arpa/inet.h>
#include 	<netinet/in.h>

#include 	<unistd.h>
#include 	<stdarg.h>
#include    <stdio.h>
#include    <stdlib.h>
#include    <unistd.h>
#include    <fcntl.h>
#include    <termios.h>
#include    <errno.h>
#include 	<errno.h>
#include 	<string.h>
#include	<time.h>
#include	<ctype.h>
#include 	<ifaddrs.h>
#include    <signal.h>
#include 	<curl/curl.h>
#include 	<curl/easy.h>
#include	"SystemLogMessage.h"
#include	"curlApi.h"

struct MemoryStruct
{
  uint8_t memory[4096];
  size_t size;
};

struct MemoryStruct chunk;

/**
 * HTTP get/post data response callback
 * @param contents
 * @param size
 * @param nmemb
 * @param userp
 */
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
	size_t realsize = size*nmemb;
	struct MemoryStruct *mem = (struct MemoryStruct *)userp;

	mem->size = realsize;;

	memset(mem->memory, 0x00, ARRAY_SIZE(mem->memory));
	chunk.size = realsize;
	memcpy(mem->memory, contents, realsize);

	return realsize;
}

/**
 * HTTP get request/response
 * @param url
 * @param responseData
 * @return
 */
int httpGet(uint8_t *url, uint8_t *responseData)
{
	int result = FAIL;
	CURL *curl;
	CURLcode res;

	curl_global_init(CURL_GLOBAL_ALL);
	curl = curl_easy_init();

	if(curl)
	{
		 curl_easy_setopt(curl, CURLOPT_URL, (char*)url);
		 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
		 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
		 //curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
		 //curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen((char*)postData));
		 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
		 //curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY);
		 //curl_easy_setopt(curl, CURLOPT_USERPWD, "user:password");
		 curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 2500L);

		 res = curl_easy_perform(curl);

		 if(res != CURLE_OK)
		 {
			 DEBUG_ERROR("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
		 }
		 else
		 {
			 if(chunk.size > 0)
			 {
				 //DEBUG_INFO("Response content: %s\n", chunk.memory);
				 memcpy(responseData, chunk.memory, ARRAY_SIZE(chunk.memory));
			 }

			 result = PASS;
		 }
		 curl_easy_cleanup(curl);
	}
	curl_global_cleanup();

	return result;
}

/**
 * HTTP post request/response
 * @param url
 * @param postData
 * @return
 */
int httpPost(uint8_t *url, uint8_t *postData, uint8_t *responseData)
{
	int result = FAIL;
	CURL *curl;
	CURLcode res;

	curl_global_init(CURL_GLOBAL_ALL);
	curl = curl_easy_init();

	if(curl)
	{
		 curl_easy_setopt(curl, CURLOPT_URL, (char*)url);
		 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
		 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
		 //curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
		 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (char*)postData);
		 //curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen((char*)postData));
		 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
		 //curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY);
		 //curl_easy_setopt(curl, CURLOPT_USERPWD, "user:password");
		 curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 2500L);

		 res = curl_easy_perform(curl);

		 if(res != CURLE_OK)
		 {
			 DEBUG_ERROR("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
		 }
		 else
		 {
			 if(chunk.size > 0)
			 {
				 //DEBUG_INFO("Response content: %s\n", chunk.memory);
				 memcpy(responseData, chunk.memory, ARRAY_SIZE(chunk.memory));
			 }

			 result = PASS;
		 }
		 curl_easy_cleanup(curl);
	}
	curl_global_cleanup();

	return result;
}

/**
 * HTTP put request
 * @param url
 * @param postData
 * @return
 */
int httpPut(uint8_t *url, uint8_t *postData)
{
	int result = FAIL;
	CURL *curl;
	CURLcode res;

	curl_global_init(CURL_GLOBAL_ALL);
	curl = curl_easy_init();

	if(curl)
	{
		struct curl_slist *headers = NULL;
		headers = curl_slist_append(headers, "Content-Type: literature/classic");
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
		curl_easy_setopt(curl, CURLOPT_URL, (char*)url);
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (char*)postData);
		curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
		//curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY);
		//curl_easy_setopt(curl, CURLOPT_USERPWD, "user:password");
		curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 2500L);

		res = curl_easy_perform(curl);

		if(res != CURLE_OK)
		{
			 DEBUG_ERROR("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
		}
		else
		{
			result = PASS;
		}
		curl_easy_cleanup(curl);
		curl_slist_free_all(headers);
	}
	curl_global_cleanup();

	return result;
}

/**
 * HTTP download response callback
 * @param ptr
 * @param size
 * @param nmemb
 * @param stream
 * @return
 */
static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
  size_t written = fwrite(ptr, size, nmemb, (FILE *)stream);

  return written;
}

/**
 * Curl download request
 * @param url
 * @return
 */
int curlDownload(uint8_t *url, uint8_t *filename)
{
	int result = FAIL;
	CURL *curl;
	CURLcode res;
	FILE *downloadFile;

	curl_global_init(CURL_GLOBAL_ALL);
	curl = curl_easy_init();

	if(curl)
	{
		curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 30000L);
		curl_easy_setopt(curl, CURLOPT_URL, (char*)url);
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
		//curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY);
		//curl_easy_setopt(curl, CURLOPT_USERPWD, "user:password");

		downloadFile = fopen((char*)filename, "wb");
		if(downloadFile)
		{
			curl_easy_setopt(curl, CURLOPT_WRITEDATA, downloadFile);
		    res = curl_easy_perform(curl);
		    if(res != CURLE_OK)
			{
		    	DEBUG_ERROR("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
			}
			else
			{
				//DEBUG_INFO("Download %s success.\n", url);
				result = PASS;
			}

		    fclose(downloadFile);
		}
		curl_easy_cleanup(curl);
	}
	curl_global_cleanup();

	return result;
}

/**
 * HTTP upload request
 * @param url
 * @param filename
 * @return
 */
int httpUpload(uint8_t *url, uint8_t *filename)
{
	int result = FAIL;
	CURL *curl;
	CURLcode res;
	FILE *upFile;
	struct stat file_info;
	curl_off_t speed_upload, total_time;

	if((upFile = fopen((char*)filename, "rb")))
	{
		if(fstat(fileno(upFile), &file_info) == 0)
		{
			curl = curl_easy_init();
			if(curl)
			{
				curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 30000L);
				curl_easy_setopt(curl, CURLOPT_URL, (char*)url);
				curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
				curl_easy_setopt(curl, CURLOPT_READDATA, upFile);
				curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
				curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
				//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
				//curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY);
				//curl_easy_setopt(curl, CURLOPT_USERPWD, "user:password");

				res = curl_easy_perform(curl);
				if(res != CURLE_OK)
				{
					DEBUG_ERROR("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
				}
				else
				{
					curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &speed_upload);
					curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);
					/*DEBUG_INFO("Upload %s to %s success.\n", filename, url);
					DEBUG_INFO("Speed: %" CURL_FORMAT_CURL_OFF_T " bytes/sec during %"
					           CURL_FORMAT_CURL_OFF_T ".%06ld seconds\n",
					           speed_upload,
					           (total_time / 1000000), (long)(total_time % 1000000));*/

					result = PASS;
				}

				fclose(upFile);

				curl_easy_cleanup(curl);
			}
		}
	}

	return result;
}

/**
 * File read callback
 * @param ptr
 * @param size
 * @param nmemb
 * @param stream
 * @return
 */
static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *stream)
{
  curl_off_t nread;
  size_t retcode = fread(ptr, size, nmemb, stream);
  nread = (curl_off_t)retcode;

  DEBUG_INFO("Read %" CURL_FORMAT_CURL_OFF_T " bytes from file\n", nread);

  return retcode;
}
/**
 * FTP upload request
 * @param url
 * @param filename
 * @return
 */
int ftpUpload(uint8_t *url, uint8_t *filename)
{
	int result = FAIL;
	CURL *curl;
	CURLcode res;
	FILE *upFile;
	struct stat file_info;
	curl_off_t fsize;

	curl_global_init(CURL_GLOBAL_ALL);
	if(!stat((char*)filename, &file_info))
	{
		fsize = (curl_off_t)file_info.st_size;
		DEBUG_INFO("%s size: %" CURL_FORMAT_CURL_OFF_T " bytes.\n", filename, fsize);

		if((upFile = fopen((char*)filename, "rb")))
		{
			curl = curl_easy_init();
			if(curl)
			{
				curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 30000L);
				curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
				curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
				curl_easy_setopt(curl, CURLOPT_URL, url);
				curl_easy_setopt(curl, CURLOPT_READDATA, upFile);
				curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fsize);
				res = curl_easy_perform(curl);
				if(res != CURLE_OK)
				{
					DEBUG_ERROR("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));

				}
				else
				{
					//DEBUG_INFO("Upload %s success.\n", url);
				}
				curl_easy_cleanup(curl);
			}
			fclose(upFile);
		}
	}
	curl_global_cleanup();

	return result;
}