//
// Dispatch_plc 调度plc模块, 主要是负责对接plc的通信数据缓存,以及调度主流程
//	本地缓存DB块的的数据, 内部线程负责下发任务指令和验收任务指令.
//

#ifndef NNXX_TESTS_DISPATCH_PLC_H
#define NNXX_TESTS_DISPATCH_PLC_H

#include "../error_code/error_code.h"
#include <glog/logging.h>
#include <thread>
#include <mutex>
#include "../tool/thread_condition.h"
#include "../tool/common_data.h"
#include "../tool/time_tool.h"
#include "../task/task_base.h"
//#include "../message/dispatch_message.pb.h"
#include "../message/message.pb.h"
#include "../dispatch/dispatch_communication.h"

#include "../tool/string_convert.h"

//调度plc
class Dispatch_plc
{
	//设备底层通信延时5000ms
#define	COMMUNICATION_OVER_TIME_MS	5000

	//调度指令超时时间 3600000 ms = 60 min
#define DISPATCH_PROCESS_TIMEOUT_MS							3600000
//调度指令超时时间  衰减值 在原有的基础上减少10秒
#define DISPATCH_PROCESS_ATTENUATION_TIMEOUT_MS				10000

public:
//调度plc状态
	enum Dispatch_plc_status
	{
		DISPATCH_PLC_UNKNOW               	= 0,    //未知
		DISPATCH_PLC_READY               	= 1,    //准备，待机
		DISPATCH_PLC_BUSY					= 2, 	//工作正忙, 暂时不用
		DISPATCH_PLC_DISCONNECT				= 3, 	//断连

		DISPATCH_PLC_REQUEST				= 4, 	//给plc发送请求
		DISPATCH_PLC_WORKING				= 5, 	//plc工作中
		DISPATCH_PLC_RESPONSE				= 6, 	//给主控答复


		DISPATCH_PLC_FAULT					= 100,	//故障
	};

	//指令完成状态, 设备答复指令, 返回任务完成的情况
	enum Response_status
	{
		RESPONS_WORKING            	= 0,    //任务进行中
		RESPONS_OVER               	= 1,    //任务完成
		RESPONS_ERROR				= 2,	//错误

		RESPONS_REALLOCATE_MIN_SHORT_CAR     	= 11,    //重新分配小车
		RESPONS_REALLOCATE_MID_SHORT_CAR     	= 12,    //重新分配中车
		RESPONS_REALLOCATE_BIG_SHORT_CAR     	= 13,    //重新分配大车
		RESPONS_REALLOCATE_HUGE_SHORT_CAR     	= 14,    //重新分配fault
		RESPONS_REALLOCATE_FAULT_SHORT_CAR     	= 15,    //重新分配fault
		RESPONS_REALLOCATE_MIN_LONG_CAR     	= 21,    //重新分配小车
		RESPONS_REALLOCATE_MID_LONG_CAR     	= 22,    //重新分配中车
		RESPONS_REALLOCATE_BIG_LONG_CAR     	= 23,    //重新分配大车
		RESPONS_REALLOCATE_HUGE_LONG_CAR     	= 24,    //重新分配fault
		RESPONS_REALLOCATE_FAULT_LONG_CAR     	= 25,    //重新分配fault

		RESPONS_MINOR_ERROR			= 100,	//一般故障, 可恢复
		RESPONS_CRITICAL_ERROR		= 101,	//致命故障,不可恢复
	};

public:
	Dispatch_plc();
	Dispatch_plc(const Dispatch_plc& other)= default;
	Dispatch_plc& operator =(const Dispatch_plc& other)= default;
	~Dispatch_plc();
public://API functions
	//调度plc 初始化
	Error_manager dispatch_plc_init(int plc_id);
	//调度plc 反初始化
	Error_manager dispatch_plc_uninit();
	//调度plc 执行请求
//	Error_manager execute_for_dispatch_request_msg(message::Dispatch_request_msg &dispatch_request_msg);
	//新版调度plc 执行请求 存车
	Error_manager execute_for_dispatch_request_msg(park_table &park_table_msg, Common_data::Dispatch_process_type dispatch_process_type, Common_data::Car_type car_type);
	//新版调度plc 执行请求 取车
	Error_manager execute_for_dispatch_request_msg(pick_table &pick_table_msg, Common_data::Dispatch_process_type dispatch_process_type, Common_data::Car_type car_type);

public://get or set member variable
	Dispatch_plc::Dispatch_plc_status get_dispatch_plc_status();
//	message::Dispatch_request_msg get_dispatch_request_msg();
	Error_manager get_result();
	float get_response_working_total_time();
	float get_response_working_remaining_time();
	void clear_request_msg();

