
//Error_code是错误码的底层通用模块，
//功能：用作故障分析和处理。

//用法：所有的功能接口函数return错误管理类，
//然后上层判断分析错误码，并进行故障处理。



#ifndef TEST_ERROR_ERROR_CODE_H
#define TEST_ERROR_ERROR_CODE_H

#include <string>
#include <string.h>

//错误管理类转化为字符串 的前缀，固定长度为58
//这个是由显示格式来确定的，如果要修改格式或者 Error_code长度超过8位，Error_level长度超过2位，折需要重新计算
#define ERROR_NAMAGER_TO_STRING_FRONT_LENGTH   58

//进程加锁的状态，
enum Lock_status
{
    UNLOCK      = 0,
    LOCK        = 1,
};

//设备使能状态，
enum Able_status
{
    UNABLE      = 0,
    ENABLE      = 1,
};

//数据是否为空
enum Empty_status
{
    NON_EMPTY   = 0,
    EMPTY       = 1,
};


//错误码的枚举，用来做故障分析
enum Error_code
{
    //成功，没有错误，默认值0
    SUCCESS                         = 0x00000000,


    //基本错误码，
    ERROR                           = 0x00000001,//错误
    PARTIAL_SUCCESS                 = 0x00000002,//部分成功
    WARNING                         = 0x00000003,//警告
    FAILED                          = 0x00000004,//失败

    NODATA                          = 0x00000010,//没有数据，传入参数容器内部没有数据时，

    POINTER_IS_NULL                 = 0x00000101,//空指针
    PARAMETER_ERROR                 = 0x00000102,//参数错误，传入参数不符合规范时，
    POINTER_MALLOC_FAIL             = 0x00000103,//手动分配内存失败

    CLASS_BASE_FUNCTION_CANNOT_USE  = 0x00000201,//基类函数不允许使用，必须使用子类的


//    错误码的规范，
//    错误码是int型，32位，十六进制。
//    例如0x12345678
//    12表示功能模块，例如:laser雷达模块               框架制定
//    34表示文件名称，例如:laser_livox.cpp             框架制定
//    56表示具体的类，例如:class laser_livox           个人制定
//    78表示类的函数，例如:laser_livox::start();       个人制定
//    注：错误码的制定从1开始，不要从0开始，
//        0用作错误码的基数，用来位运算，来判断错误码的范围。

//    laser扫描模块
    LASER_ERROR_BASE                = 0x01000000,

//    laser_base基类
	LASER_BASE_ERROR_BASE			= 0x01010000,
    LASER_TASK_PARAMETER_ERROR      = 0x01010001,   //雷达任务输入参数错误
    LASER_CONNECT_FAILED,
	LASER_START_FAILED,
	LASER_CHECK_FAILED				,
	LASER_STATUS_ERROR,								//雷达状态错误


    LASER_LIVOX_SKD_INIT_FAILED,


//    laser_livox.cpp的错误码
    LIVOX_ERROR_BASE                = 0x01020000,
    LIVOX_START_FAILE               = 0x01020101,
	LIVOX_TASK_TYPE_ERROR,							//livox任务类型错误


     //PLC error code  ...
    PLC_ERROR_BASE                  = 0x02010000,
    PLC_UNKNOWN_ERROR,
    PLC_EMPTY_TASK,
    PLC_IP_PORT_ERROR,
    PLC_SLAVE_ID_ERROR,
    PLC_CONNECTION_FAILED,
    PLC_READ_FAILED,
    PLC_WRITE_FAILED,
    PLC_NOT_ENOUGH_DATA_ERROR,

    //Locater.cpp error from 0x0301000-0x030100FF
        LOCATER_TASK_INIT_CLOUD_EMPTY=0x03010000,
    LOCATER_TASK_ERROR,
    LOCATER_TASK_INPUT_CLOUD_UNINIT,
    LOCATER_INPUT_CLOUD_EMPTY,
    LOCATER_YOLO_UNINIT,
    LOCATER_POINTSIFT_UNINIT,
    LOCATER_3DCNN_UNINIT,
    LOCATER_INPUT_YOLO_CLOUD_EMPTY,
    LOCATER_Y_OUT_RANGE_BY_PLC,
    LOCATER_MEASURE_HEIGHT_CLOUD_UNINIT,
    LOCATER_MEASURE_HEIGHT_CLOUD_EMPTY,
    LOCATER_INPUT_CLOUD_UNINIT,


