﻿#include "HttpClient.h"

#include "curl/curl.h"
#include "curl/easy.h"
#include "tracer.h"
#include "algorithm.h"
#include "cJSON.h"
#include <MyStringUtils.h>

struct curl_blob blob_clientCert;
struct curl_blob blob_clientKey;

HttpClient::HttpClient(void) {
}

HttpClient::~HttpClient(void)
{
}

size_t responseCallBack(char* contents, size_t size, size_t nmemb, void* userp) {
	size_t realsize = size * nmemb;//一次回调返回的数据量

	std::string* buffer = reinterpret_cast<std::string*>(userp);
	if (buffer)
		buffer->append((char*)contents, realsize);
	return realsize;
}

bool HttpClient::post(string url, string postParams, string& response) {
	Tracer::logger("Post", url);

	cJSON* obj = cJSON_Parse(postParams.c_str());
	if (cJSON_IsObject(obj)) {
		desensitizeReport(obj);//TODO Body 脱敏
		Tracer::json("callServer.body", obj);
	}
	response.clear();

	CURL* curl = curl_easy_init();
	//TODO 设置curl的请求头
	struct curl_slist* header_list = NULL;
	header_list = curl_slist_append(header_list, "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko");
	header_list = curl_slist_append(header_list, "Content-Type:application/json; charset=UTF-8");
	header_list = curl_slist_append(header_list, string("Authorization:Bearer ").append(token).c_str());
	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);

	//TODO 响应头数据 0代表不接收 1代表接收
	curl_easy_setopt(curl, CURLOPT_HEADER, false);

	curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);  //支持服务器跳转
	curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);  // enable TCP keep-alive for this transfer
	curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);	// keep-alive idle time to 120 seconds
	curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);	// interval time between keep-alive probes: 60 seconds

	//TODO 设置请求为post请求
	curl_easy_setopt(curl, CURLOPT_POST, true);

	//设置请求的URL地址
	curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
	//curl_easy_setopt(curl, CURLOPT_COOKIE, token);

	//设置post请求的参数
	if (!postParams.empty()) {
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postParams.c_str());
		curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postParams.length());
	}

	//设置ssl验证
	curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
	curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
	curl_easy_setopt(curl, CURLOPT_CAINFO, NULL);

	if (!this->clientCert.empty()) {
		curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
		curl_easy_setopt(curl, CURLOPT_SSLCERT_BLOB, &blob_clientCert);
	}
	if (!this->clientKey.empty()) {
		curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
		curl_easy_setopt(curl, CURLOPT_SSLKEY_BLOB, &blob_clientKey);
	}

	//CURLOPT_VERBOSE的值为1时，会显示详细的调试信息
	curl_easy_setopt(curl, CURLOPT_VERBOSE, debugVerbose);
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);

	//设置数据接收和写入函数
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, responseCallBack);

	//设置超时时间
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 20);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20);

	// 开启post请求
	CURLcode res = curl_easy_perform(curl);
	if (res != CURLE_OK)
	{
		Tracer::error("curl_easy_perform()", curl_easy_strerror(res));
		curl_easy_cleanup(curl);
		return false;
	}

	this->clientCert.clear();
	this->clientKey.clear();
	curl_easy_cleanup(curl);
	return true;
}

