#ifndef APP_COMMON_H
#define APP_COMMON_H

#include <stdio.h>
#include <stdarg.h>
#include <sys/time.h>
#include <string.h>
#include <vector>
#include <memory>

#include "CommonDataType/CommonDataType.h"
//#include "DvppCommon/DvppCommon.h"


#include <iostream>
#include <fstream>
#include <sstream>
#include <assert.h>
#include <vector>
#include <numeric>
#include <algorithm>
#include <math.h>
#include <ctime>
#include <math.h>
#include <chrono>
#include <cmath>
#include <functional>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include <NvInfer.h>
#include "logging.h"
#include <NvInferPlugin.h>
#include <NvOnnxParser.h>
#include <NvCaffeParser.h>

#include <cuda.h>
#include <cuda_runtime.h>
#include <cuda_runtime_api.h>

#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include "preprocess.h"


#ifdef ASCEND
#include "DvppCommon.h"
#else
#include "nvidia_acl_datatype.h"

#include "cuda_utils.h"
#include "logging.h"
#include "yolov5_common.h"
#include "utils.h"
#include "calibrator.h"
#include "preprocess.h"
#include "yololayer.h"

using namespace Yolo;
#endif


using namespace std;
using namespace cv;
using namespace nvinfer1;
using namespace nvcaffeparser1;

#define USE_FP16  // set USE_INT8 or USE_FP16 or USE_FP32
#define DEVICE 0  // GPU id
#define BATCH_SIZE 1    //batch size
#define MAX_WORKSPAXE_SIZE (16 * (1 << 20)) //工作空间大小
#define MAX_IMAGE_INPUT_SIZE_THRESH 3000*3000
#define INPUT_CHANNEL 3     //输入通道数

//NVIDIA NX YOLOV5模型推理相关宏(因不与ASCEND冲突放到这)
#define NMS_THRESH 0.4
#define CONF_THRESH 0.5


#define GET_INPUT_SIZE(w, h) (INPUT_CHANNEL * w *h)
#define GET_OUTPUT_SIZE(w, h, cr , ca) (INPUT_CHANNEL * (((h / 32) * ( h / 32)) + ((h / 16) * ( h / 16)) + ((h / 8) * ( h / 8))) * (STEP1_POS_CONF + cr + ca))

//STEP0
#define STEP0_MAX_IMAGE_INPUT_SIZE_THRESH 3000*3000

#define STEP0_BATCH_SIZE 1    //batch size
#define STEP0_NMS_THRESH 0.5     //step1 非极大值抑制阈值
#define STEP0_SCORE_THRESH 0.4   //step1 置信度(得分)阈值
#define STEP0_INPUT_CHANNEL 3     //输入通道数

#define STEP0_INPUT_H  640        //step0 输入图像高
#define STEP0_INPUT_W  640       //step0 输入图像宽

//STEP1
#define STEP1_POS_CONF 5

#define STEP1_NMS_THRESH 0.5     //step1 非极大值抑制阈值 
#define STEP1_SCORE_THRESH 0.4   //step1 置信度(得分)阈值

#define STEP1_CLASS_NUM 19    //step1 7分类
#define STEP1_CLEAR_NUM 21     //step1 21个清晰度

#define STEP1_INPUT_H  960        //step1 输入图像高
#define STEP1_INPUT_W  960       //step1 输入图像宽
#define STEP1_BATCH_SIZE 1
#define STEP1_OUTPUT_HISTOGRAM_N 5    //不能超过139167

#define STEP1_BBOX_SIZE1  (STEP1_INPUT_H/32)
#define STEP1_BBOX_SIZE2  (STEP1_INPUT_H/16)
#define STEP1_BBOX_SIZE3  (STEP1_INPUT_H/8)

#define STEP1_INPUT_SIZE    INPUT_CHANNEL*STEP1_INPUT_H*STEP1_INPUT_W      //input
#define STEP1_OUTPUT_SIZE   INPUT_CHANNEL*(STEP1_BBOX_SIZE1*STEP1_BBOX_SIZE1+STEP1_BBOX_SIZE2*STEP1_BBOX_SIZE2+STEP1_BBOX_SIZE3*STEP1_BBOX_SIZE3)*(STEP1_CLEAR_NUM+STEP1_CLASS_NUM+STEP1_POS_CONF)       //output

//STEP1
#define STEP1_CLASS_NUM_DATE 8
#define STEP1_CLASS_NUM_CON 7

//STEP2
#define STEP2_POS_CONF 5

#define STEP2_NMS_THRESH 0.5      //step2 非极大值抑制阈值
#define STEP2_SCORE_THRESH 0.4    //step2 置信度(得分)阈值

#define STEP2_CLASS_NUM 47    //step2 31分类
#define STEP2_CLEAR_NUM 5     //step2 5个清晰度

#define STEP2_INPUT_H  608        //step2 输入图像高
#define STEP2_INPUT_W  608       //step2 输入图像宽
#define STEP2_BATCH_SIZE 1
#define STEP2_OUTPUT_HISTOGRAM_N 5    //step2 不能超过22743

