#include "ANSCUSTOMDetector.h"
#include "Utility.h"
#include <windows.h>

namespace ANSCENTER
{
	std::string ANSCUSTOMDETECTOR::FindANSCustomLibraryName(const std::string& folderPath, const std::string& keyword) {
		ANS_DBG("ANSCUSTOM_FindLib", "ENTRY folder=%s keyword=%s",
			folderPath.c_str(), keyword.c_str());
		std::string searchPath = folderPath + "\\*.dll";
		WIN32_FIND_DATAA findFileData;
		HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findFileData);

		if (hFind == INVALID_HANDLE_VALUE) {
			ANS_DBG("ANSCUSTOM_FindLib", "NO_MATCH (FindFirstFile invalid handle) folder=%s",
				folderPath.c_str());
			return ""; // Return an empty string if no file is found
		}

		do {
			std::string fileName = findFileData.cFileName;
			if (fileName.find(keyword) != std::string::npos) {
				FindClose(hFind); // Close the handle before returning
				std::string fullPath = folderPath + "\\" + fileName;
				ANS_DBG("ANSCUSTOM_FindLib", "FOUND %s", fullPath.c_str());
				return fullPath; // Return the full path
			}
		} while (FindNextFileA(hFind, &findFileData) != 0);

		FindClose(hFind); // Close the handle after finishing the loop
		ANS_DBG("ANSCUSTOM_FindLib", "NO_MATCH folder=%s keyword=%s",
			folderPath.c_str(), keyword.c_str());
		return ""; // Return an empty string if no match is found
	}
	bool ANSCUSTOMDETECTOR::OptimizeModel(bool fp16, std::string& optimizedModelFolder) {
		ANS_DBG("ANSCUSTOM_Optimize", "ENTRY this=%p fp16=%d", (void*)this, (int)fp16);
		std::lock_guard<std::recursive_mutex> lock(_mutex);
		if (!ANSODBase::OptimizeModel(fp16, optimizedModelFolder)) {
			ANS_DBG("ANSCUSTOM_Optimize", "ERROR base OptimizeModel failed this=%p", (void*)this);
			return false;
		}
		optimizedModelFolder = _modelFolder;
		if (!_customDetector) {
			ANS_DBG("ANSCUSTOM_Optimize", "ERROR _customDetector null this=%p", (void*)this);
			return false;
		}
		bool ok = _customDetector->OptimizeModel(fp16);
		ANS_DBG("ANSCUSTOM_Optimize", "%s this=%p folder=%s",
			ok ? "SUCCESS" : "FAILED", (void*)this, optimizedModelFolder.c_str());
		return ok;
	}
	bool ANSCUSTOMDETECTOR::LoadModel(const std::string& modelZipFilePath, const std::string& modelZipPassword) {
		ANS_DBG("ANSCUSTOM_LoadModel", "ENTRY this=%p zip=%s", (void*)this, modelZipFilePath.c_str());
		std::lock_guard<std::recursive_mutex> lock(_mutex);
		ModelLoadingGuard mlg(_modelLoading);
		try {
			bool result = ANSODBase::LoadModel(modelZipFilePath, modelZipPassword);
			if (!result) {
				ANS_DBG("ANSCUSTOM_LoadModel", "ERROR base LoadModel failed this=%p zip=%s",
					(void*)this, modelZipFilePath.c_str());
				return false;
			}
			std::string labelMap;
			CreateCustomDetector();
			if (!_customDetector) {
				ANS_DBG("ANSCUSTOM_LoadModel", "ERROR _customDetector null after Create this=%p", (void*)this);
				return false;
			}
			//_customDetector->SetLoadEngineOnCreate(this->_loadEngineOnCreation);
			bool ok = _customDetector->Initialize(_modelFolder,_modelConfig.detectionScoreThreshold, labelMap);
			ANS_DBG("ANSCUSTOM_LoadModel", "%s this=%p folder=%s thr=%.3f",
				ok ? "SUCCESS" : "FAILED", (void*)this, _modelFolder.c_str(),
				_modelConfig.detectionScoreThreshold);
			return ok;
		}
		catch (std::exception& e) {
			ANS_DBG("ANSCUSTOM_LoadModel", "ERROR exception this=%p: %s", (void*)this, e.what());
			this->_logger.LogFatal("ANSCUSTOMDETECTOR::LoadModel", e.what(), __FILE__, __LINE__);
			return false;
		}

	}
	bool ANSCUSTOMDETECTOR::LoadModelFromFolder(std::string licenseKey, ModelConfig modelConfig, std::string modelName, std::string className, const std::string& modelFolder, std::string& labelMap) {
		ANS_DBG("ANSCUSTOM_LoadFolder", "ENTRY this=%p model=%s class=%s folder=%s",
			(void*)this, modelName.c_str(), className.c_str(), modelFolder.c_str());
		std::lock_guard<std::recursive_mutex> lock(_mutex);
		ModelLoadingGuard mlg(_modelLoading);
		try {
			_modelFolder = modelFolder;
			std::string labelMap;
			_modelConfig = modelConfig;
			if (_modelConfig.modelMNSThreshold < 0.2)
				_modelConfig.modelMNSThreshold = 0.5;
			if (_modelConfig.modelConfThreshold < 0.2)
				_modelConfig.modelConfThreshold = 0.5;
			CreateCustomDetector();
			if (!_customDetector) {
				ANS_DBG("ANSCUSTOM_LoadFolder", "ERROR _customDetector null after Create this=%p", (void*)this);
				_isInitialized = false;
				return false;
			}
			_customDetector->SetLoadEngineOnCreate(this->_loadEngineOnCreation);
			_isInitialized = _customDetector->Initialize(_modelFolder, _modelConfig.detectionScoreThreshold, labelMap);
			ANS_DBG("ANSCUSTOM_LoadFolder", "%s this=%p folder=%s thr=%.3f loadOnCreate=%d",
				_isInitialized ? "SUCCESS" : "FAILED",
				(void*)this, _modelFolder.c_str(),
				_modelConfig.detectionScoreThreshold,
				(int)this->_loadEngineOnCreation);
			return _isInitialized;
		}
		catch (std::exception& e) {
			ANS_DBG("ANSCUSTOM_LoadFolder", "ERROR exception this=%p: %s", (void*)this, e.what());
			this->_logger.LogFatal("ANSCUSTOMDETECTOR::LoadModel", e.what(), __FILE__, __LINE__);
			return false;
		}
	}
	bool ANSCUSTOMDETECTOR::ConfigureParameters(Params& param) {
		ANS_DBG("ANSCUSTOM_Configure", "ENTRY this=%p", (void*)this);
		std::lock_guard<std::recursive_mutex> lock(_mutex);
		try {
			if (!_customDetector) {
				ANS_DBG("ANSCUSTOM_Configure", "ERROR _customDetector null this=%p", (void*)this);
				this->_logger.LogError("ANSCUSTOMDETECTOR::ConfigureParamaters", "Custom detector is not initialized", __FILE__, __LINE__);
				return false;
			}
			// Convert the vector of Params to a vector of CustomParams
			CustomParams customParams;
			_customDetector->ConfigureParameters(customParams);

			// loop throught this->_params and set the values
			param.ROI_Config.clear();
			for (auto& cf : customParams.ROI_Config) {
				ROIConfig ROIConfig;
				ROIConfig.Rectangle = cf.Rectangle;
				ROIConfig.Polygon = cf.Polygon;
				ROIConfig.Line = cf.Line;
				ROIConfig.MinItems = cf.MinItems;
				ROIConfig.MaxItems = cf.MaxItems;
				ROIConfig.Name = cf.Name;
				ROIConfig.ROIMatch = cf.ROIMatch;
				param.ROI_Config.push_back(ROIConfig);
			}
			param.ROI_Options.clear();
			for (auto& op : customParams.ROI_Options) {
				param.ROI_Options.push_back(op);
			}
			param.Parameters.clear();
			for (auto& par : customParams.Parameters) {
				Parameter Param;
				Param.Name = par.Name;
				Param.DataType = par.DataType;
				Param.NoOfDecimals = par.NoOfDecimals;
				Param.MaxValue = par.MaxValue;
				Param.MinValue = par.MinValue;
				Param.StartValue = par.StartValue;
				Param.ListItems.clear();
				for (auto& item : par.ListItems) {
					Param.ListItems.push_back(item);
				}
				Param.DefaultValue = par.DefaultValue;
				Param.Value = par.Value;
				param.Parameters.push_back(Param);
			}
			param.ROI_Values.clear();
			for (auto& roi : customParams.ROI_Values) {
				ROIValue roiValue;
				roiValue.ROIMatch = roi.ROIMatch;
				roiValue.OriginalImageSize = roi.OriginalImageSize;
				roiValue.Name = roi.Name;
				roiValue.Option = roi.Option;
				roiValue.ROIPoints.clear();
				for (auto& point : roi.ROIPoints) {
					Point customPoint;
					customPoint.x = point.x;
					customPoint.y = point.y;
					roiValue.ROIPoints.push_back(customPoint);
				}
				param.ROI_Values.push_back(roiValue);
			}
			ANS_DBG("ANSCUSTOM_Configure", "SUCCESS this=%p ROI_Config=%zu Options=%zu Params=%zu ROI_Values=%zu",
				(void*)this, param.ROI_Config.size(), param.ROI_Options.size(),
				param.Parameters.size(), param.ROI_Values.size());
			return true;
		}
		catch (std::exception& e) {
			ANS_DBG("ANSCUSTOM_Configure", "ERROR exception this=%p: %s", (void*)this, e.what());
			this->_logger.LogFatal("ANSCUSTOMDETECTOR::ConfigureParamaters", e.what(), __FILE__, __LINE__);
			return false;
		}
	}
	bool ANSCUSTOMDETECTOR::SetParameters(const Params& param) {
		ANS_DBG("ANSCUSTOM_SetParams", "ENTRY this=%p ROI_Config=%zu Options=%zu Params=%zu ROI_Values=%zu",
			(void*)this, param.ROI_Config.size(), param.ROI_Options.size(),
			param.Parameters.size(), param.ROI_Values.size());
		std::lock_guard<std::recursive_mutex> lock(_mutex);
		try {
			if (!_customDetector) {
				ANS_DBG("ANSCUSTOM_SetParams", "ERROR _customDetector null this=%p", (void*)this);
				return false;
			}
			// Convert the vector of Params to a vector of CustomParams
			ANSODBase::SetParameters(param);
			CustomParams customParams;
			customParams.ROI_Config.clear();
			for (auto& cf : param.ROI_Config) {
				CustomROIConfig customROIConfig;
				customROIConfig.Rectangle = cf.Rectangle;
				customROIConfig.Polygon = cf.Polygon;
				customROIConfig.Line = cf.Line;
				customROIConfig.MinItems = cf.MinItems;
				customROIConfig.MaxItems = cf.MaxItems;
				customROIConfig.Name = cf.Name;
				customROIConfig.ROIMatch = cf.ROIMatch;
				customParams.ROI_Config.push_back(customROIConfig);
			}
			customParams.ROI_Options.clear();
			for (auto& op : param.ROI_Options) {
				customParams.ROI_Options.push_back(op);
			}
			customParams.Parameters.clear();
			for (auto& par : param.Parameters) {
				CustomParameter customParam;
				customParam.Name = par.Name;
				customParam.DataType = par.DataType;
				customParam.NoOfDecimals = par.NoOfDecimals;
				customParam.MaxValue = par.MaxValue;
				customParam.MinValue = par.MinValue;
				customParam.StartValue = par.StartValue;
				customParam.ListItems.clear();
				for (auto& item : par.ListItems) {
					customParam.ListItems.push_back(item);
				}
				customParam.DefaultValue = par.DefaultValue;
				customParam.Value = par.Value;
				customParams.Parameters.push_back(customParam);
			}
			customParams.ROI_Values.clear();
			for (auto& roi : param.ROI_Values) {
				CustomROIValue roiValue;
				roiValue.ROIMatch = roi.ROIMatch;
				roiValue.OriginalImageSize = roi.OriginalImageSize;
				roiValue.Name = roi.Name;
				roiValue.Option = roi.Option;
				roiValue.ROIPoints.clear();
				for (auto& point : roi.ROIPoints) {
					CustomPoint customPoint;
					customPoint.x = point.x;
					customPoint.y = point.y;
					roiValue.ROIPoints.push_back(customPoint);
				}
				customParams.ROI_Values.push_back(roiValue);
			}
			bool ok = _customDetector->SetParameters(customParams);
			ANS_DBG("ANSCUSTOM_SetParams", "%s this=%p", ok ? "SUCCESS" : "FAILED", (void*)this);
			return ok;
		}
		catch (std::exception& e) {
			ANS_DBG("ANSCUSTOM_SetParams", "ERROR exception this=%p: %s", (void*)this, e.what());
			this->_logger.LogFatal("ANSCUSTOMDETECTOR::SetParamaters", e.what(), __FILE__, __LINE__);
			return false;
		}
	}
	bool ANSCUSTOMDETECTOR::CreateCustomDetector() {
		ANS_DBG("ANSCUSTOM_CreateDet", "ENTRY this=%p folder=%s prevDet=%p prevHMod=%p",
			(void*)this, _modelFolder.c_str(),
			(void*)_customDetector.get(), (void*)hMod);
		std::lock_guard<std::recursive_mutex> lock(_mutex);
		try {
			Destroy();
			//1. Load dynamic library
			_modelFilePath = FindANSCustomLibraryName(_modelFolder, "ANSCustom");//
			if (!FileExist(_modelFilePath)) {
				_modelFilePath = CreateFilePath(_modelFolder, "ANSCustomCode.dll"); // This is the dynamic library
			}
			//2. Check if the file exists again
			if (!FileExist(_modelFilePath)) {
				ANS_DBG("ANSCUSTOM_CreateDet", "ERROR DLL not found path=%s", _modelFilePath.c_str());
				this->_logger.LogFatal("ANSCUSTOMDETECTOR::Initialize", "Cannot find ANSCustomCode.dll", __FILE__, __LINE__);
				return false;
			}

			// 3. Load the library
			std::wstring dllPath = String2WString(_modelFilePath);
			hMod = LoadLibrary(dllPath.c_str());
			if (!hMod) {
				DWORD err = GetLastError();
				ANS_DBG("ANSCUSTOM_CreateDet", "ERROR LoadLibrary failed path=%s err=%lu",
					_modelFilePath.c_str(), (unsigned long)err);
				this->_logger.LogFatal("ANSCUSTOMDETECTOR::Initialize", "Cannot open library", __FILE__, __LINE__);
				return false;
			}
			ANS_DBG("ANSCUSTOM_CreateDet", "LIB_LOADED hMod=%p path=%s", (void*)hMod, _modelFilePath.c_str());
			CreatePluginFunc createPlugin = (CreatePluginFunc)GetProcAddress(hMod, "Create");

			if (!createPlugin) {
				ANS_DBG("ANSCUSTOM_CreateDet", "ERROR GetProcAddress(Create) failed hMod=%p — FreeLibrary",
					(void*)hMod);
				this->_logger.LogFatal("ANSCUSTOMDETECTOR::Initialize.", "Cannot load Create", __FILE__, __LINE__);
				FreeLibrary(hMod);
				hMod = nullptr;
				return false;
			}
			_customDetector = std::unique_ptr<IANSCustomClass>(createPlugin());
			if (!_customDetector) {
				ANS_DBG("ANSCUSTOM_CreateDet", "ERROR createPlugin returned null hMod=%p — FreeLibrary",
					(void*)hMod);
				this->_logger.LogFatal("ANSCUSTOMDETECTOR::Initialize", "Cannot create custom detector", __FILE__, __LINE__);
				FreeLibrary(hMod);
				hMod = nullptr;
				return false;
			}
			ANS_DBG("ANSCUSTOM_CreateDet", "SUCCESS this=%p detector=%p hMod=%p",
				(void*)this, (void*)_customDetector.get(), (void*)hMod);
			return true;
		}
		catch (std::exception& e) {
			ANS_DBG("ANSCUSTOM_CreateDet", "ERROR exception this=%p: %s", (void*)this, e.what());
			this->_logger.LogFatal("ANSCUSTOMDETECTOR::Initialize", e.what(), __FILE__, __LINE__);
			return false;
		}
	}
	bool ANSCUSTOMDETECTOR::Initialize(std::string licenseKey, ModelConfig modelConfig, const std::string& modelZipFilePath, const std::string& modelZipPassword, std::string& labelMap) {
		ANS_DBG("ANSCUSTOM_Initialize", "ENTRY this=%p zip=%s",
			(void*)this, modelZipFilePath.c_str());
		std::lock_guard<std::recursive_mutex> lock(_mutex);
		ModelLoadingGuard mlg(_modelLoading);
		try {
			bool result = ANSODBase::Initialize(licenseKey, modelConfig, modelZipFilePath, modelZipPassword, labelMap);
			if (!result) {
				ANS_DBG("ANSCUSTOM_Initialize", "ERROR base Initialize failed this=%p zip=%s",
					(void*)this, modelZipFilePath.c_str());
				return false;
			}
			_modelConfig = modelConfig;
			if (_modelConfig.modelMNSThreshold < 0.2)
				_modelConfig.modelMNSThreshold = 0.5;
			if (_modelConfig.modelConfThreshold < 0.2)
				_modelConfig.modelConfThreshold = 0.5;
			_modelConfig.detectionType = ANSCENTER::DetectionType::DETECTION;
			labelMap.clear();
			//1. Create custom detector
			CreateCustomDetector();
			if (!_customDetector) {
				ANS_DBG("ANSCUSTOM_Initialize", "ERROR _customDetector null after Create this=%p", (void*)this);
				_isInitialized = false;
				return false;
			}
			//2. Load initial model
			_customDetector->SetLoadEngineOnCreate(this->_loadEngineOnCreation);
			_isInitialized = _customDetector->Initialize(_modelFolder, _modelConfig.detectionScoreThreshold,labelMap);
			ANS_DBG("ANSCUSTOM_Initialize", "%s this=%p folder=%s thr=%.3f loadOnCreate=%d",
				_isInitialized ? "SUCCESS" : "FAILED",
				(void*)this, _modelFolder.c_str(),
				_modelConfig.detectionScoreThreshold,
				(int)this->_loadEngineOnCreation);
			return _isInitialized;
		}
		catch (std::exception& e) {
			ANS_DBG("ANSCUSTOM_Initialize", "ERROR exception this=%p: %s", (void*)this, e.what());
			this->_logger.LogFatal("ANSCUSTOMDETECTOR::Initialize", e.what(), __FILE__, __LINE__);
			return false;
		}
	}
	std::vector<Object> ANSCUSTOMDETECTOR::RunInference(const cv::Mat& input) {
		return RunInference(input, "CustomCam");
	}
	std::vector<Object> ANSCUSTOMDETECTOR::RunInference(const cv::Mat& input,const std::string& camera_id) {
		ANS_DBG("ANSCUSTOM_Infer", "ENTRY this=%p cam=%s in=%dx%d type=%d",
			(void*)this, camera_id.c_str(), input.cols, input.rows, input.type());
		if (!PreInferenceCheck("ANSCUSTOMDETECTOR::RunInference")) {
			ANS_DBG("ANSCUSTOM_Infer", "EARLY_OUT preInferenceCheck failed this=%p cam=%s",
				(void*)this, camera_id.c_str());
			return {};
		}
		std::vector<Object> result;

		try {
			// Early returns - good practice maintained
			if (!_licenseValid) {
				ANS_DBG("ANSCUSTOM_Infer", "ERROR invalid license this=%p cam=%s",
					(void*)this, camera_id.c_str());
				this->_logger.LogError("ANSCUSTOMDETECTOR::RunInference",
					"Invalid License", __FILE__, __LINE__);
				return result;
			}

			if (!_isInitialized) {
				ANS_DBG("ANSCUSTOM_Infer", "ERROR not initialized this=%p cam=%s",
					(void*)this, camera_id.c_str());
				this->_logger.LogError("ANSCUSTOMDETECTOR::RunInference",
					"Model is not initialized", __FILE__, __LINE__);
				return result;
			}

			if (input.empty() || input.cols < 10 || input.rows < 10) {
				ANS_DBG("ANSCUSTOM_Infer", "EARLY_OUT input too small this=%p cam=%s %dx%d",
					(void*)this, camera_id.c_str(), input.cols, input.rows);
				return result;
			}

			if (!_customDetector) {
				ANS_DBG("ANSCUSTOM_Infer", "ERROR _customDetector null this=%p cam=%s",
					(void*)this, camera_id.c_str());
				return result;
			}

			// Run inference
			std::vector<CustomObject> customResult = _customDetector->RunInference(input, camera_id);

			// Pre-allocate to avoid reallocations
			result.reserve(customResult.size());

			//// Use emplace_back + move semantics for zero-copy construction
			for (auto& customObj : customResult) {
				Object obj;
				obj.classId = customObj.classId;
				obj.trackId = customObj.trackId;
				obj.className = std::move(customObj.className);
				obj.confidence = customObj.confidence;
				obj.mask = std::move(customObj.mask);
				obj.box = customObj.box;
				obj.extraInfo = std::move(customObj.extraInfo);
				obj.kps = std::move(customObj.kps);
				obj.polygon = std::move(customObj.polygon);
				obj.cameraId = std::move(customObj.cameraId);

				result.emplace_back(std::move(obj));
			}

			if (_trackerEnabled) {
				result = ApplyTracking(result, camera_id);
				if (_stabilizationEnabled) result = StabilizeDetections(result, camera_id);
			}

			ANS_DBG("ANSCUSTOM_Infer", "DONE this=%p cam=%s det=%zu tracked=%d stab=%d",
				(void*)this, camera_id.c_str(), result.size(),
				(int)_trackerEnabled, (int)_stabilizationEnabled);
			return result;  // RVO applies, no copy
		}
		catch (const std::exception& e) {  // Catch by const reference
			ANS_DBG("ANSCUSTOM_Infer", "ERROR exception this=%p cam=%s: %s",
				(void*)this, camera_id.c_str(), e.what());
			this->_logger.LogFatal("ANSCUSTOMDETECTOR::RunInference",
				e.what(), __FILE__, __LINE__);
			return {};  // Return empty vector
		}
	}
	
	ANSCUSTOMDETECTOR::~ANSCUSTOMDETECTOR() {
		ANS_DBG("ANSCUSTOM_Dtor", "ENTRY this=%p detector=%p hMod=%p",
			(void*)this, (void*)_customDetector.get(), (void*)hMod);
		try {
			// Auto-release plugin object before unloading its DLL.
			// Destroy() itself swallows exceptions, but wrap defensively
			// so the destructor never throws.
			Destroy();
		}
		catch (const std::exception& e) {
			ANS_DBG("ANSCUSTOM_Dtor", "ERROR exception this=%p: %s", (void*)this, e.what());
			this->_logger.LogFatal("ANSCUSTOMDETECTOR::~ANSCUSTOMDETECTOR()", e.what(), __FILE__, __LINE__);
		}
		catch (...) {
			ANS_DBG("ANSCUSTOM_Dtor", "ERROR unknown exception this=%p", (void*)this);
		}
		ANS_DBG("ANSCUSTOM_Dtor", "EXIT this=%p detector=%p hMod=%p",
			(void*)this, (void*)_customDetector.get(), (void*)hMod);
	}
	bool ANSCUSTOMDETECTOR::Destroy() {
		ANS_DBG("ANSCUSTOM_Destroy", "ENTRY this=%p detector=%p hMod=%p",
			(void*)this, (void*)_customDetector.get(), (void*)hMod);
		try {
			if (_customDetector) {
				ANS_DBG("ANSCUSTOM_Destroy", "DESTROY detector=%p", (void*)_customDetector.get());
				_customDetector->Destroy();
				_customDetector.reset();
			}
			if (hMod) {
				ANS_DBG("ANSCUSTOM_Destroy", "FREE_LIBRARY hMod=%p", (void*)hMod);
				FreeLibrary(hMod);
				hMod = nullptr;
			}
			ANS_DBG("ANSCUSTOM_Destroy", "SUCCESS this=%p", (void*)this);
			return true;
		}
		catch (std::exception& e) {
			ANS_DBG("ANSCUSTOM_Destroy", "ERROR exception this=%p: %s", (void*)this, e.what());
			this->_logger.LogFatal("ANSCUSTOMDETECTOR::Destroy", e.what(), __FILE__, __LINE__);
			return false;
		}
	}

}

