/*
SDK示例: YoseenDemo

 简要说明SDK函数用法: 设备发现\配置, 用户登入\登出, 预览开始\停止, jpg\mp4\stream文件保存
 */
#include <YoseenSDK/YoseenSDK.h>
#include "Common/keyboard.h"

#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <time.h>

/*
 *
 * */
enum ShellViewFlags {
	ShellViewFlags_SaveMp4 = 0x0001, ShellViewFlags_SaveStream = 0x0002,
};
struct ShellView {
	s32 flags;

	//
	s32 userHandle;							//用户句柄
	s32 previewHandle;						//预览句柄
	YoseenLoginInfo loginInfo;				//登入信息
	CameraBasicInfo cameraBasicInfo;		//热像仪基本信息
	YoseenPreviewInfo previewInfo;			//预览信息

	//
	char fn[256];							//文件名称
	char echo[256];							//操作反馈
};
static ShellView _shellView = { };

/*
 主程序建立
 */
static int setup() {
	int ret = Yoseen_InitSDK();
	if (0 != ret){
		printf("Yoseen_InitSDK, ret %d\n",ret);
		return ret;
	}

	_shellView.userHandle = -1;
	_shellView.previewHandle = -1;

	return ret;
}

/*
 主程序清理
 */
static void cleanup() {
	if (_shellView.previewHandle >= 0) {
		Yoseen_StopPreview(_shellView.previewHandle);
	}

	if (_shellView.userHandle >= 0) {
		Yoseen_Logout(_shellView.userHandle);
	}

	Yoseen_FreeSDK();
}

/**
 按时间和后缀生成文件名
 */
static const char* _getFileName(const char* suffix) {
	static char fn[64];
	time_t t1 = time(NULL);
	struct tm* t2 = localtime(&t1);
	sprintf(fn, "./Data/%04d%02d%02d_%02d%02d%02d%s", t2->tm_year + 1900,
			t2->tm_mon + 1, t2->tm_mday, t2->tm_hour, t2->tm_min, t2->tm_sec,
			suffix);
	return fn;
}

/*
 显示SDK函数调用结果
 */
static void ShellView_Echo(const char *szFormat, ...) {
	char* echo = _shellView.echo;

	va_list ap;
	va_start(ap, szFormat);
	vsnprintf(echo, 256, szFormat, ap);
	va_end(ap);

	printf("%s\n", echo);
}

/**
 发现在线设备
 */
static void _discover() {
	//发现在线设备, 返回响应链表
	DiscoverCameraResp2* dcrList = Yoseen_DiscoverCameras(xxxdiscoverflags_broadcast);

	//迭代响应链表
	char str[256];
	if (dcrList == NULL) {
		snprintf(str, 256, "discover no cameras");
	} else {
		char* w = str;
		snprintf(w, 32, "discover cameras, ");
		w += strlen(w);
		DiscoverCameraResp2* dcr = dcrList;
		while (dcr != NULL) {
			u32 ip = dcr->CameraIp;
			u8* p = (u8*) &ip;
			snprintf(w, 16, "%d.%d.%d.%d, ", *(p + 3), *(p + 2), *(p + 1), *p);
			w += strlen(w);
			dcr = dcr->pNext;
		}
	}

	//
	YoseenLoginInfo& loginInfo = _shellView.loginInfo;
	if (NULL != dcrList) {
		u8* p = (u8*) &dcrList->CameraIp;
		snprintf(loginInfo.CameraAddr, 32, "%d.%d.%d.%d", *(p + 3), *(p + 2), *(p + 1), *p);
	}
	ShellView_Echo("%s. ===use %s===", str, loginInfo.CameraAddr);

	//释放发现响应链表
	Yoseen_DiscoverCamerasFree(&dcrList);
}

/*
 用户登入和登出
 */
static void _login() {
	s32 userHandle = _shellView.userHandle;
	if (userHandle >= 0) {
		s32 ret = Yoseen_Logout(userHandle);
		_shellView.userHandle = -1;
		ShellView_Echo("Yoseen_Logout, ret %d", ret);
	} else {
		CameraBasicInfo& cameraBasicInfo = _shellView.cameraBasicInfo;
		YoseenLoginInfo& loginInfo = _shellView.loginInfo;
		//strcpy(loginInfo.CameraAddr,"192.168.1.201");//force ip
		userHandle = Yoseen_Login(&loginInfo, &cameraBasicInfo);
		if (userHandle >= 0) {
			_shellView.userHandle = userHandle;
		}
		ShellView_Echo("Yoseen_Login, ret %d", userHandle);
	}
}

/*
 预览开始和停止
 */

/*
 预览回调, 此回调触发在工作线程
 */
static void __stdcall _previewCallback(s32 errorCode, DataFrame* frame, void* customData) {
	if (0 == errorCode) {
//		//接收数据成功, 根据预览数据类型, 选择对应数据做后处理
//		bgra* bmpData = (bgra*) frame->Bmp;
//
//		//温度流单帧
//		DataFrameHeader* tempHead = (DataFrameHeader*) frame->Head;
//		s16* tempData = (s16*) frame->Temp;
//
//		//视频流单帧
//		H264FrameHeader* h264Head = (H264FrameHeader*) frame->H264;
	} else {
		//接收数据失败, 预览内置自动恢复, YET_PreviewRecoverBegin-YET_PreviewRecoverEnd
		ShellView_Echo("PreviewCallback, errorCode %d", errorCode);
	}
}