#define STEP2_BBOX_SIZE1  (STEP2_INPUT_H/32)
#define STEP2_BBOX_SIZE2  (STEP2_INPUT_H/16)
#define STEP2_BBOX_SIZE3  (STEP2_INPUT_H/8)

#define STEP2_INPUT_SIZE    INPUT_CHANNEL*STEP2_INPUT_H*STEP2_INPUT_W      //input
#define STEP2_OUTPUT_SIZE   INPUT_CHANNEL*(STEP2_BBOX_SIZE1*STEP2_BBOX_SIZE1+STEP2_BBOX_SIZE2*STEP2_BBOX_SIZE2+STEP2_BBOX_SIZE3*STEP2_BBOX_SIZE3)*(STEP2_CLEAR_NUM+STEP2_CLASS_NUM+STEP2_POS_CONF)       //output


#define CONVERT_TO_ODD(NUM) (NUM)  // Convert the input to odd num
#define CONVERT_TO_EVEN(NUM) (NUM) // Convert the input to even num
#define CHECK_ODD(num) (NUM)
#define CHECK_EVEN(num) (NUM)

//模型参数
typedef struct _YoloV5ModelParam{
    unsigned int uiClassNum;
    unsigned int uiDetSize;
    float fScoreThreshold;
    float fNmsThreshold;
}YoloV5ModelParam;

typedef struct _YoloV5ClearityModelParam{
    unsigned int uiClassNum;
    unsigned int uiClearNum;
    unsigned int uiDetSize;
    float fScoreThreshold;
    float fNmsThreshold;
}YoloV5ClearityModelParam;

typedef struct _ModelCommonInfo{
    unsigned int uiModelWidth;
    unsigned int uiModelHeight;
    unsigned int uiInputSize;
    unsigned int uiOutputSize;
    unsigned int uiChannel;
    unsigned int uiBatchSize;
    std::string strInputBlobName;
    std::string strOutputBlobName;
}ModelCommonInfo;

typedef struct _YoloV5ModelInfo{
    YoloV5ModelParam yolov5ModelParam;
    ModelCommonInfo modelCommonInfo;
}YoloV5ModelInfo;

typedef struct _YoloV5ClearityModelInfo{
    YoloV5ClearityModelParam yolov5ClearityModelParam;
    ModelCommonInfo modelCommonInfo;
}YoloV5ClearityModelInfo;

struct ModelConfig
{
    std::string strAnchorPath;  //锚框文件路径
    std::string strClassPath;   //类别名称集合
    std::string strOmPath;      //om文件路径
    int iModelWidth;            //模型输入宽度
    int iModelHeight;           //模型输入高度
    float fScoreThreshold;      //得分阈值
    float fNMSTreshold;         //nms阈值
    int iClassNum;              //类别个数
    int iLineNum;               //字段代号
};

typedef struct
{
    float fLTX = 0; //左上X坐标
    float fLTY = 0; //左上y坐标
    float fRBX = 0; //右下y坐标
    float fRBY = 0; //右下y坐标
}Location;

//耗时宏
// #define CUDA_MALLOC_TIME_CONSUMING_TEST         //CUDA内存分配耗时
// #define CUDA_MEMCPY_TIME_CONSUMING_TEST         //CUDA内存拷贝耗时
#define INFERENCE_MODEL_TIME_CONSUMING_TEST     //模型推理耗时
// #define OPENCV_CVTCOLOR_YUV2RGB_TIME_CONSUMING_TEST //OpenCV YUV2RGB耗时
// #define OPENCV_CVTCOLOR_RGB2YUV_TIME_CONSUMING_TEST //OpenCV RGB2YUV耗时
// #define OPENCV_CVTCOLOR_BGR2RGB_TIME_CONSUMING_TEST //OpenCV BGR2RGB耗时

#define ENCODE_H264_STREAM  //编码H264
#define PACKAGE_VIDEO_STREAM  //封装视频(MP4,FLV)
#define RTSP_PUSH_VIDEO_STREAM  //RTSP推流(推送H264)

#define IMAGE_WIDTH 1920 //1920 2560
#define IMAGE_HEIGHT 1080 //1080 1440

//////////基础画像////////////////////////////////////
//来车检测功能ID 包含:来车,行车方向,停车,停车启动 
#define METHOD_BASE_WIDTH 1280
//车厢划分功能ID///////////////////////////////////////
#define METHOD_BASE_HEIGHT 720
//相机帧率////////////////////////////////////////////
#define FRAME_RATE 25


//////////功能ID///////////////////////////////////////
//来车检测功能ID 包含:来车,行车方向,停车,停车启动 
#define TRAIN_ACTION 1
//车厢划分功能ID///////////////////////////////////////
#define TRAIN_PARTION 2

#define DIRECTION 0