//std::vector<Object> ANSCUSTOMDETECTOR::RunInference(const cv::Mat& input, const std::string& camera_id) {
//	std::lock_guard<std::recursive_mutex> lock(_mutex);
//	std::vector<Object> result;
//	try {
//		if (!_licenseValid) {
//			this->_logger.LogError("ANSCUSTOMDETECTOR::RunInference", "Invalid License", __FILE__, __LINE__);
//			return result;
//		}
//		if (!_isInitialized) {
//			this->_logger.LogError("ANSCUSTOMDETECTOR::RunInference", "Model is not initialized", __FILE__, __LINE__);
//			return result;
//		}
//		// Run inference
//		if (input.empty()) return result;
//		if ((input.cols < 10) || (input.rows < 10)) return result;
//		std::vector<CustomObject> customResult;
//		customResult = _customDetector->RunInference(input,camera_id);
//		for (int i = 0; i < customResult.size(); i++) {
//			Object obj;
//			obj.classId = customResult[i].classId;
//			obj.trackId = customResult[i].trackId;
//			obj.className = customResult[i].className;
//			obj.confidence = customResult[i].confidence;
//			obj.mask = customResult[i].mask;
//			obj.box = customResult[i].box;
//			obj.extraInfo = customResult[i].extraInfo;
//			obj.kps = customResult[i].kps;
//			obj.polygon = customResult[i].polygon;
//			obj.cameraId = customResult[i].cameraId;
//			//obj.attributes = customResult[i].attributes;
//			result.push_back(obj);
//		}
//		return result;
//	}
//	catch (std::exception& e) {
//		result.clear();
//		this->_logger.LogFatal("ANSCUSTOMDETECTOR::RunInference", e.what(), __FILE__, __LINE__);
//		return result;
//	}
//}