    //point sift from 0x03010100-0x030101FF
        LOCATER_SIFT_INIT_FAILED=0x03010100,
    LOCATER_SIFT_INPUT_CLOUD_UNINIT,
    LOCATER_SIFT_PREDICT_FAILED,
    LOCATER_SIFT_CREATE_INPUT_DATA_FAILED,
    LOCATER_SIFT_FILTE_OBS_FAILED,
    LOCATER_SIFT_INPUT_BOX_PARAMETER_FAILED,
    LOCATER_SIFT_INPUT_CLOUD_EMPTY,
    LOCATER_SIFT_PREDICT_NO_CAR_POINT,

    //yolo from 0x03010200-0x030102FF
        LOCATER_YOLO_DETECT_FAILED=0x03010200,
    LOCATER_YOLO_DETECT_NO_TARGET,
    LOCATER_YOLO_PARAMETER_INVALID,
    LOCATER_YOLO_INPUT_CLOUD_UNINIT,

    //3dcnn from 0x03010300-0x030103FF
    LOCATER_3DCNN_INIT_FAILED=0x03010300,
    LOCATER_3DCNN_INPUT_CLOUD_UNINIT,
    LOCATER_3DCNN_PREDICT_FAILED,
    LOCATER_3DCNN_VERIFY_RECT_FAILED_3,
    LOCATER_3DCNN_VERIFY_RECT_FAILED_4,
    LOCATER_3DCNN_KMEANS_FAILED,
    LOCATER_3DCNN_IIU_FAILED,
    LOCATER_3DCNN_INPUT_CLOUD_EMPTY,
    LOCATER_3DCNN_PCA_OUT_CLOUD_EMPTY,

    //System_manager error from 0x04010000-0x0401FFFF
    SYSTEM_READ_PARAMETER_ERROR=0x04010100,
    SYSTEM_PARAMETER_ERROR,
    SYSTEM_INPUT_TERMINOR_NO_LASERS,

    //terminor_command_executor.cpp from 0x04010200-0x040102FF
    TERMINOR_NOT_READY=0x04010200,
    TERMINOR_INPUT_LASER_NULL,
    TERMINOR_NOT_CONTAINS_LASER,
    TERMINOR_INPUT_PLC_NULL,
    TERMINOR_INPUT_LOCATER_NULL,
    TERMINOR_CREATE_WORKING_THREAD_FAILED,
    TERMINOR_FORCE_QUIT,
    TERMINOR_LASER_TIMEOUT,
    TERMINOR_POST_PLC_TIMEOUT,
    TERMINOR_CHECK_RESULTS_ERROR,

    ////Hardware limit from 0x05010000 - 0x0501ffff
    ///railing.cpp from 0x05010100-0x050101ff
    HARDWARE_LIMIT_LEFT_RAILING=0x05010100,         //左栏杆限制
    HARDWARE_LIMIT_RAILING_PARAMETER_ERROR,
    HARDWARE_LIMIT_RAILING_ERROR,
    HARDWARE_LIMIT_CENTER_X_LEFT,
    HARDWARE_LIMIT_CENTER_X_RIGHT,
    HARDWARE_LIMIT_CENTER_Y_TOP,
    HARDWARE_LIMIT_CENTER_Y_BOTTOM,
    HARDWARE_LIMIT_HEIGHT_OUT_RANGE,
    HARDWARE_LIMIT_ANGLE_OUT_RANGE,
    //termonal_limit from 0x05010200-0x050102ff
    HARDWARE_LIMIT_TERMINAL_LEFT_ERROR,
    HARDWARE_LIMIT_TERMINAL_RIGHT_ERROR,
    HARDWARE_LIMIT_TERMINAL_LR_ERROR,


    //wj_lidar error from 0x06010000-0x0601FFFF
        WJ_LIDAR_CONNECT_FAILED=0x06010000,
    WJ_LIDAR_UNINITIALIZED,
    WJ_LIDAR_READ_FAILED,
    WJ_LIDAR_WRITE_FAILED,
    WJ_LIDAR_GET_CLOUD_TIMEOUT,