//////////算法配置//////////
//算法参数数量
#define IMAGEANALYSE_NUM 17
//图像优化处理
#define IMAGE_GRAY		0x00000001                  //灰度处理
#define IMAGE_EQUALIZE		0x00000002              //直方图均衡化处理
#define IMAGE_GAMMA		0x00000004                  //gamma变化
#define IMAGE_SPEC		0x00000008                  //自定义处理
//图像对比标准
#define IMAGE_COMP_BY_TEMPLE	0x00000001          //物体形状
#define IMAGE_COMP_BY_HIST	0x00000002              //图像直方图
#define IMAGE_COMP_BY_SPEC	0x00000004              //

//////////车厢状态////////////////////////////////////
#define TRAIN_INIT_STATUS	0x01                    //无车
#define TRAIN_LEFT_RUN      0x02                    //左侧来车
#define TRAIN_RIGHT_RUN     0x03                    //右侧来车
#define TRAIN_UNKOWN_RUN    0x04                    //来车(无法确认方向)
#define TRAIN_PAUSE         0x05                    //停车
#define TRAIN_RESTART       0x06                    //列车重新启动
#define TRAIN_PASSED        0x07                    //列车完全通过
#define TRAIN_WAIT_INIT     0x08                    //列车完全通过等待重新初始化
//////////标准值(估算)////////////////////////////////////
//车厢长度
#define TRAIN_WIDTH		14.5
//车钩在画面正中央时单个车厢所在图像中的长度
#define TRAIN_IN_CAMERA_WIDTH	10
//初始速度
#define TRAIN_DEFAULT_SPEED     (((TRAIN_WIDTH) / 5.0))

enum cmd_enum : unsigned char
{
    //开始识别
    //value[0]代表识别最大次数，识别不出来就返回"fail"
    cmd_start_recognize = 0x01,
    cmd_end_recognize = 0x02,
};

//识别目标
enum Target
{
    NUM = 0,        // 编号 (包含 2:煤炭漏斗车(兖矿自备,枣矿自备); 3:敞车; 4:棚车; 5:罐车; 6:平车; 8:牲畜车; 15:毒品车)
    PRO = 1,        // 属性
    HEAD = 2,       // 车头
    CHKDATE = 3,    // 定检期
    CONTAINER = 4,  // 集装箱
    SPACE = 5,      // 连接轴间隔 (包含 18:连接轴通用间隔)
    TRAINSPACE = 6, // 车厢间隔 (包含 9:敞车间隔; 10:自备车间隔; 11:平车间隔; 12:罐车间隔; 13:棚车车间隔; 14:牲畜车间隔; 16: 毒品车间隔; 17:混合车厢间隔;)
    TOPSPACE = 7    // 顶部间隔
};

//编号在前 或 属性在前
enum FirstTarget
{
    AUTO_FIRST = 0,     //自动判断
    NUM_FIRST = 1,      //编号在前
    PRO_FIRST = 2       //属性在前
};

//行驶方向
enum RunDirection
{
    DIRECTION_UNKNOWN = 0, //未知
    DIRECTION_LEFT = 1,    //向左行驶
    DIRECTION_RIGHT = 2    //向右行驶
};

//车辆状态
enum TrainStatus
{
    TRAINSTATUS_NO = 0,     //无车
    TRAINSTATUS_RUN = 1,    //行驶
    TRAINSTATUS_STOP = 2,   //停止
    TRAINSTATUS_BACK = 3    //倒车
};

enum RunDirectionAndFirst
{
    // -1-不知道行驶方向和哪个框在前
    DO_NOT_KNOW_DIRECTION = -1,
    // 0-向左行驶，编号在前 
    LEFT_RUN_AND_NUM_FIRST = 0,
    // 1-向左行驶，属性在前 
    LEFT_RUN_AND_PRO_FIRST = 1,
    // 2-向右行驶，编号在前 
    RIGHT_RUN_AND_NUM_FIRST = 2,
    // 3-向右行驶，属性在前
    RIGHT_RUN_AND_PRO_FIRST = 3
};

//模型识别种类
enum ModelTarget
{
    //车头上的编号
    TRAIN_HEAD = 0,
    //属性
    TRAIN_PRO = 1,
    //编号 矿车、煤炭漏斗车（兖矿自备、枣矿自备）
    K_TRAIN_NUM = 2,
    //编号 敞车
    C_TRAIN_NUM = 3,
    //编号 棚车
    P_TRAIN_NUM = 4,
    //编号 罐车
    G_TRAIN_NUM = 5,
    //编号 平车
    NX_TRAIN_NUM = 6,
    //定检期
    TRAIN_CHECK = 7,
    //编号 牲畜车
    J_TRAIN_NUM = 8,
    //车厢间隔 敞车
    C_TRAIN_SPACE = 9,
    //车厢间隔 矿车、煤炭漏斗车（兖矿自备、枣矿自备）
    K_TRAIN_SPACE = 10,
    //车厢间隔 平车
    NX_TRAIN_SPACE = 11,
    //车厢间隔 罐车
    G_TRAIN_SPACE = 12,
    //车厢间隔 棚车
    P_TRAIN_SPACE = 13,
    //车厢间隔 牲畜车
    J_TRAIN_SPACE = 14,
    //毒品车
    W_TRAIN_NUM = 15,
    //毒品车间隔
    W_TRAIN_SPACE = 16,
    //混合车厢间隔
    M_TRAIN_SPACE = 17,
    //连接轴通用间隔
    U_TRAIN_SPACE = 18
};

