package com.persagy.cameractl.service.windows;

import java.awt.Point;
import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;

import javax.swing.SwingUtilities;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.hutool.core.date.DateUtil;

import com.persagy.cameractl.conf.AllStaticConfig;
import com.persagy.cameractl.service.common.LoginModule;
import com.persagy.cameractl.service.common.ToolKits;
import com.persagy.cameractl.utils.Camera;
import com.persagy.cameractl.utils.EnumTools;
import com.persagy.cameractl.utils.OtherTools;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.persagy.cameractl.service.windows.NetSDKLib.*;
import com.persagy.cameractl.utils.ResultClass;

public class DahMainWindows {
	Logger logger = LoggerFactory.getLogger(DahMainWindows.class);

	//默认连接超时时间，单位：毫秒
	int wait_time=5000;
	
	// 摄像头对象
	Camera _camera;

	// 登录句柄
	LLong loginHandler;

	// 下载句柄
	LLong m_hDownLoadHandle = new LLong(0);

//	回放时生成的回放文件路径，不包含文件名称
	String playBackFileDir;
//	回放时生成的回放文件名称
	String playBackFileName;
//	回放时生成的回放文件路径，包含文件名称
	String playBackFilePath;

	// 回放mp4生成的状态码，0 生成中 1 生成结束 2生成错误
	int playBackMp4State = 1;

	public DahMainWindows(Camera cameraI) {
		this._camera = cameraI;
	};

	/* 初始化SDK、注册用户 */
	private String init() {
		// 初始化
		ResultClass initResult = LoginModule.init(null, null);
		// 初始化失败
		if (initResult.name == false)
			return EnumTools.ControlFailedCode.init_failed.toString();
		// ---------------登录
		ResultClass loginResult = LoginModule.login(_camera.cameraIp, _camera.cameraPort, _camera.userName,
				_camera.password);
//        登录成功
		if (loginResult.name) {
			loginHandler = new LLong(Integer.valueOf(String.valueOf(loginResult.resultData)));
			return "true";
		}
		return loginResult.reason;
	};

	/*
	 * 获取控制命令的参数1 左上左下右上右下 需要第一个参数(即垂直速度)
	 */
	private int getControlParam1() {
		String str1 = EnumTools.listSdkCommand.get(10);
		String str2 = EnumTools.listSdkCommand.get(11);
		String str3 = EnumTools.listSdkCommand.get(12);
		String str4 = EnumTools.listSdkCommand.get(13);
		String commandStr = _camera.command;
		if (commandStr.equals(str1) || commandStr.equals(str2) || commandStr.equals(str3) || commandStr.equals(str4))
			return _camera.verSpeed;
		return 0;
	};

	/*
	 * 获取控制命令的参数2(即水平速度) 上下左右变倍调焦光圈左上左下右上右下需要第二个参数
	 */
	private int getControlParam2() {
		return this._camera.speed;
	};

	/*
	 * 根据自定义的命令类型，转化为大华的命令
	 */
	private int convertCommandType() {
		int commandIndex = EnumTools.listSdkCommand.indexOf(_camera.command);
		switch (commandIndex) {
		case 0:
			return NET_PTZ_ControlType.NET_PTZ_ZOOM_ADD_CONTROL;
		case 1:
			return NET_PTZ_ControlType.NET_PTZ_ZOOM_DEC_CONTROL;
		case 2:
			return NET_PTZ_ControlType.NET_PTZ_FOCUS_ADD_CONTROL;
		case 3:
			return NET_PTZ_ControlType.NET_PTZ_FOCUS_DEC_CONTROL;
		case 4:
			return NET_PTZ_ControlType.NET_PTZ_APERTURE_ADD_CONTROL;
		case 5:
			return NET_PTZ_ControlType.NET_PTZ_APERTURE_DEC_CONTROL;
		case 6:
			return NET_PTZ_ControlType.NET_PTZ_UP_CONTROL;
		case 7:
			return NET_PTZ_ControlType.NET_PTZ_DOWN_CONTROL;
		case 8:
			return NET_PTZ_ControlType.NET_PTZ_LEFT_CONTROL;
		case 9:
			return NET_PTZ_ControlType.NET_PTZ_RIGHT_CONTROL;
		case 10:
			return NET_EXTPTZ_ControlType.NET_EXTPTZ_LEFTTOP;
		case 11:
			return NET_EXTPTZ_ControlType.NET_EXTPTZ_LEFTDOWN;
		case 12:
			return NET_EXTPTZ_ControlType.NET_EXTPTZ_RIGHTTOP;
		case 13:
			return NET_EXTPTZ_ControlType.NET_EXTPTZ_RIGHTDOWN;
		default:
			return -1;
		}
	}