	//控制外门， 调度发给plc的状态，
	//door_index 0~1是入口外门, 2~3是出口外门
	//door_mode 0是无效, 1是开门, 2是关门
	Error_manager control_ouside_door(int door_index, int door_mode);

	//获取plc搬运器的状态  0=故障 1=存车 2=取车 3=空闲 4=维护
	int get_plc_carrier_status();
protected://member functions
	//jiancha qingqiu xiaoxi
//    Error_manager check_dispatch_request_msg(message::Dispatch_request_msg & dispatch_request_msg);

	//执行外界任务的执行函数
	void execute_thread_fun();
	//数据储存线程函数
	void data_storage_thread_fun();

	//封装 给plc的调度请求
	Error_manager encapsulate_dispatch_request_to_plc();
	//封装 给plc的调度请求
	Error_manager encapsulate_dispatch_request_to_plc_new();
	//更新plc通信
	Error_manager update_dispatch_plc_communication();
	//检查plc答复反馈
	Error_manager check_response_from_plc();
	//检查plc答复反馈
	Error_manager check_response_from_plc_new();
	//发送调度答复信息给主控
	Error_manager send_dispatch_response_to_main_control();
	//发送调度答复信息给主控
	Error_manager send_dispatch_response_to_main_control_new();



protected://member variable
public:
	std::atomic<Dispatch_plc_status>			m_dispatch_plc_status;			//设备总状态, 控制任务流程(长流程)
	int 										m_plc_id;				//设备id, 索引, 就是楚天车库的单元号.
	std::mutex									m_lock;	//锁

	//任务执行线程
	std::thread*        						mp_execute_thread;   			//执行的线程指针，内存由本类管理
	Thread_condition							m_execute_condition;			//执行的条件变量

	//数据存储线程
	std::thread*        						mp_data_storage_thread;   			//数据存储线程的指针，内存由本类管理
	Thread_condition							m_data_storage_condition;			//数据存储线程的条件变量


	//指令
	Common_data::Dispatch_process_type			m_dispatch_process_type ;			//调度流程类型
//	message::Dispatch_request_msg				m_dispatch_request_msg;				//1执行搬运请求(主控->调度管理)
//	message::Dispatch_response_msg				m_dispatch_response_msg;			//6搬运动作执行完成后反馈结果(调度管理->主控)

	park_table									m_park_table_msg;		//停车表单
	pick_table									m_pick_table_msg;		//取车表单
//	int 										m_terminal_id;			//出入口id
	Common_data::Car_type						m_car_type;							//车的大小



	std::string									m_command_key;						//任务唯一码, 索引
	int 										m_timeout_ms;						//超时时间,单位ms
	std::chrono::system_clock::time_point		m_start_time;						//流程开始时间
	Error_manager								m_result;							//中间的错误码