//识别区域
enum IdentifyAreas
{
    //不在识别区
    NO_THING = -1,
    //非平车识别区
    NOT_FLATCAR = 0,
    //平车识别区
    FLATCAR = 1
};

//选优模式
enum SelectBestMode
{
    FREQUENCY = 0,  //频率优先
    LENGTH          //长度优先
};

enum TargetMaxLen
{
    TYPE_MAXLEN = 7,           //车型
    NUM_MAXLEN = 7,            //编号
    LOAD_MAXLEN = 3,           //载重 （KM98车型载重为100）
    SELF_MAXLEN = 3,           //自重
    VOLUME_MAXLEN = 3,         //容积
    CHANGE_MAXLEN = 2,         //换长
    VOLUMESURFACE_MAXLEN = 7,  //罐车容量记表
    CHKDATE_MAXLEN = 8         //定检期
};

enum ModelType
{
    MODELTYPE_NUM = 1,          //车号模型
    MODELTYPE_CHKDATE = 2,      //定检期模型
    MODELTYPE_CONTAINER = 3     //集装箱模型
};

enum ValidType
{
    VALID_ALL = 0,          //画面信息全部有效
    VALID_LEFT = 1,         //画面间隔左边有效
    VALID_RIGHT = 2         //画面间隔右边有效
};

//来车检测模型结果
enum MonitorModelState
{
    //初始化状态
    MONITOR_MODEL_INIT_STATE = -1,
    //车头部分
    MONITOR_MODEL_TRAIN_HEAD = 0,
    //无车
    MONITOR_MODEL_NO_TRAIN = 1,
    //车尾部分
    MONITOR_MODEL_TRAIN_TAIL = 2,
    //车体部分
    MONITOR_MODEL_TRAIN_BODY = 3
};

//帧基本信息
typedef struct
{
    uint32_t iWidth = 0;
    uint32_t iHeight = 0;
    acldvppStreamFormat format;
    int iRate = 0;  //帧率
} FrameInfo;

//原图上大框坐标(第二步还原坐标时用)
typedef struct
{
    float fLTX = 0; //左上X坐标
    float fLTY = 0; //左上y坐标
    float fRBX = 0; //右下y坐标
    float fRBY = 0; //右下y坐标
}Step1Location;

//推理数据(NVIDIA)
typedef struct
{
    int iDataSource = 0;                //数据来源标识
    uint32_t iFrameId = 0;
    FrameInfo frameInfo;
    uint32_t iSize = 0;                 // Size of memory, bytes
    uint32_t iSrcSize = 0;                 // Size of memory, bytes
    std::shared_ptr<void> pData;        // Smart pointer of data
    std::shared_ptr<void> pSrcData;     // Smart pointer of data(源数据) 推理时,RGB数据会拷贝一份,源数据不变用于传送到后处理引擎画框,另一份数据用于resize成640x640并归一化到0-1
    uint64_t i64TimeStamp = 0;          //帧数据时间戳
    Step1Location step1Location;        //step2 use
    int iTargetType;                        //目标类别 (0:车号; 1:属性; 2:车头; 3:定检期; 4:集装箱)
    int iBigClassId = -1;                   //大框id (给第二步用 1-属性 23456-编号)
    int iCarXH = 0;                         //当前大框所属车厢

} InferenceData;


//帧数据
typedef struct
{
    int iDataSource = 0; //数据来源标识
    uint32_t iFrameId = 0;
    FrameInfo frameInfo;
    uint32_t iSize = 0;          // Size of memory, bytes
    std::shared_ptr<void> pData; // Smart pointer of data
    uint64_t i64TimeStamp = 0;   //帧数据时间戳
} FrameData;

//帧解码后数据
typedef struct
{
    int iDataSource = 0;                                            //数据来源标识
    uint32_t iFrameId = 0;
    uint32_t iWidth = 0;                                            // Width of image
    uint32_t iHeight = 0;                                           // Height of image
    uint32_t iWidthStride = 0;                                      // Width after align up
    uint32_t iHeightStride = 0;                                     // Height after align up
    acldvppPixelFormat format = PIXEL_FORMAT_YUV_SEMIPLANAR_420;    // Format of image
    uint32_t iSize = 0;                                             // Size of data in byte
    std::shared_ptr<void> pData = nullptr;                          // Smart pointer of data
    uint64_t i64TimeStamp = 0;                                      //帧数据时间戳
    bool bHostMemory = false;                                       //数据解码后内存是否在Host侧
    std::string strPicFilePath;
    std::string strTrainDate;   //过车日期    (格式：YYYY-MM-DD)
    std::string strTrainName;   //车次        (格式：HH-MM-SS)
    bool bIsEnd = false;        //列车结束标识
    int iStatus = 0;            //0-无车; 1-有车行驶; 2-有车停止
    int iDirection = 0;         //行驶方向(0-未知; 1-向左; 2-向右)
    int iRate = 0;              //帧率
} DecodedData;