	/*
	 * 大华摄像头控制
	 */
	private String controlCamera() {
//		0 开始	1 停止
		int dwStop = this._camera.dwStop == true ? 0 : 1;
		/*
		 * 八方控制、变倍、调焦、光圈 均不需要第三个参数;发送停止命令时，三个参数均为零 上下左右变倍调焦光圈 只需要第二个参数，代表速度 左上左下右上右下
		 * 需要第一个参数(垂直速度)和第二个参数(水平速度) 水平旋转，第一个参数和第二个参数均不需要
		 */
		int lParam1 = dwStop == 1 ? 0 : getControlParam1();
		int lParam2 = dwStop == 1 ? 0 : getControlParam2();
		int lParam3 = 0;
		int commandType = convertCommandType();

		boolean controlResult = LoginModule.netsdk.CLIENT_DHPTZControlEx(this.loginHandler, this._camera.channel,
				commandType, lParam1, lParam2, lParam3, dwStop);

		// 控制操作调用失败
		if (!controlResult) {
			String reason = ToolKits.getErrorCodePrint();
			// 返回失败时的错误码
			return reason;
		}
		return "true";
	};

	/*
	 * 返回错误结果，同时释放资源 isLogingout 是否注销登录，在注册失败时只需要释放SDK不需要注销登录 executeResult
	 * 调用sdk的结果，一般为错误码 errPrefixString 返回给客户端调用者的错误信息前缀
	 */
	private ResultClass executeErr(boolean isLogingout, String executeResult, String errPrefixString) {
		if (isLogingout)
			LoginModule.logout(loginHandler);
		String errReason = OtherTools.joinErrStr(executeResult, errPrefixString);
		return OtherTools.executeErr(errReason);
	};

	/*
	 * 返回调用成功及结果数据,同时注销登陆
	 */
	private ResultClass executeSuccess(Object resultData) {
		LoginModule.logout(loginHandler);
		return OtherTools.executeSuccess(resultData);
	};

	/*
	 * 视频下载
	 * */
	private String RecordDown() {
		// -----首先设置码流类型
		IntByReference steamType = new IntByReference(2);// 0-主辅码流,1-主 码流,2-辅码流
		int emType = EM_USEDEV_MODE.NET_RECORD_STREAM_TYPE;
		boolean bret = LoginModule.netsdk.CLIENT_SetDeviceMode(loginHandler, emType, steamType.getPointer());
		// 码流设置失败
		if (!bret) {
			return "码流设置失败：" + ToolKits.getErrorCodePrint();
		}

		// --------下载录像
		// 开始时间
		NET_TIME struStartTime = new NET_TIME();
		// 结束时间
		NET_TIME struStopTime = new NET_TIME();

		Date startDate = DateUtil.parse(this._camera.startDateStr);
		Date endDate = DateUtil.parse(this._camera.endDateStr);

		struStartTime.dwYear = DateUtil.year(startDate);
		struStartTime.dwMonth = DateUtil.month(startDate) + 1;
		struStartTime.dwDay = DateUtil.dayOfMonth(startDate);
		struStartTime.dwHour = DateUtil.hour(startDate, true);
		struStartTime.dwMinute = DateUtil.minute(startDate);
		struStartTime.dwSecond = DateUtil.second(startDate);

		struStopTime.dwYear = DateUtil.year(endDate);
		struStopTime.dwMonth = DateUtil.month(endDate) + 1;
		struStopTime.dwDay = DateUtil.dayOfMonth(endDate);
		struStopTime.dwHour = DateUtil.hour(endDate, true);
		struStopTime.dwMinute = DateUtil.minute(endDate);
		struStopTime.dwSecond = DateUtil.second(endDate);

		playBackMp4State = 0;
		m_hDownLoadHandle = LoginModule.netsdk.CLIENT_DownloadByTimeEx(loginHandler, _camera.channel, 0, struStartTime,
				struStopTime, playBackFilePath, new DownLoadPosCallBackByFile(), null, null, null, null);
		// 下载失败
		if (m_hDownLoadHandle.longValue() == 0) {
			playBackMp4State = 2;
			return "下载失败：" + ToolKits.getErrorCodePrint();
		}
		return "true";
	};

	/* 大华摄像头控制入口 */
	public ResultClass controlMain() {
		// 初始化
		String initResult = this.init();
		if (initResult != "true") {
			return this.executeErr(false, initResult, "初始化失败");
		}
		// 控制开始
		String controlResult = this.controlCamera();
		if (controlResult != "true") {
			return this.executeErr(true, controlResult, "控制指令调用失败");
		}
		_camera.dwStop = false;
		// 控制停止
		String controlResult2 = this.controlCamera();
		if (controlResult2 != "true") {
			return this.executeErr(true, controlResult2, "停止控制指令调用失败");
		}
		return this.executeSuccess(null);
	};

