//
// Created by huli on 2021/3/24.
//

#ifndef NNXX_TESTS_DISPATCH_COORDINATES_H
#define NNXX_TESTS_DISPATCH_COORDINATES_H

#include "../error_code/error_code.h"
#include "../dispatch/dispatch_parameter.pb.h"
#include "../tool/singleton.h"
#include "../tool/point3D_tool.h"
#include "../tool/common_data.h"
#include <glog/logging.h>
#include <map>
#include <mutex>

//调度的坐标系
class Dispatch_coordinates:public Singleton<Dispatch_coordinates>
{
// 子类必须把父类设定为友元函数，这样父类才能使用子类的私有构造函数。
	friend class Singleton<Dispatch_coordinates>;

public:
	//调度坐标参数
#define DISPATCH_COORDINATES_PARAMETER_PATH "dispatch_coordinates.prototxt"

	//出入口的功能模式
	enum Passageway_functioning_pattern
	{
		PASSAGEWAY_FUNCTIONING_PATTERN_UNKNOWN          = 0,    //未知
		PASSAGEWAY_FUNCTIONING_PATTERN_INLET            = 1,    //单向入口
		PASSAGEWAY_FUNCTIONING_PATTERN_OUTLET           = 2,    //单向出口
		PASSAGEWAY_FUNCTIONING_PATTERN_BIDIRECTION      = 3,    //双向口
	};

	//车位分配路线（根据中跑车的路线来定）
	enum Parkspace_path
	{
		UNKNOW_PATH = 0,				//未知
		OPTIMAL_PATH = 1,				//最优路径, A方案
		LEFT_PATH = 2,					//左侧路径, B方案
		RIGHT_PATH = 3,					//右车路径, B方案
		TEMPORARY_CACHE_PATH = 4,		//临时停车位路径, B方案

		DOUBLE_PATH = 5, 				//左右都可以的路径, B方案取车专用
		THIRD_FLOOR_PATH = 6, 			//3楼路径, B方案取车专用

	};

	//调度设备的id集合
	struct space_device
	{
		int m_catcher_id;
		int m_carrier_id;
	};

private:
	// 父类的构造函数必须保护，子类的构造函数必须私有。
	Dispatch_coordinates();
public:
	//必须关闭拷贝构造和赋值构造，只能通过 get_instance 函数来进行操作唯一的实例。
	Dispatch_coordinates(const Dispatch_coordinates& other) = delete;
	Dispatch_coordinates& operator =(const Dispatch_coordinates& other) = delete;
	~Dispatch_coordinates();
public://API functions
	//初始化 调度的坐标系 模块。如下三选一
	virtual Error_manager dispatch_coordinates_init();
	//初始化 调度的坐标系 模块。从文件读取
	Error_manager dispatch_coordinates_init_from_protobuf(std::string prototxt_path);
	//初始化 调度的坐标系 模块。从protobuf读取
	Error_manager dispatch_coordinates_init_from_protobuf(Dispatch_proto::Dispatch_coordinates_parameter_all& dispatch_coordinates_parameter_all);
	//反初始化
	virtual Error_manager dispatch_coordinates_uninit();
	//获取2点之间的路径长度, 只算x轴和z轴, 只是计算一个大概值
	Error_manager get_distance(int coordinates_id_1, int coordinates_id_2, Parkspace_path parkspace_path, float & distance);
	//把1楼出入口的坐标修正到2楼.
	bool amend_coordinates_from_1st_floor_to_2nd_floor(int & coordinates_id);
	//选择最近的搬运器, return true:选左边, return false:选右边
	bool choice_nearest_carrier(int dispatch_source, int coordinates_id_1, int coordinates_id_2);
	//判断取车的路径
	Parkspace_path get_pickup_path(int dispatch_source, int dispatch_destination);
	//检查停车位和取车位, 判断是否能改道
	bool is_able_redirect(int pickup_parkspace_id, int store_parkspace_id);

	//搬运器尝试空间加锁
	Error_manager carrier_try_space_lock(int row_min, int column_min, int row_max, int column_max, int carrier_id, int & avoid_catcher_id );
	//抓取器尝试空间加锁
	Error_manager catcher_try_space_lock(int row_min, int column_min, int row_max, int column_max, int catcher_id );
	//搬运器强制空间加锁(不做判断了, 直接加锁)
	Error_manager carrier_force_space_lock(int row_min, int column_min, int row_max, int column_max, int carrier_id );
	//抓取器强制空间加锁(不做判断了, 直接加锁)
	Error_manager catcher_force_space_lock(int row_min, int column_min, int row_max, int column_max, int catcher_id );
	//搬运器解锁, 退回电梯井, 全部解锁
	Error_manager carrier_space_unlock(int carrier_id);
	//抓取器解锁, 上升到最上层, 全部解锁, 保留4楼的空间锁
	Error_manager catcher_space_unlock(int catcher_coordinates_id, int catcher_id);
	//抓取器 加锁3楼和4楼的2*3个车位
	Error_manager catcher_3rd_4st_floor_space_lock(int catcher_4st_floor_coordinates_columns, int catcher_id);
public://get or set member variable

	void set_space_lock(int space_rows, int space_columns, int catcher_id, int carrier_id);
	void set_space_lock_for_catcher(int space_rows, int space_columns, int catcher_id);
	void set_space_lock_for_carrier(int space_rows, int space_columns, int carrier_id);