static void _stopPlay() {
	s32 previewHandle = _shellView.previewHandle;
	if (previewHandle >= 0) {
		s32 ret = Yoseen_StopPreview(previewHandle);
		_shellView.previewHandle = -1;
		ShellView_Echo("Yoseen_StopPreview, ret %d", ret);
	}
}

static void _startPlay(s32 dataType) {
	_stopPlay();

	//
	YoseenPreviewInfo& previewInfo = _shellView.previewInfo;
	previewInfo.DataType = dataType;
	previewInfo.CustomData = &_shellView;
	previewInfo.CustomCallback = _previewCallback;
	previewInfo.Hwnd = NULL;
	s32 previewHandle = Yoseen_StartPreview(_shellView.userHandle, &previewInfo);
	//s32 previewHandle = Yoseen_StartPreviewTempScale(_shellView.userHandle, &previewInfo, 3);
	ShellView_Echo("Yoseen_StartPreview, ret %d", previewHandle);
	if (previewHandle < 0) {
		return;
	}
	_shellView.previewHandle = previewHandle;
}

/*
 保存jpg文件, 文件内包含单帧温度数据
 */
static void _saveJpgx() {
	s32 userHandle = _shellView.userHandle;
	if (userHandle < 0) return;

	const char* fn = _getFileName(".jpg");
	s32 ret = Yoseen_SaveFrame(userHandle, fn, 1);
	ShellView_Echo("Yoseen_SaveFrame, fn %s, ret %d", fn, ret);
}

/*
 保存mp4文件
 */
static void _saveMp4() {
	s32 previewHandle = _shellView.previewHandle;
	if (0 > previewHandle) return;
	s32 ret;
	s32& flags = _shellView.flags;
	if (flags & ShellViewFlags_SaveMp4) {
		ret = Yoseen_EndSave(previewHandle, xxxmediafile_mp4);
		flags &= (~ShellViewFlags_SaveMp4);
		ShellView_Echo("Yoseen_EndSave, ret %d", ret);
	} else {
		const char* fn = _getFileName(".mp4");
		ret = Yoseen_BeginSave(previewHandle, fn, xxxmediafile_mp4);
		if (0 == ret) {
			flags |= ShellViewFlags_SaveMp4;
		}
		ShellView_Echo("Yoseen_BeginSave, fn %s, ret %d", fn, ret);
	}
}

/*
 保存stream文件, 文件内包含多帧温度数据
 */
static void _saveStream() {
	s32 previewHandle = _shellView.previewHandle;
	if (0 > previewHandle) return;
	s32 ret;
	s32& flags = _shellView.flags;
	if (flags & ShellViewFlags_SaveStream) {
		ret = Yoseen_EndSave(previewHandle, xxxmediafile_stream);
		flags &= (~ShellViewFlags_SaveStream);
		ShellView_Echo("Yoseen_EndSave, ret %d", ret);
	} else {
		const char* fn = _getFileName(".stream");
		ret = Yoseen_BeginSave(previewHandle, fn, xxxmediafile_stream);
		if (0 == ret) {
			flags |= ShellViewFlags_SaveStream;
		}
		ShellView_Echo("Yoseen_BeginSave, fn %s, ret %d", fn, ret);
	}
}

/*
 主程序消息循环
 */
#define Const_Menu		"=================================================================\n"\
"YoseenDemo\n"\
"d: discover cameras\n"\
"1: login, logout\n"\
"2: start temp preview\n"\
"3: start video preview\n"\
"4: stop preview\n===\n"\
"6: save .jpg\n"\
"7: save .mp4\n"\
"8: save .stream\n"\
"q: quit\n"\
"=================================================================\n"
static void msgloop() {
	printf(Const_Menu);

	while (1) {
		usleep(200 * 1000);
		if (_kbhit()) {
			char ch = _getch();
			switch (ch) {

			//发现在线热像仪
			case 'd':
				_discover();
				break;

			//登入热像仪
			case '1':
				_login();
				break;

			//开始和停止预览
			case '2':
				_startPlay(xxxdatatype_temp);
				break;
			case '3':
				_startPlay(xxxdatatype_video);
				break;
			case '4':
				_stopPlay();
				break;

			//保存单帧和多帧数据
			case '6':
				_saveJpgx();
				break;
			case '7':
				_saveMp4();
				break;
			case '8':
				_saveStream();
				break;

			//退出
			case 'q':
				goto error1;
			default:
				break;
			}
		}
	}

	error1: return;
}

/*
 主程序入口函数
 */
int main(int argc, char* argv[]) {
	if(argc>=2){
		YoseenLoginInfo& loginInfo = _shellView.loginInfo;
		strncpy(loginInfo.CameraAddr, argv[1],128);
		printf("===manual ip %s===\n",loginInfo.CameraAddr);
	}

	//
	int ret = setup();
	if (0 != ret) {
		return ret;
	}

	msgloop();

	cleanup();

	return ret;
}