bool HttpClient::get(string url, string& response) {
	Tracer::logger("Get", url);
	response.clear();

	CURL* curl = curl_easy_init();
	struct curl_slist* header_list = NULL;
	header_list = curl_slist_append(header_list, "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko");
	header_list = curl_slist_append(header_list, "Accept:application/json; charset=UTF-8");
	header_list = curl_slist_append(header_list, "Content-Type:application/json; charset=UTF-8");
	header_list = curl_slist_append(header_list, "source:diagnosis");
	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);

	curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
	curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20);
	curl_easy_setopt(curl, CURLOPT_HEADER, false);
	curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, false);

	curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
	curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
	curl_easy_setopt(curl, CURLOPT_CAINFO, NULL);

	if (!this->clientCert.empty()) {
		curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
		curl_easy_setopt(curl, CURLOPT_SSLCERT_BLOB, &blob_clientCert);
	}
	if (!this->clientKey.empty()) {
		curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
		curl_easy_setopt(curl, CURLOPT_SSLKEY_BLOB, &blob_clientKey);
	}

	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, responseCallBack);

	curl_easy_setopt(curl, CURLOPT_VERBOSE, debugVerbose);
	CURLcode res = curl_easy_perform(curl);
	if (res != CURLE_OK)
	{
		Tracer::error("curl_easy_perform()", curl_easy_strerror(res));
		curl_easy_cleanup(curl);
		return false;
	}

	this->clientCert.clear();
	this->clientKey.clear();
	curl_easy_cleanup(curl);
	return true;
}

bool HttpClient::setClientCert(string& cert)
{
	this->clientCert = cert;
	blob_clientCert.data = (void*)this->clientCert.c_str();
	blob_clientCert.len = this->clientCert.size();
	blob_clientCert.flags = CURL_BLOB_COPY;
	return true;
}

bool HttpClient::setClientKey(string& key)
{
	this->clientKey = key;
	blob_clientKey.data = (void*)this->clientKey.c_str();
	blob_clientKey.len = this->clientKey.size();
	blob_clientKey.flags = CURL_BLOB_COPY;
	return true;
}

bool HttpClient::setToken(string token)
{
	this->token = token;
	return true;
}

void HttpClient::desensitizeReport(cJSON* obj)
{
	if (cJSON_HasObjectItem(obj, "testData")) {
		cJSON* arrayTestData = cJSON_GetObjectItem(obj, "testData");
		for (int i = 0; i < cJSON_GetArraySize(arrayTestData); i++) {
			cJSON* testDataItem = cJSON_GetArrayItem(arrayTestData, i);
			if (cJSON_HasObjectItem(testDataItem, "testItemList")) {
				cJSON* arrayTestItemList = cJSON_GetObjectItem(testDataItem, "testItemList");
				for (int j = 0; j < cJSON_GetArraySize(arrayTestItemList); j++) {
					cJSON* testItemListItem = cJSON_GetArrayItem(arrayTestItemList, j);

					if (cJSON_HasObjectItem(testItemListItem, "testItem")) {
						cJSON* arrayTestItem = cJSON_GetObjectItem(testItemListItem, "testItem");

						for (int k = 0; k < cJSON_GetArraySize(arrayTestItem); k++) {
							cJSON* testItem = cJSON_GetArrayItem(arrayTestItem, k);

							if (cJSON_HasObjectItem(testItem, "serverId")) {
								if (string("2E")._Equal(cJSON_GetObjectItem(testItem, "serverId")->valuestring))
								{
									if (cJSON_HasObjectItem(testItem, "did")) {

										cJSON* objTemp = cJSON_GetObjectItem(testItem, "did");
										string srcString = objTemp->valuestring;
										MyStringUtils::desensitize(srcString, 8);
										cJSON_ReplaceItemInObject(testItem, "did", cJSON_CreateString(srcString.c_str()));
									}
								}
								else if (string("31")._Equal(cJSON_GetObjectItem(testItem, "serverId")->valuestring))
								{
									if (cJSON_HasObjectItem(testItem, "did")) {

										cJSON* objTemp = cJSON_GetObjectItem(testItem, "did");
										string srcString = objTemp->valuestring;
										if (MyStringUtils::startWith(srcString, "01 80 20 "))
										{
											MyStringUtils::desensitize(srcString, 8);
											cJSON_ReplaceItemInObject(testItem, "did", cJSON_CreateString(srcString.c_str()));
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
}

bool HttpClient::setDeviceSn(string deviceSn)
{
	this->deviceSn = deviceSn;
	return true;
}