	/* 回放入口 */
	public ResultClass playBackMain() {
		ResultClass returnResult = new ResultClass();
		playBackFilePath = OtherTools.getVideoFilePath();
		if (playBackFilePath.equals("")) {
			returnResult.name = false;
			returnResult.reason = "回放文件名称生成失败";
			return returnResult;
		}

		File mp4File = new File(playBackFilePath);
		playBackFileName = mp4File.getName();
		File fileParent = mp4File.getParentFile();// 返回的是File类型,可以调用exsit()等方法
		playBackFileDir = fileParent.getPath();

		String errPrefixStr = "回放失败";
		// 初始化
		String initResult = this.init();
		if (initResult != "true")
			return this.executeErr(false, initResult, "初始化失败");

		// 回放开始
		String playBackResult = this.RecordDown();
		if (playBackResult != "true")
			return this.executeErr(true, playBackResult, "视频文件下载失败");

		final CountDownLatch latch = new CountDownLatch(1);// 使用java并发库concurrent
		new Thread(new Runnable() {
			public void run() {
				// 生成中
				while (playBackMp4State == 0) {
					try {
						Thread.sleep(1);
					} catch (Exception e) {
						// TODO: handle exception
					}
				}
				latch.countDown();// 让latch中的数值减一

			}
		}).start();
		try {
			latch.await();// 阻塞当前线程直到latch中数值为零才执行
			// 生成成功
			if (playBackMp4State == 1) {
				String token = OtherTools.getMp4NamePrefix(playBackFileName);
				String url = OtherTools.playMp4RootUrl + "dahua/" + token;
				Map<String, String> dataMap = new HashMap<String, String>();
				dataMap.put("url", url);
				return this.executeSuccess(dataMap);
			}
			return this.executeErr(true, "视频文件生成失败", errPrefixStr);
		} catch (Exception e) {
			return this.executeErr(true, "等待MP4生成异常", errPrefixStr);
		}
	};

	/* 大屏轮巡入口 */
	public ResultClass dapLx() {
		// 初始化
		String initResult = this.init();
		if (initResult != "true") {
			return this.executeErr(false, initResult, "初始化失败");
		}
		// 查询融合屏通道信息
		NetSDKLib.NET_COMPOSITE_CHANNEL netComposite_CHANNEL = new NetSDKLib.NET_COMPOSITE_CHANNEL();
		int rhpSize = netComposite_CHANNEL.size();
		Pointer rhpChannelPointer = new Memory(netComposite_CHANNEL.size());
		boolean queryRhpXx = LoginModule.netsdk.CLIENT_QueryDevState(loginHandler, NetSDKLib.NET_DEVSTATE_COMPOSITE_CHN,
				rhpChannelPointer, rhpSize, new IntByReference(0), wait_time);
		if (!queryRhpXx) {
			String reason = ToolKits.getErrorCodePrint();
			long peer = Pointer.nativeValue(rhpChannelPointer);
			Native.free(peer);//手动释放内存
			Pointer.nativeValue(rhpChannelPointer, 0);//避免Memory对象被GC时重复执行Nativ.free()方法
			return this.executeErr(true, "获取融合屏通道号错误：" + reason, "");
		}

		ToolKits.GetPointerDataToStruct(rhpChannelPointer, 0, netComposite_CHANNEL);
		String screenId = new String(netComposite_CHANNEL.szCompositeID).trim();
		if (!screenId.equals(AllStaticConfig.dahuaTvScreenId))
			return this.executeErr(true, "未获取到设置的屏ID", "");
		
		//融合屏使用的虚拟通道号
		int rhpChannel=netComposite_CHANNEL.nVirtualChannel;
		
		//-------------获取输出通道上的窗口数量
		//首先获取分割模式，怎么主动释放nET_SPLIT_MODE_INFO
		NetSDKLib.NET_SPLIT_MODE_INFO nET_SPLIT_MODE_INFO=new NetSDKLib.NET_SPLIT_MODE_INFO();
		boolean getCkCountResult= LoginModule.netsdk.CLIENT_GetSplitMode(loginHandler,rhpChannel,nET_SPLIT_MODE_INFO,wait_time);
		if(!getCkCountResult) {
			String reason2 = ToolKits.getErrorCodePrint();
			return this.executeErr(true, "获取融合屏分割模式错误：" + reason2, "");
		}
		//自由开窗模式下才可以
		if(NetSDKLib.NET_SPLIT_MODE.NET_SPLIT_FREE==nET_SPLIT_MODE_INFO.emSplitMode) {}
		
		
		return this.executeSuccess(null);
	};

//	public static void stopDownLoadRecordFile(LLong m_hDownLoadHandle) {
//		if (m_hDownLoadHandle.longValue() == 0) {
//			return;
//		}
//		LoginModule.netsdk.CLIENT_StopDownload(m_hDownLoadHandle);
//	}

	/*用于下载时的进度回调*/
	class DownLoadPosCallBackByFile implements NetSDKLib.fTimeDownLoadPosCallBack {
		public void invoke(LLong lLoginID, final int dwTotalSize, final int dwDownLoadSize, int index,
				NET_RECORDFILE_INFO.ByValue recordfileinfo, Pointer dwUser) {
			SwingUtilities.invokeLater(new Runnable() {
				@Override
				public void run() {
//					System.out.println("ByFile " + dwDownLoadSize + " / " + dwTotalSize);
//					downloadByFileProgressBar.setValue(dwDownLoadSize*100 / dwTotalSize);
					// 下载完成
					if (dwDownLoadSize == -1) {
						playBackMp4State = 1;
					}
				}
			});
		}
	}

}