	//数据缓存
	//调度管理给plc发送调度指令
	std::string										m_request_key;				//请求唯一码, 用作识别
	unsigned int									m_request_status = 0;			//请求确认标志
	// 调度指令的起点,终点,方向
	Common_data::Dispatch_process_type				m_request_dispatch_motion_direction ;		//调度方向	0=未知，1=存车，2=取车
	unsigned int									m_request_passageway_id = 0;					//出入口id	6个入口和6个出口
	Common_data::Passageway_direction				m_request_passageway_direction ;				//出入口方向	0=未知，1=入口，2=出口
	unsigned short									m_request_car_height_level = 0;								//车高 0=无车 1=1480 2=1500 3=2050 4=超高车
	unsigned int									m_request_parkingspace_index_id = 0;			//楼上车位索引id	1~180(3*6*13)
	unsigned int									m_request_parkingspace_unit_id = 0;				//楼上车位单元号	1~3
	unsigned int									m_request_parkingspace_label_id = 0;			//楼上车位标签号  1~78
	unsigned int									m_request_parkingspace_floor_id = 0;			//楼上车位楼层号	2~11
	unsigned int									m_request_parkingspace_room_id = 0;				//楼上车位房间号	1~6
	Common_data::Parkingspace_direction				m_request_parkingspace_direction ;			//楼上车位方向	0=未知，1=朝南，2=朝北
	//汽车的定位信息(地面雷达)
	float 											m_request_car_center_x = 0;				//整车的中心点x值, 四轮的中心, 单位:米 m
	float  											m_request_car_center_y = 0;				//整车的中心点y值, 四轮的中心, 单位:米 m
	float  											m_request_car_angle = 0;				//整车的车身旋转角, 单位:度 (-90~90)
	float  											m_request_car_front_theta = 0;			//整车的前轮的旋转角, 单位:度 (-90~90)
	float  											m_request_car_length = 0;				//整车的长度, 用于规避碰撞, 单位:米 m
	float  											m_request_car_width = 0;				//整车的宽度, 用于规避碰撞, 单位:米 m
	float  											m_request_car_height = 0;				//整车的高度, 用于规避碰撞, 单位:米 m
	float  											m_request_car_wheel_base = 0;			//整车的轮距, 前后轮的距离, 用于机器人或agv的抓车, 单位:米 m
	float  											m_request_car_wheel_width = 0;			//整车的轮距, 左右轮的距离, 用于机器人或agv的抓车, 单位:米 m
	std::string										m_request_car_license;					//车牌号(汽车唯一标示)	例如: 鄂A12345

	Common_data::Car_type							m_request_car_type;					//车的大小
	float 											m_request_uniformed_car_x = 0;				//转角复位后,车辆中心点x
	float  											m_request_uniformed_car_y = 0;				//转角复位后,车辆中心点y

	//防撞雷达
	Common_data::Anticollision_lidar_flag			m_request_anticollision_lidar_flag ;		//汽车是否停到正确的位置, 防撞雷达	预留, 楚天暂时不用,0=未知，1=位置正常，2=位置异常
	//轮距雷达
	float  											m_request_car_wheel_base_exact_value = 0;	//汽车前后轮距,轮距雷达的精确值	预留, 楚天暂时不用,单位:米 m


	//plc给调度管理发送调度答复
	std::string										m_response_key;									//答复唯一码, 用作识别
	Response_status									m_response_status;			//指令完成状态, 机器人答复指令, 返回任务完成的情况
	float											m_response_working_total_time;				//搬运总时间(秒)
	float											m_response_working_remaining_time;			//剩余时间(秒)
	// 调度指令的起点,终点,方向
	Common_data::Dispatch_process_type				m_response_dispatch_motion_direction ;		//调度方向	0=未知，1=存车，2=取车
	unsigned int									m_response_passageway_id = 0;					//出入口id	6个入口和6个出口
	Common_data::Passageway_direction				m_response_passageway_direction ;			//出入口方向	0=未知，1=入口，2=出口
	unsigned short									m_response_car_height_level = 0;								//车高 0=无车 1=1480 2=1500 3=2050 4=超高车
	unsigned int									m_response_parkingspace_index_id = 0;			//楼上车位索引id	1~180(3*6*13)
	unsigned int									m_response_parkingspace_unit_id = 0;			//楼上车位单元号	1~3
	unsigned int									m_response_parkingspace_label_id = 0;			//楼上车位标签号	1~78
	unsigned int									m_response_parkingspace_floor_id = 0;			//楼上车位楼层号	2~11
	unsigned int									m_response_parkingspace_room_id = 0;			//楼上车位房间号	1~6
	Common_data::Parkingspace_direction				m_response_parkingspace_direction ;			//楼上车位方向	0=未知，1=朝南，2=朝北
	//汽车的定位信息(地面雷达)
	float 											m_response_car_center_x = 0;			//整车的中心点x值, 四轮的中心, 单位:米 m
	float  											m_response_car_center_y = 0;			//整车的中心点y值, 四轮的中心, 单位:米 m
	float  											m_response_car_angle = 0;				//整车的车身旋转角, 单位:度 (-90~90)
	float  											m_response_car_front_theta = 0;			//整车的前轮的旋转角, 单位:度 (-90~90)
	float  											m_response_car_length = 0;				//整车的长度, 用于规避碰撞, 单位:米 m
	float  											m_response_car_width = 0;				//整车的宽度, 用于规避碰撞, 单位:米 m
	float  											m_response_car_height = 0;				//整车的高度, 用于规避碰撞, 单位:米 m
	float  											m_response_car_wheel_base = 0;			//整车的轮距, 前后轮的距离, 用于机器人或agv的抓车, 单位:米 m
	float  											m_response_car_wheel_width = 0;			//整车的轮距, 左右轮的距离, 用于机器人或agv的抓车, 单位:米 m
	std::string										m_response_car_license;					//车牌号(汽车唯一标示)	例如: 鄂A12345