//存图数据
typedef struct
{
    uint32_t iFrameId = 0;
    uint32_t iWidth = 0;        //Width of image
    uint32_t iHeight = 0;       //Height of image

    std::string strImgPath;
    std::string strImgName;
    uint32_t iSize = 0;                     // Size of memory, bytes
    std::shared_ptr<void> pData = nullptr;  // Smart pointer of data
    bool bIsEnd = false;                    //列车结束标识
    bool bSaveToFtp = false;                //是否保存至ftp服务器
    uint64_t i64TimeStamp = 0;              //帧数据时间戳
    std::shared_ptr<DecodedData> pDecodeData = nullptr;
    int iDirection = 0;                     //行驶方向(0-未知; 1-向左; 2-向右)
    int nMonitorState = MONITOR_MODEL_INIT_STATE;
} SaveImgData;

//识别处理数据
typedef struct
{
    int iDataSource = 0;        //数据来源标识
    uint32_t iFrameId = 0;      //帧号
    uint64_t i64TimeStamp = 0;  //帧数据时间戳
    uint32_t iDataNO = 0;       //数据编号
    std::string strTrainDate;   //过车日期    (格式：YYYY-MM-DD)
    std::string strTrainName;   //车次        (格式：HH-MM-SS)
    int iDirection = 0;         //行驶方向(0-未知; 1-向左; 2-向右)
    int iStatus = 0;            //车辆状态(0-无车; 1-有车行驶; 2-有车停止)
    std::shared_ptr<DecodedData> pDecodeData = nullptr;
    std::shared_ptr<void> pVoidData = nullptr;
    std::shared_ptr<void> pData = nullptr;

    uint32_t iSize = 0;                     // Size of memory, bytes
    uint32_t iWidth = 0;        //Width of image
    uint32_t iHeight = 0;       //Height of image
    int iRate = 0;              //帧率
    int iTrainIndex = 0;
    bool bIsEnd = false;        //车厢结束标识
    bool bIsTrainEnd = false;   //列车结束标识
    std::string strOrigTrainDate; //原过车日期    (格式：YYYY-MM-DD)
    std::string strOrigTrainName; //原车次        (格式：HH-MM-SS)
    uint32_t iOrigFrameId = 0;    //原帧号
    int nMonitorState = MONITOR_MODEL_INIT_STATE;
    std::string strPicFilePath;

}ProcessData;

//预处理子数据
typedef struct
{
    int iBigClassId = -1;           //类别大类 （第二步用 1-属性 23456-编号）
    int iCarXH = 0;                 //所属车厢序号 （第二步用）
    uint32_t iWidth = 0;
    uint32_t iHeight = 0;
    uint32_t iWidthStride = 0;                                    // Width after align up
    uint32_t iHeightStride = 0;                                   // Height after align up
    acldvppPixelFormat format = PIXEL_FORMAT_YUV_SEMIPLANAR_420;  // Format of image
    uint32_t iSize = 0;                                               // Size of memory, bytes
    std::shared_ptr<void> pData = nullptr;                        // Smart pointer of data
    std::string strPicFilePath;
    Step1Location step1Location;
} PreSubData;

//预处理数据
typedef struct
{
    std::vector<PreSubData> vecPreSubData;
} PreData;

//推理子数据
typedef struct
{
    int iBigClassId = -1;   //类别大类 （第二步用 1-属性 23456-编号）
    int iCarXH = 0;         //图像所属车厢序号（第二步用）
    std::vector<RawData> vecInferOutput;
    Step1Location step1Location;
} AclSubData;

typedef struct
{
    int iBigClassId = -1;   //类别大类 （第二步用 1-属性 23456-编号）
    int iCarXH = 0;         //图像所属车厢序号（第二步用）
    std::vector<stDetection> vecInferOutput;
    Step1Location step1Location;
} CudaAclSubData;

//推理数据
typedef struct
{
    std::vector<AclSubData> vecAclSubData;
} AclData;



//推理数据(Cuda)
typedef struct
{
    std::vector<InferenceData> vecAclSubData;
} CudaAclData;

//动态检测结果
typedef struct
{
    uint32_t iFrameId = 0;      //帧号
    uint64_t i64TimeStamp = 0;  //帧数据时间戳
    bool bHasTrain = false;     //有无车标志
    bool bIsEnd = false;        //列车结束标识
    std::string strTrainDate;   //过车日期    (格式：YYYY-MM-DD)
    std::string strTrainName;   //车次        (格式：HH-MM-SS)
    int iDirection = 0;         //行驶方向(0-未知; 1-向左; 2-向右)
    int nMonitorState = MONITOR_MODEL_INIT_STATE;
} MoveData;

