#pragma once
/********************************************************
	* @file    : error_api_define.h
	* @brief   : 异常算法接口2的 公用的定义属性
	* @details :
	* @author  : qqm
	* @date    : 2022.3.10
*********************************************************/
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <unordered_map>

#include "public_define.h"

#if defined(_MSC_VER) || defined(_WIN32) || defined(_WIN64)
#define dll_export __declspec(dllexport)
#define dll_import __declspec(dllimport)
#else //  __linux__
#define dll_export __attribute__ ((visibility("default")))
#include <memory>
#endif
#define MAX_SOCRE_DEFINE 1000

/////////////////////////////异常接口2返回的结构体设计////////////////////////////////
namespace eapi {
/// 条码/二维码
	struct ErCodeQ {
		preinfo::BOX_TYPE type;				/// 类型 条码还是二维码
		std::string result;					/// 识别结果
		preinfo::PaperRect<double> box;		/// 整个大的区域坐标
		ErCodeQ() :type(preinfo::BOX_TYPE::BOX_EXAM_BARCODE), result("") {};
	};
	/// 填涂判断通用结果存放结构体
	struct ErSinTt :preinfo::PaperRect<double> {
		bool filled;			/// 本填涂框是否是填涂
		int  fildedNumber;		/// 本区域内有效的判断依据数量（红色点数） 
		ErSinTt() :filled(false),fildedNumber(0) {};
	};
	/// 单个填涂序列（单个选择题，或者单个考号填涂列）
	struct ErTtRes {
		std::vector<ErSinTt> smallBoxes;
		int id;					/// 题号 或 序号之类
		int uuid;				/// uuid
		ErTtRes() :id(0) { smallBoxes.clear(); };
	};
	/// 学号填涂框
	struct ErFillNumber {
		bool effective;						/// 是否有效
		preinfo::PaperRect<double> box;		/// 整个大的区域坐标
		std::string fillNumber;				/// 填涂识别结果
		std::vector<ErTtRes> smallItems;	/// 每一列或行的填涂信息	
		ErFillNumber() :effective(false), fillNumber("") { smallItems.clear(); };
	};
	/// 选择题 可以考虑删除
	struct ErChoise {
		std::vector<ErTtRes> sinChoise;		/// 单个选择题
		ErChoise() { sinChoise.clear(); };
	};
	/// Score区域
	struct ErScore {
		bool effective;						/// 是否有效 - 无效情况下 下面三个不需要读取
		preinfo::SCORE_TYPE type;			/// 打分框的类型
		bool withHalf;						/// 是否含有.5分
		int	limit;							/// 上限分值 数据来自模板json中"limit"字段
		double maxSocre;                    /// 小问最大分值
		int cols;							/// 个数
		preinfo::PaperRect<double> box;		/// 打分框区域
		std::vector<ErSinTt> smallBoxes;	/// 单个打分框
		std::vector<double> vecSocreValue;	/// 单个打分框内分数值
		ErScore() :effective(true) { smallBoxes.clear(); vecSocreValue.clear(); };
		double GetSocre()                   /// 获取该打分框分数
		{
			double ret = 0.0;
			if (effective)
			{
				if ( smallBoxes.size() == 1)
				{
					//单个空，并且没有分数
					if (maxSocre == -1)
					{
						//没有小问给选中最大分值，界面自己综合调整显示
						ret = smallBoxes[0].fildedNumber > 0 ? MAX_SOCRE_DEFINE : 0;
					}
					else
					{
						//小问，给小问最大分
						ret = smallBoxes[0].fildedNumber > 0 ? maxSocre : 0;
					}
				}
				else if (type == preinfo::SCORE_TYPE::NORMAL)
				{
					int selectred = -1;
					int maxred = 0;
					if (withHalf)
					{
						ret += smallBoxes[smallBoxes.size() - 1].fildedNumber > 0 ? 0.5 : 0;
						for (int m = 0; m < smallBoxes.size() - 1; m++)
						{
							if (maxred < smallBoxes[m].fildedNumber)
							{
								maxred = smallBoxes[m].fildedNumber;
								selectred = m;
							}
						}
					}
					else
					{
						for (int m = 0; m < smallBoxes.size(); m++)
						{
							if (maxred < smallBoxes[m].fildedNumber)
							{
								maxred = smallBoxes[m].fildedNumber;
								selectred = m;
							}
						}
					}
					if (selectred > -1)
						ret += vecSocreValue[selectred];
				}
				else if (type == preinfo::SCORE_TYPE::COMBIN)
				{
					int selectred = -1;
					int maxred = 0;
					//十位
					int tw = limit / 10;
					for (int m = 1; m <= tw; m++)
					{
						if (maxred < smallBoxes[m].fildedNumber)
						{
							maxred = smallBoxes[m].fildedNumber;
							selectred = m;
						}
					}
					if (selectred > -1)
						ret += 10 * vecSocreValue[selectred];

					selectred = -1;
					maxred = 0;

					if (withHalf)
					{
						if (smallBoxes[smallBoxes.size() - 1].fildedNumber > 0)
							ret += 0.5;
						for (int m = tw + 1; m < smallBoxes.size() - 1; m++)
						{
							if (maxred < smallBoxes[m].fildedNumber)
							{
								maxred = smallBoxes[m].fildedNumber;
								selectred = m;
							}
						}
					}
					else
					{
						for (int m = tw + 1; m < smallBoxes.size(); m++)
						{
							if (maxred < smallBoxes[m].fildedNumber)
							{
								maxred = smallBoxes[m].fildedNumber;
								selectred = m;
							}
						}
					}
					if (selectred > -1)
						ret += vecSocreValue[selectred];
				}
				else
				{
					int selectred = -1;
					int maxred = 0;
					for (int m = 0; m < smallBoxes.size(); m++)
					{
						if (maxred < smallBoxes[m].fildedNumber)
						{
							maxred = smallBoxes[m].fildedNumber;
							selectred = m;
						}
					}
					if (selectred > -1)
						ret += vecSocreValue[selectred];
				}
			}
			else
			{
				ret = -1.0;
			}
			return ret;
		};
	};
	/// 通用主观题
	struct ErBox {
		int id;								/// 模板内的ID
		int uuid;							/// 自增的UUID
		int multiple;						/// 是否是多块
		int orderNumber;					/// 多块的块号 
		int marktype;						/// markType
		preinfo::PaperRect<double> box;		/// 大区域
		preinfo::BOX_TYPE type;				/// 类型
		ErScore score;						/// 打分框
		/// 选做题填涂框 选做题时候才有效
		ErTtRes	xzTt;						/// 选做填涂
		ErBox() :id(0), type(preinfo::BOX_TYPE::BOX_NONE) {};
	};

	/// 新增的异常处理接口交互结构体  
	typedef struct SingleErrorPaperInfo
	{
		/**
			包含各种每一张答题卡上面的模板信息，坐标信息，题目信息，识别结果信息
		*/
		int					pageId;				/// 本页页号
		int					status;				/// 本页状态
		std::string			strPath;			/// 矫正后图像绝对路径

		ErFillNumber		fillNumber;			/// 填涂考号
		std::vector<ErCodeQ> codeResult;		/// 条码/二维码识别结果
		ErChoise			choice;				/// 选择题
		std::vector<ErBox>	boxes;				/// 通用主观题
		SingleErrorPaperInfo() :pageId(-1), status(PAPER_SUCC), strPath("") {};
	}speinfo;
}