#ifndef APP_COMMON_H
#define APP_COMMON_H

#include <algorithm>
#include <assert.h>
#include <chrono>
#include <cmath>
#include <ctime>
#include <deque>
#include <fstream>
#include <functional>
#include <iostream>
#include <math.h>
#include <memory>
#include <numeric>
#include <regex>
#include <sstream>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>

#include <NvInfer.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>

#ifdef __cplusplus
extern "C"
{
#endif
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/samplefmt.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libswscale/swscale.h>
#ifdef __cplusplus
};
#endif

#include "Utils.h"
#include "TimeUtil.h"
#include "StringUtil.h"
#include "FileUtil.h"
#include "Config.h"
#include "Log.h"
//#include "httplib.h"
#include "multitype_queue.h"
#include "nvidia_acl_datatype.h"
#include "CommonDataType.h"

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

#include "CommonEnum.h"
#include "CommonStruct.h"


using namespace Yolo;


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

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

#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 CORNER_BATCH_SIZE 1    //batch size
#define CORNER_NMS_THRESH 0.5     //corner 非极大值抑制阈值
#define CORNER_SCORE_THRESH 0.6   //corner 置信度(得分)阈值
#define CORNER_INPUT_CHANNEL 3     //输入通道数

#define CORNER_CLASS_NUM 2    //corner 2分类

#define CORNER_INPUT_H  640        //corner 输入图像高
#define CORNER_INPUT_W  640       //corner 输入图像宽

#define CORNER_BBOX_SIZE1  (CORNER_INPUT_H/32)
#define CORNER_BBOX_SIZE2  (CORNER_INPUT_H/16)
#define CORNER_BBOX_SIZE3  (CORNER_INPUT_H/8)

#define CORNER_POS_CONF 5

#define CORNER_INPUT_SIZE    INPUT_CHANNEL*CORNER_INPUT_H*CORNER_INPUT_W      //input
#define CORNER_OUTPUT_SIZE   INPUT_CHANNEL*(CORNER_BBOX_SIZE1*CORNER_BBOX_SIZE1+CORNER_BBOX_SIZE2*CORNER_BBOX_SIZE2+CORNER_BBOX_SIZE3*CORNER_BBOX_SIZE3)*(CORNER_CLASS_NUM+CORNER_POS_CONF)       //output

//STEP1
#define STEP1_POS_CONF 5

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

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

#define STEP1_INPUT_H  640        //step1 输入图像高
#define STEP1_INPUT_W  640       //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.6    //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


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);

// 0 = 停止识别； 1 = 开始识别
extern std::atomic<int> g_identify_type;
// -1 = 未知方向；  1 = 向左行驶；  2 = 向右行驶
extern std::atomic<int> g_come_direction;
// 0 = 无车；  1 = 有车；
extern std::atomic<int> g_car_type;

#endif