    //wj lidar protocol error from 0x06020000-0x0602FFFF
        WJ_PROTOCOL_ERROR_BASE=0x06020000,
    WJ_PROTOCOL_INTEGRITY_ERROR,
    WJ_PROTOCOL_PARSE_FAILED,
    WJ_PROTOCOL_EMPTY_PACKAGE,
    WJ_PROTOCOL_EXCEED_MAX_SIZE,

    //wj region detect error from 0x06030000-0x0603FFFF
        WJ_REGION_EMPTY_CLOUD=0x06030000,
    WJ_REGION_RECTANGLE_ANGLE_ERROR,
    WJ_REGION_RECTANGLE_SIZE_ERROR,
    WJ_REGION_RECTANGLE_SYMMETRY_ERROR,
    WJ_REGION_CLUSTER_SIZE_ERROR,

    //wj manager error from 0x06040000-0x0604FFFF
    WJ_MANAGER_UNINITIALIZED=0x06040000,
    WJ_MANAGER_LIDAR_DISCONNECTED,
    WJ_MANAGER_PLC_DISCONNECTED,
    WJ_MANAGER_EMPTY_CLOUD,

    WJ_LIDAR_TASK_EMPTY_RESULT=0x06050000,
    WJ_LIDAR_TASK_EMPTY_TASK,
    WJ_LIDAR_TASK_WRONG_TYPE,
    WJ_LIDAR_TASK_INVALID_TASK,
    WJ_LIDAR_TASK_MEASURE_FAILED,

    //cifx error from 0x07010000-0x0701FFFF
    CIFX_DRIVER_INIT_ERROR=0x07010000,
    CIFX_DRIVER_OPEN_ERROR,
    CIFX_CHANNEL_OPEN_ERROR,
    CIFX_BUS_OPEN_ERROR,
    CIFX_READ_FAILED,
    CIFX_READ_TIMEOUT,
    CIFX_WRITE_FAILED,
    CIFX_WRITE_TIMEOUT,

    //odom error from 0x07020000-0x0702FFFF
    
};

//错误等级，用来做故障处理
enum Error_level
{
//    正常，没有错误，默认值0
    NORMAL                = 0,


//    可忽略的故障，NEGLIGIBLE_ERROR
//    提示作用，不做任何处理，不影响代码的流程，
//    用作一些不重要的事件，一半出错也不会影响到系统功能，
//    例如：文件保存错误，等
    NEGLIGIBLE_ERROR      = 1,


//    一般故障，MINOR_ERROR
//    用作底层功能函数的错误返回，表示该功能函数执行失败，
//    返回给应用层之后，需要做故障分析和处理，
//    例如：雷达数据传输失败，应用层进行重新扫描，或者重连，或者重置参数等。
    MINOR_ERROR           = 2,


//    严重故障，MAJOR_ERROR
//    用作应用层的任务事件的结果，表示该功能模块失败。
//    通常是底层函数返回一般故障之后，应用层无法处理并解决故障，此时就要进行故障升级，
//    从一般故障升级为严重故障，然后进行回退流程，回退已经执行的操作，最终回到故障待机状态。
//    需要外部清除故障，并复位至正常待机状态，才能恢复功能的使用。
//    例如：雷达扫描任务失败，且无法自动恢复。
    MAJOR_ERROR           = 3,


//    致命故障，CRITICAL_ERROR
//    系统出现致命错误。导致系统无法正常运行，
//    此时系统应该紧急停机，执行紧急流程，快速停机。
//    此时不允许再执行任何函数和任务指令，防止系统故障更加严重。
//    也不需要做任何错误处理了，快速执行紧急流程。
//    例如：内存错误，进程挂死，关键设备失控，监控设备报警，等
    CRITICAL_ERROR        = 4,
};


class Error_manager
{
public://外部接口函数
    //构造函数
    Error_manager();
    //拷贝构造
    Error_manager(const Error_manager & error_manager);
    //赋值构造
    Error_manager(Error_code error_code, Error_level error_level = NORMAL,
                  const char* p_error_description = NULL, int description_length = 0);
    //赋值构造
    Error_manager(Error_code error_code, Error_level error_level , std::string & error_aggregate_string);
    //析构函数
    ~Error_manager();