//模型具体结果
typedef struct
{
    int iLine = -1;        //字段代号（仅第二步使用）
    int iClassId = -1;     //大小框的类别
    float fScore = 0;      //分数
    int iAnchorId = -1;    //暂时仅记录
    float fLTX = 0;        //左上X坐标 Left Top x
    float fLTY = 0;        //左上y坐标 Left Top y
    float fRBX = 0;        //右下y坐标 Right Bottom x
    float fRBY = 0;        //右下y坐标 Right Bottom y
    float fClear = 0;      //清晰度
} SingleData;

//后处理子数据
typedef struct
{
    int iTargetType;                        //目标类别 (0:车号; 1:属性; 2:车头; 3:定检期; 4:集装箱)
    int iBigClassId = -1;                   //大框id (给第二步用 1-属性 23456-编号)
    int iCarXH = 0;                         //当前大框所属车厢
    std::vector<SingleData> vecSingleData;  //模型具体结果
    Step1Location step1Location;            //原图上大框坐标(第二步坐标还原时用)   
} PostSubData;

//后处理数据
typedef struct
{
    int iModelType = -1;                        //(0:车号模型，1:定检期模型，2:集装箱模型)
    std::vector<PostSubData> vecPostSubData;    //模型后处理结果
    uint32_t iFrameId = 0;

    int nMonitorState = MONITOR_MODEL_INIT_STATE;

} PostData;


//转换具体内容
typedef struct
{
    int iLine = -1;                     //字段代号
    bool IsChkFlag = false;             //是否符合基本数据校验
    std::vector<std::string> vecValue;  //转换后的每个字符内容
    std::vector<float> vecScore;        //每个字符对应的分数
} TransInfo;

//转换后子数据
typedef struct
{
    int iBigClassId = -1;               //类别大类(1-属性; 23456-编号; 7-定检期)
    int iCarXH = 0;                     //当前大框所属车厢
    float fScoreSum = 0;                //大框内各个字符总得分, 取最优帧用
    std::string strAllValue;            //大框内所有字符, 集装箱校验,选优用
    std::vector<TransInfo> vecTransInfo;//具体的转换信息
    Step1Location step1Location;        //原图上大框坐标
} TransSubData;

//转换后数据
typedef struct
{
    std::vector<TransSubData> vecTransSubData;
} TransData;


//火车车号信息
typedef struct
{
    int iDataSource = 0;                //数据来源标识
    int iCarXH = 0;                     //车厢序号
    bool bIsEnd = false;                //列车结束标识
    uint64_t i64TrainEndTimeStamp = 0;  //列车结束帧号时间戳(bIsEnd=true，该参数才有值)
    std::string strTrainType;           //车厢类型
    std::string strTrainNum;            //车厢编号
    std::string strBestImg;             //最优图片名称
    float fScoreSum = 0;                //车号最优图字符总得分
    uint64_t i64TimeStamp = 0;          //最优图片时间戳
    Step1Location step1Location;        //原图上大框坐标
    std::string strTrainDate;           //过车日期    (格式：YYYY-MM-DD)
    std::string strTrainName;           //车次        (格式：HH-MM-SS)
    uint32_t iStartFrameId = 0;         //当前车厢车号的开始帧号
    uint32_t iEndFrameId = 0;           //当前车厢车号的结束帧号
    uint64_t i64StartTimeStamp = 0;     //当前车厢车号的开始帧号时间戳
    uint64_t i64EndTimeStamp = 0;       //当前车厢车号的结束帧号时间戳
    int iTrainTypeId = -1;              //车厢类型ID(标识哪种类型的车)
    int iDirection = 0;                 //行驶方向(0-未知; 1-向左; 2-向右)
} TrainNum;

//火车属性信息
typedef struct
{
    int iDataSource = 0;                //数据来源标识
    int iCarXH = 0;                     //车厢序号
    bool bIsEnd = false;                //列车结束标识
    uint64_t i64TrainEndTimeStamp = 0;  //列车结束帧号时间戳(bIsEnd=true，该参数才有值)
    std::string strLoad;                //载重
    std::string strSelf;                //自重
    std::string strVolume;              //容积
    std::string strChange;              //换长
    std::string strVolumeSurface;       //罐车容量记表
    std::string strBestImg;             //最优图片名称
    float fScoreSum = 0;                //属性最优图字符总得分
    uint64_t i64TimeStamp = 0;          //最优图片时间戳
    Step1Location step1Location;        //原图上大框坐标
    std::string strTrainDate;           //过车日期    (格式：YYYY-MM-DD)
    std::string strTrainName;           //车次        (格式：HH-MM-SS)
    uint32_t iStartFrameId = 0;         //当前车厢属性的开始帧号
    uint32_t iEndFrameId = 0;           //当前车厢属性的结束帧号(即下节车厢属性的开始帧号)
    uint64_t i64StartTimeStamp = 0;     //当前车厢属性的开始帧号时间戳
    uint64_t i64EndTimeStamp = 0;       //当前车厢属性的结束帧号时间戳
    int iDirection = 0;                 //行驶方向(0-未知; 1-向左; 2-向右)
} TrainPro;