	void set_space_lock(int space_id, int catcher_id, int carrier_id);
	void set_space_lock_for_catcher(int space_id, int catcher_id);
	void set_space_lock_for_carrier(int space_id, int carrier_id);

	void cout_space_lock();

protected://member functions

public://member variable

	std::mutex											m_lock;
	//空间锁, 防撞. (存放着调度设备的id集合, 交接过程中, 允许两个个设备占有同一个空间)
	space_device**										mpp_space_lock;						//空间锁, 二维数组, 存放着调度设备的id集合, 内存由本模块管理, (默认11*15=165)
	int													m_space_lock_rows;					//空间锁, 行		(默认11)
	int													m_space_lock_columns;				//空间锁, 列		(默认15)
	int													m_space_lock_total;					//空间锁, 总数	(默认165)
	int 												m_liftway_width;					//电梯井道宽, 默认占有3列车位



	//楼上车位的坐标 1~165
	std::map<int, Point3D_tool::Point3D>	m_packspace_coordinates_map;

	//一楼出入口的坐标 1100~1107
	std::map<int, Point3D_tool::Point3D>	m_passageway_coordinates_map;

	//搬运器在2~4楼交界处 的坐标 1201~1206 1301~1306 1401~1406
	//搬运器在电梯井的坐标 2101~2112 2201~2212
	//搬运器在一楼出入口的坐标 1100 和 1107
	std::map<int, Point3D_tool::Point3D>	m_carrier_coordinates_map;

	//机器手在2~4楼交界处 的坐标 1201~1206 1301~1306 1401~1406
	//机器手在一楼出入口的坐标 1101~1106
	std::map<int, Point3D_tool::Point3D>	m_catcher_coordinates_map;


	Point3D_tool::Point3D_box				m_carrier_box;//搬运器 限定范围DISPATCH_CARRIER_PICKUP_END
	Point3D_tool::Point3D_box				m_catcher_box;//机器手 限定范围

	float									m_catcher_b_min;
	float									m_catcher_b_max;
	float									m_catcher_d1_min;
	float									m_catcher_d1_max;
	float									m_catcher_d2_min;
	float									m_catcher_d2_max;


	float 									m_default_wheelbase;		//默认轴距 2700mm

	float 									m_catcher_1th_floor_z;			//机器手在1楼的z周高度, 1
	float 									m_catcher_2th_floor_z;			//机器手在2楼的z周高度, 2620
	float 									m_catcher_3th_floor_z;			//机器手在3楼的z周高度, 5220
	float 									m_catcher_4th_floor_z;			//机器手在4楼的z周高度, 5410

	float 									m_carrier_1th_floor_z;			//搬运器在1楼的z周高度, 1
	float 									m_carrier_2th_floor_z;			//搬运器在2楼的z周高度, 2525
	float 									m_carrier_3th_floor_z;			//搬运器在3楼的z周高度, 5125
	float 									m_carrier_4th_floor_z;			//搬运器在4楼的z周高度, 7725

	float									m_catcher_d1_d2_distance;		//机器手2D1-2D2零位间距1903mm
	float									m_catcher_wheel_base_limit;		//机器手下降过程中的轮距限制 3000mm

	float									m_carrier_y_y1_distance;		//小跑车 y-y1的间距1500mm
	float									m_carrier_default_y1_back;		//小跑车的默认y1, 回到中跑车 4500mm
	float									m_carrier_default_y1_leave;		//小跑车的默认y1, 离开中跑车 10500mm
	float									m_carrier_default_y_back;		//小跑车的默认y, 回到中跑车 3000mm
	float									m_carrier_default_y_leave;		//小跑车的默认y, 离开中跑车 9000mm

	float									m_carrier_default_x_left;		//中跑车的默认x, 左侧电梯井 1mm
	float									m_carrier_default_x_right;		//中跑车的默认x, 左侧电梯井 32600mm

	int										m_passageway_terminal_id_min;		//通道口终端id最小值, 默认0
	int										m_passageway_terminal_id_max;		//通道口终端id最大值, 默认7
	int										m_passageway_terminal_number;		//通道口终端个数, 默认8
	std::map<int, Passageway_functioning_pattern>	m_passageway_functioning_pattern_map;//出入口的功能模式

	int										m_parkspace_id_min;					//车位id最小值, 默认1
	int										m_parkspace_id_max;					//车位id最小值, 默认165
	int										m_parkspace_id_total;				//车位id总数, 默认165

	int										m_third_floor_parkspace_id_min;		//3楼车位id最小值, 默认19
	int										m_third_floor_parkspace_id_max;		//3楼车位id最小值, 默认27
	int										m_third_floor_parkspace_id_total;	//3楼车位id总数, 默认9

	int										m_car_wheel_base_min;			//汽车轮距最小值, 默认1000
	int										m_car_wheel_base_max;			//汽车轮距最大值, 默认4000

	float 									m_separated_distance_z;		//机器人和搬运器分离时的z轴距离, 默认190
	float 									m_separated_distance_x;		//机器人和搬运器分离时的x轴距离, 默认3600
private:

};


#endif //NNXX_TESTS_DISPATCH_COORDINATES_H