	Common_data::Car_type							m_response_car_type;					//车的大小
	float 											m_response_uniformed_car_x = 0;				//转角复位后,车辆中心点x
	float  											m_response_uniformed_car_y = 0;				//转角复位后,车辆中心点y

	//防撞雷达
	Common_data::Anticollision_lidar_flag			m_response_anticollision_lidar_flag ;	//汽车是否停到正确的位置, 防撞雷达	预留, 楚天暂时不用,0=未知，1=位置正常，2=位置异常
	//轮距雷达
	float  											m_response_car_wheel_base_exact_value = 0;	//汽车前后轮距,轮距雷达的精确值	预留, 楚天暂时不用,单位:米 m



#ifdef CHUTIAN_PROJECT_PROJECT
	//dispatch状态
	unsigned char			m_dispatch_heartbeat = 0;				//心跳位, 0-255循环

	//plc状态信息
	unsigned char			m_plc_heartbeat = 0;				//心跳位, 0-255循环
	unsigned char			m_plc_status_info = 0;			//plc状态的集合
	//0 bit, 手动模式
	//1 bit, 自动模式
	//2 bit, 自动运行中
	//3 bit, 复位
	//4 bit, 1号口可以进车
	//5 bit, 2号口可以进车
	//6 bit, 预留
	//7 bit, 预留
//	unsigned char			m_reserved2_37[36] = {0};		//预留 36个
	float					m_turnplate_angle_min1 = 0;		//1号口转盘最小值
	float					m_turnplate_angle_max1 = 0;		//1号口转盘最大值
	float					m_turnplate_angle_min2 = 0;		//2号口转盘最小值
	float					m_turnplate_angle_max2 = 0;		//2号口转盘最大值
#endif //CHUTIAN_PROJECT_PROJECT
#ifdef SHANGGUJIE_PROJECT_PROJECT
	//硬件状态, 目前只做显示判断
	std::chrono::system_clock::time_point												m_last_update_time;	//状态更新时间点
	unsigned short																		m_last_heartbeat;			//上一次的心跳

	bool 																				m_plc_communication_status;		//调度和plc的通信状态, true=正常
	//调度状态
	Dispatch_communication::Dispatch_plc_status_from_manager_to_plc						m_dispatch_plc_status_from_manager_to_plc;//调度管理给plc发送状态消息 的结构体
	Dispatch_communication::Dispatch_plc_status_from_plc_to_manager						m_dispatch_plc_status_from_plc_to_manager;//plc给调度管理发送状态消息 的结构体
#endif //SHANGGUJIE_PROJECT_PROJECT









	//test time
	std::chrono::system_clock::time_point           test_start_time;
	std::chrono::system_clock::time_point           test_end_time;


private:

};


#endif //NNXX_TESTS_DISPATCH_PLC_H