//火车定检期信息
typedef struct
{
    int iDataSource = 0;            //数据来源标识
    int iCarXH = 0;                 //车厢序号
    bool bIsEnd = false;            //列车结束标识
    std::string strTrainDate;       //过车日期    (格式：YYYY-MM-DD)
    std::string strTrainName;       //车次        (格式：HH-MM-SS)
    std::string strChkDate1;        //定检期第一行
    std::string strChkDate2;        //定检期第二行
    std::string strBestImg;         //定检期最优图
    float fScoreSum = 0;            //定检期最优图字符总得分
    uint64_t i64TimeStamp = 0;      //最优图片时间戳
    Step1Location step1Location;    //原图上大框坐标
    uint32_t iStartFrameId = 0;     //当前车厢定检期的开始帧号
    uint32_t iEndFrameId = 0;       //当前车厢定检期的结束帧号
    uint64_t i64StartTimeStamp = 0; //当前车厢定检期的开始帧号时间戳
    uint64_t i64EndTimeStamp = 0;   //当前车厢定检期的结束帧号时间戳
    std::string strChkDate1DeadLine;//定检期1截至日期
} ChkDate;

//火车集装箱信息
typedef struct
{
    int iDataSource = 0;            //数据来源标识
    int iCarXH = 0;                 //车厢序号
    bool bIsEnd = false;            //列车结束标识
    std::string strTrainDate;       //过车日期    (格式：YYYY-MM-DD)
    std::string strTrainName;       //车次        (格式：HH-MM-SS)
    std::string strContainerNo;     //集装箱号
    std::string strBestImg;	        //集装箱最优图
    float fScoreSum = 0;            //集装箱最优图总得分, 取最优帧用
    uint64_t i64TimeStamp = 0;      //集装箱最优图时间戳
    Step1Location step1Location;    //原图上大框坐标
    uint32_t iStartFrameId = 0;     //当前车厢集装箱的开始帧号
    uint32_t iEndFrameId = 0;       //当前车厢集装箱的结束帧号
    bool bChkFlag = false;          //集装箱是否校验通过
} Container;

//车厢的2个集装箱信息
typedef struct
{
    Container container1;
    Container container2;
} TrainContainer;

//火车信息
typedef struct
{
    int iDataSource = 0;                //数据来源标识
    bool bIsEnd = false;                //列车结束标识
    uint64_t i64TrainEndTimeStamp = 0;  //列车结束帧号时间戳(bIsEnd=true，该参数才有值)
    std::string strTrainDate;           //过车日期    (格式：YYYY-MM-DD)
    std::string strTrainName;           //车次        (格式：HH-MM-SS)
    int iCarXH = 0;                     //车厢序号
    uint64_t i64TimeStamp = 0;          //当前车厢时间戳 = ((车号时间戳+属性时间戳) / 2)
    TrainNum trainNum;                  //车厢车号信息
    TrainPro trainPro;                  //车厢属性信息
    ChkDate chkDate;                    //车厢定检期信息
    Container container1;               //车厢集装箱1信息
    Container container2;               //车厢集装箱2信息
    uint32_t iStartFrameId = 0;         //当前车厢开始帧号
    uint32_t iEndFrameId = 0;           //当前车厢结束帧号
    uint64_t i64StartTimeStamp = 0;     //当前车厢开始帧号时间戳(集装箱合并使用)
    uint64_t i64EndTimeStamp = 0;       //当前车厢结束帧号时间戳(集装箱合并使用)
    bool bMergerFlag = false;           //定检期集装箱合并完成
    int iDirection = 0;                 //行驶方向(0-未知; 1-向左; 2-向右)
} Train;

//ftp上传数据
typedef struct
{
    std::string strLocalFile;       //本地文件
    std::string strFtpFilePath;     //上传路径
    std::string strFtpFileName;     //上传文件名
    bool bIsEnd  = false;           //列车结束标识
} FtpData;


typedef struct
{
    float fLTX = 0; //左上X坐标
    float fLTY = 0; //左上y坐标
    float fRBX = 0; //右下y坐标
    float fRBY = 0; //右下y坐标
}Coordinates;

typedef struct
{
    std::string strTrainDate;           //过车日期    (格式：YYYY-MM-DD)
    std::string strTrainName;           //车次        (格式：HH-MM-SS)
    uint32_t iStartFrameId = 0;         //当前车厢开始帧号
    uint64_t i64StartTimeStamp = 0;     //当前车厢开始帧时间戳
    uint32_t iEndFrameId = 0;           //当前车厢结束帧号
    uint64_t i64EndTimeStamp = 0;       //当前车厢结束帧时间戳
    int iTrainIndex = 0;                //第几节车厢
    bool bIsEnd = false;                //是否最后一节
    bool bmodelconfirmed;               //是否是间隔模型切分的车厢
} TrainRange;