    //初始化
    void error_manager_init();
    //初始化
    void error_manager_init(Error_code error_code, Error_level error_level = NORMAL,
                            const char* p_error_description = NULL, int description_length = 0);
    //初始化
    void error_manager_init(Error_code error_code, Error_level error_level , std::string & error_aggregate_string);
    //重置
    void error_manager_reset(Error_code error_code, Error_level error_level = NORMAL,
                             const char* p_error_description = NULL, int description_length = 0);
    //重置
    void error_manager_reset(Error_code error_code, Error_level error_level , std::string & error_aggregate_string);
    //重置
    void error_manager_reset(const Error_manager & error_manager);
    //清除所有内容
    void error_manager_clear_all();

    //重载=
    Error_manager& operator=(const Error_manager & error_manager);
    //重载=，支持Error_manager和Error_code的直接转化，会清空错误等级和描述
    Error_manager& operator=(Error_code error_code);
    //重载==
    bool operator==(const Error_manager & error_manager);
    //重载==，支持Error_manager和Error_code的直接比较
    bool operator==(Error_code error_code);
    //重载!=
    bool operator!=(const Error_manager & error_manager);
    //重载!=，支持Error_manager和Error_code的直接比较
    bool operator!=(Error_code error_code);


    //获取错误码
    Error_code get_error_code();
    //获取错误等级
    Error_level get_error_level();
    //获取错误描述的指针，（浅拷贝）
    char* get_error_description();

    //复制错误描述，（深拷贝）
    //output：p_error_description     错误描述的字符串指针，不可以为NULL，必须要有实际的内存
    //output:description_length      错误描述的字符串长度，不可以为0，长度最好足够大，一般256即可。
    void copy_error_description(const char* p_error_description, int description_length);
    //复制错误描述，（深拷贝）
    //output：error_description_string     错误描述的string
    void copy_error_description(std::string & error_description_string);

    //设置错误码
    void set_error_code(Error_code error_code);
    //比较错误等级并升级，取高等级的结果
    void set_error_level_up(Error_level error_level);
    //比较错误等级并降级，取低等级的结果
    void set_error_level_down(Error_level error_level);
    //错误等级，设定到固定值
    void set_error_level_location(Error_level error_level);
    //设置错误描述
    void set_error_description(const char* p_error_description, int description_length = 0);
    //设置错误描述
    void set_error_description(std::string & error_description_string);

    //尾部追加错误描述
    void add_error_description(const char* p_error_description, int description_length = 0);
    //尾部追加错误描述
    void add_error_description(std::string & error_description_string);

    //比较错误是否相同，
    // 注：只比较错误码和等级
	bool is_equal_error_manager(const Error_manager & error_manager);
	//比较并覆盖错误，讲低级错误转为字符串存放于描述中，
	//如果错误相同，则保留this的，将输入参数转入描述。
	void compare_and_cover_error(const Error_manager & error_manager);
	//比较并覆盖错误，讲低级错误转为字符串存放于描述中，
	//如果错误相同，则保留this的，将输入参数转入描述。
	void compare_and_cover_error( Error_manager * p_error_manager);

	//将所有的错误信息，格式化为字符串，用作日志打印。
    //output：p_error_description     错误汇总的字符串指针，不可以为NULL，必须要有实际的内存
    //output:description_length      错误汇总的字符串长度，不可以为0，长度最好足够大，一般256即可。
    void translate_error_to_string(char* p_error_aggregate, int aggregate_length);
    //output：error_description_string     错误汇总的string
    void translate_error_to_string(std::string & error_aggregate_string);
    //错误码转字符串的简易版，可支持cout<<
    //return     错误汇总的string
    std::string to_string();



protected:
    Error_code              m_error_code;               //错误码
    Error_level             m_error_level;              //错误等级
    char*                   pm_error_description;       //错误描述
    int                     m_description_length;       //错误描述的字符长度

protected://内部功能函数
public:
    //释放错误描述的内存，
    void free_description();

    //重新分配错误描述的内存，并从外部拷贝新的（深拷贝）
    //input：p_error_description     错误描述的字符串指针，可以为NULL，
    //input:description_length      错误描述的字符串长度，如果为0，则从p_error_description里面获取有效的长度
    void reallocate_memory_and_copy_string(const char* p_error_description, int description_length = 0);

    //重新分配错误描述的内存，并从外部拷贝新的（深拷贝）
    //input：error_aggregate_string     错误描述的string
    void reallocate_memory_and_copy_string(std::string & error_aggregate_string);
};




#endif //TEST_ERROR_ERROR_CODE_H