//模型识别配置结构体
//包含文件配置部分和内部处理变量
typedef struct imganalyse
{
// from file
/////////下述设定取自csv文件
    int nType;                              //算法目的 0:动态检测 1:车厢划分
    int nAreaX1;                            //算法监测区域 开始位置x坐标
    int nAreaY1;                            //算法监测区域 开始位置y坐标
    int nAreaX2;                            //算法监测区域 结束位置x坐标
    int nAreaY2;                            //算法监测区域 结束位置y坐标
    int bOrLevel;                           //算法结果融合等级 相同值进行与运算 不同值进行或运算
    bool bDiff;                             //是否以不同作为判断条件 false:以匹配度相同作为判定条件 true：以匹配度不同作为判定条件
    bool bOn;                               //是否启用改区域匹配监测(该算法是否有效)  false：不启用(无效) true:启用(有效)
    double dSameThresholdVal;               //判定匹配相同的阈值
    double dDiffThresholdVal;               //判定匹配不同的阈值
    int nPauseMaxCoumt;                     //判定为停车的最大计量(超过设定值判定为停车)
    int npicimprovetype;                    //图像改善处理(包含 灰度化/均衡化直方图/gamma变换/自定义)
    int templemethod;                       //模型比对模式
    int histmethod;                         //直方图比对模式
    int specmethod;                         //自定义比对模式
    int compmethod;                         //对比类型(模型比对/模型比对/自定义比对,可多选)
    std::string baseImagePath;              //基准图片路径
/////////下述设定为处理识别变量
    double dComparePoint;                   //比对值
    double dPreComparePoint;                //比对值
    bool bChanged;                          //与基准图对比值 是否发生变化 true:发生变化 false:没有发生变化
    bool bPreChanged;                       //上一帧与基准图对比值
    bool fluctuationFlag;                   //最近100帧的最大值与最小值的波动标志
    int nSameCount;                         //比对值没有发生变化的计数
    int iIndex;                             //第几个配置项
}AnalyseInfo;


//车厢划分信息结构体
//文件配置
typedef struct trainpartion
{
    std::string strTrainDate;
    std::string strTrainName;
    int nindex;                             //车厢顺位
    uint64_t i64StartTimeStamp;             //当节车厢出现的开始帧时间
    uint64_t i64EndTimeStamp;               //当节车厢出现的结束帧时间
    float fspeed;                           //当节车厢的车速
    int startframe;                         //当节车厢出现的开始帧帧号
    int endframe;                           //当节车厢出现的结束帧帧号
    int modelSpaceFrame;
    bool bfuncconfirmed;                    //是否算法划分完成                  true:是  false:否
    bool bmodelconfirmed;                   //是否根据第一次识别结果确认完成     true:是  false:否
    float fLTX;                             //车钩开始位置X值
    float fLTY;                             //车钩开始位置y值
    float fRBX;                             //车钩结束位置X值
    float fRBY;                             //车钩结束位置y值
    bool bIsEnd = false;                    //是否最后一节
    int nStatus;                            //方向(0:未知，1:向左行驶，2:向右行驶)
    int iRate;                              //帧率                        
}PartionInfo;

typedef struct
{
    std::shared_ptr<ProcessData> processData;
    std::string strAllClassType;
}TrainBackInfo;

//方向计算
typedef struct
{
    int iBigClassId = -1;                   //大框id (给第二步用 1-属性 23456-编号)
    uint32_t iFrameId = 0;                  //帧号
    float fCenterX; //第一步识别目标中心点X坐标
    float fTargetWidth; // 第一步识别目标X坐标宽度
} CalculateInfo;


typedef struct
{
    int iDataSource = 0;                //数据来源标识
    uint32_t iFrameId = 0;
    FrameInfo frameInfo;
    uint32_t iSize = 0;                 // Size of memory, bytes
    uint32_t iSrcSize = 0;                 // Size of memory, bytes
    std::shared_ptr<void> pData;        // Smart pointer of data
    std::shared_ptr<void> pSrcData;     // Smart pointer of data(源数据) 推理时,RGB数据会拷贝一份,源数据不变用于传送到后处理引擎画框,另一份数据用于resize成640x640并归一化到0-1
    uint64_t i64TimeStamp = 0;          //帧数据时间戳
} YoloModelInfo;

template<typename _T>
std::string join_dims(const std::vector<_T>& dims){
    std::stringstream output;
    char buf[64];
    const char* fmts[] = {"%d", " x %d"};
    for(int i = 0; i < dims.size(); ++i){
        snprintf(buf, sizeof(buf), fmts[i != 0], dims[i]);
        output << buf;
    }
    return output.str();
}

inline unsigned int getElementSize(nvinfer1::DataType t);

inline int64_t volume(const nvinfer1::Dims& d);

#endif
