//---------------------------------------------------------------------------
// For SELMA200, 20180227, moon, 완료
//---------------------------------------------------------------------------
#include <vcl.h>
#include <inifiles.hpp>
#include <registry.hpp>
#include <tlhelp32.h>
#include <shellapi.h>
#pragma hdrstop

#include "Environment.h"
#include "MotorSetting_Form.h"
#include "TerminateWaiting_Form.h"
#include "VirtualMachine_Form.h"
#include "Bayer.h"
#include "MultiLanguage.h"

#include "Main_Form.h"
#include <iostream>
using namespace std;


#pragma package(smart_init)
#pragma link "TntStdCtrls"
#pragma link "TntExtCtrls"
#pragma link "TntGrids"

bool SimulationMode;

int InspectionKind;
int InspectionOrStudy;

TUserInfo UserInfo;
TProgramPath ProgramPath;
TMachineSetupData MachineSetupData;
TCameraMapInfo CameraMapInfo[SYSTEM_TOTAL_CAMERA_COUNT];
TSPBSystemSetupData SPBSystemSetupData[SYSTEM_SPB_MAX_COUNT];
TVariableCameraInformation VariableCameraInformation[SYSTEM_TOTAL_CAMERA_COUNT];
TThreeDCameraDefaultInformation ThreeDCameraDefaultInformation[SYSTEM_TOTAL_CAMERA_COUNT];
TUVLaserStatus UVLaser;
TNFALaserInfo NFALaserinfo;
TPcUiFlag PcUiFlag;

TProductData ProductData;
TMachineParams MachineParams;
TMachineOperationInfo MachineOperationInfo;
TTabletGradeData TabletGradeData_PC;
TTabletStudyResultData TabletStudyResultData_PC;
TSystemMonitorInfo SystemMonitorInfo;

TDSMThread *DSMThread = NULL;
TDSMInfo DSMInfo;

AnsiString LogFileName = "";
TFileStream *LogFileStream = NULL;
TProgramVersion ProgramVersion;
TComputerSystemInfo ComputerSystemInfo;
TCPBSetupInfo CPBSetupInfo;

TPCSystemHeader PCSystemHeader;
TInitialValues InitialValues;
TPCProgramOption PCProgramOption;

TTPBSystemInfo TPBSystemInfo;

TMachine Machine;
int RANGER_3D_BASE_SHUTTER_SPEED;
int RANGER_3D_BASE_SHUTTER_SPEED2;

int GlobalSD1LSFTable[MAX_MOTOR_SPEED];
int GlobalSD2LSFTable[MAX_MOTOR_SPEED];

int SYSTEM_DEFAULT_ANLOG_GAIN;

int testGlobalCameraNumber; // For SELMA200 TEST

bool bSystemStatusCheckSW = true;
bool bInitProgramAuthority = false;

int ThreeDSensorActiveStatus;
int Disk1ThreeDSensorErrorCode;
int Disk2ThreeDSensorErrorCode;

int RecentDisk1ThreeDCameraLSFValue;
int RecentDisk2ThreeDCameraLSFValue;

unsigned char DefectBayerImage[SYSTEM_CAMERA_WIDTH * SYSTEM_CAMERA_HEIGHT];

int GlobalProgramID;
bool SystemLinkCameraInfo[SYSTEM_TOTAL_CAMERA_COUNT];
AnsiString SystemCameraID[SYSTEM_TOTAL_CAMERA_COUNT];

eProductInfo MESUpDate_Product;
eParamInfo MESUpDate_Param;
eAlarmInfo MESUpDate_Alarm;
TLaserInfo RecipeInfo;
TProgramAccessAuthorityData ProgramAccessAuthorityData;

LARGE_INTEGER Frequency;
LARGE_INTEGER TotalBeginTime;
LARGE_INTEGER TotalEndtime;
LARGE_INTEGER CheckBeginTime;
LARGE_INTEGER CheckEndtime;

//---------------------------------------------------------------------------
void __fastcall Environment_Init(void)

{
	ProgramVersion.MajorVersion = PROGRAM_MAJOR_VERSION;
	ProgramVersion.MinorVersion = PROGRAM_MINOR_VERSION;
	ProgramVersion.Date = PROGRAM_RELEASE_DATE;
	ProgramVersion.Type = PROGRAM_TARGET_SYSTEM;

	UserInfo.Status = USER_STATUS_LOGOUT;

	for (int cameraIndex = 1; cameraIndex <= SYSTEM_TOTAL_CAMERA_COUNT; cameraIndex++)
	{
		SystemLinkCameraInfo[cameraIndex - 1] = true;
		if (GlobalProgramID == PROGRAM_ID_150P)
		{
			if (cameraIndex == SD1_2D_SIDE_FACE_00_CAMERA_INDEX ||
			        cameraIndex == SD1_2D_OTHER_SIDE_FACE_00_CAMERA_INDEX ||
			        cameraIndex == SD2_2D_SIDE_FACE_00_CAMERA_INDEX ||
			        cameraIndex == SD2_2D_OTHER_SIDE_FACE_00_CAMERA_INDEX)
			{
				SystemLinkCameraInfo[cameraIndex - 1] = false;
			}
		}
	}

	if (!ReadCameraID(ProgramPath.Env + "\\SystemCameraID.ini"))
	{
		//ShowMessageW(ENVIRONMENT_RETURNSTR_13);
	}

	if (!ReadCameraMapData(ProgramPath.Env + "\\SystemInfor.ini", CameraMapInfo))
	{
		ShowMessageW(ENVIRONMENT_RETURNSTR_08);
	}

	if (!ReadSPBSystemSetupData(ProgramPath.Env + "\\SystemInfor.ini", SPBSystemSetupData, CameraMapInfo))
	{
		ShowMessageW(ENVIRONMENT_RETURNSTR_08);
	}

	if (!ReadMachineSetupData(ProgramPath.Env + "\\SystemInfor.ini", MachineSetupData))
	{
		ShowMessageW(ENVIRONMENT_RETURNSTR_08);
	}

	if (!ReadMachineParams(ProgramPath.Env + "\\MachineInfor.ini", MachineParams))
	{
		ShowMessageW(ENVIRONMENT_RETURNSTR_04);
	}

	if (!ReadMachineOperationInfo(ProgramPath.Env + "\\UserInfor.ini", MachineOperationInfo, MachineSetupData))
	{
		ShowMessageW(ENVIRONMENT_RETURNSTR_11);
	}

	if (!ReadPCSystemHeader(ProgramPath.Env + "\\SystemInfor.ini"))
	{
		ShowMessageW(ENVIRONMENT_RETURNSTR_08);
	}

	if (!ReadInitialValues(ProgramPath.Env + "\\Initials.ini"))
	{
	}

	if (!ReadPCProgramOption(ProgramPath.Env + "\\UserInfor.ini", PCProgramOption))
	{
		ShowMessageW(ENVIRONMENT_RETURNSTR_11);
	}

	for (int cameraIndex = 0; cameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; cameraIndex++)
	{
		ReadCameraWhiteBalanceColorInfo(ProgramPath.Env + "\\WhiteBalanceInfo.ini", cameraIndex);
	}

	ReadDiskLineScanFrequency(ProgramPath.Env + "\\DiskLineScanFrequency.ini");
	ReadSystem2DCamAnalogGain(ProgramPath.Env + "\\SystemCameraAnalogGain.ini");

	bInitProgramAuthority = !ReadSystemUserAuthorityInformation(ProgramPath.Env + "\\SystemAuthorityInformation.ini");

	InitCommon_PC();

	if (ReadDSMInfo(ProgramPath.Env + "\\DSMInfor.ini", DSMInfo))
	{
		// start disk space manager thread
		DSMThread = new TDSMThread(true);		// create suspended
		if (DSMThread)
		{
			DSMThread->SetParams(
			    DSMInfo.ReduceTime[0], DSMInfo.ReduceTime[1], DSMInfo.ReduceTime[2],
			    DSMInfo.PrimeLotCount[0], DSMInfo.PrimeLotCount[1], DSMInfo.PrimeLotCount[2],
			    DSMInfo.PrimeLotMaxDefectCount[0], DSMInfo.PrimeLotMaxDefectCount[1], DSMInfo.PrimeLotMaxDefectCount[2],
			    DSMInfo.TrivialLotMaxDefectCount[0], DSMInfo.TrivialLotMaxDefectCount[1], DSMInfo.TrivialLotMaxDefectCount[2],
			    DSMInfo.MinDiskSpaceRatio, DSMInfo.DSMAlwaysOn, DSMInfo.MainformDiskSpaceEnabled, DSMInfo.DSMStartTime, DSMInfo.DSMEndTime);
			DSMThread->Priority = tpLower;
			DSMThread->SetDefectPath(ProgramPath.Defect);
			DSMThread->SetProductDataRoot(ProgramPath.Product);
			DSMThread->SetLogPath(ProgramPath.Log);
			DSMThread->Resume();
		}
		else
		{
			ShowMessageW(ENVIRONMENT_RETURNSTR_02);
		}
	}
	else
	{
		DSMThread = NULL;
	}

	if (!ReadComputerSystemInfo(ProgramPath.Env + "\\SystemInfor.ini", ComputerSystemInfo))
	{
		ShowMessageW(ENVIRONMENT_RETURNSTR_08);
	}

	ConnectCSVLogFile();

	CPBSetupInfo.StudySetupDataValid = false;
	CPBSetupInfo.InspectionSetupDataValid = false;
	CPBSetupInfo.GradeDataValid = false;

	for (int stepMotorIndex = 0; stepMotorIndex < MAX_STEP_MOTOR_COUNT; stepMotorIndex++)
	{
		ProductData.NCMotorPos[stepMotorIndex] = 0;
	}


	TRegIniFile *regIniFile = new TRegIniFile("Application");
	if (regIniFile)
	{
		regIniFile->RootKey = HKEY_LOCAL_MACHINE;
		regIniFile->OpenKey(PROGRAM_REGISTRY_KEY, true);

		SimulationMode = regIniFile->ReadBool("SYSTEM", "SIM MODE", false);
		CommSimulationMode = SimulationMode;
		if (SimulationMode)
			VirtualMachineForm = new TVirtualMachineForm(Application);
		if (SimulationMode)
			Machine.SetSimulationMode(true);
		delete regIniFile;
	}

	ThreeDSensorActiveStatus = THREED_SENSOR_OFF;

	Disk1ThreeDSensorErrorCode = 0;
	Disk2ThreeDSensorErrorCode = 0;

	RecentDisk1ThreeDCameraLSFValue = -1;
	RecentDisk2ThreeDCameraLSFValue = -1;
}
//---------------------------------------------------------------------------
void __fastcall Environment_Destroy(void)
{
  if(ProgramPath.Root != "")
  {
    WriteMachineSetupData(ProgramPath.Env + "\\SystemInfor.ini", MachineSetupData);
  	WriteMachineParams(ProgramPath.Env + "\\MachineInfor.ini", MachineParams);
  	WriteMachineOperationInfo(ProgramPath.Env + "\\UserInfor.ini", MachineOperationInfo);
  }

	if (DSMThread)
	{
		DSMThread->Priority = tpHigher;
		DSMThread->Terminate();
		DSMThread->Resume();
		TTerminateWaitingForm *waitingForm = new TTerminateWaitingForm(NULL);
		waitingForm->Show();
		Application->ProcessMessages();
		DSMThread->WaitFor();
		waitingForm->Close();
		delete waitingForm;
		delete DSMThread;
		DSMThread = NULL;
	}

	DisconnectCSVLogFile();
}
//---------------------------------------------------------------------------

bool __fastcall SendSPBCaptureSetup_Multi(TProductData *pProductData, unsigned int globalCamMask, float tabletHalfLength, int *shutterSpeedList,
        int disk1TargetSpeed, int disk1BaseSpeed, int disk2TargetSpeed, int disk2BaseSpeed, int TestSubsamplingMode, bool bCalib, int frameBufferCount, int triggerFreq_3D)
{
	bool returnValue = true;
	bool UseTestSubsamplingMode = false;
	unsigned char camMask[SYSTEM_SPB_MAX_COUNT];
	unsigned short shutterSpeed[SYSTEM_SPB_MAX_COUNT][SYSTEM_SPB_CAMERA_COUNT];
	unsigned short shutterDelay[SYSTEM_SPB_MAX_COUNT][SYSTEM_SPB_CAMERA_COUNT];
	unsigned short triggerFreq[SYSTEM_SPB_MAX_COUNT][SYSTEM_SPB_CAMERA_COUNT];
	unsigned char subsamplingMode[SYSTEM_SPB_MAX_COUNT][SYSTEM_SPB_CAMERA_COUNT];
	TCaptureSetupData captureSetupData;
	captureSetupData.CameraMask = 0;
	captureSetupData.ContainParams = 0;

	int defaultTriggerFreq;

	if (pProductData->SubSamplingMode != TestSubsamplingMode)
		UseTestSubsamplingMode = true;

	for (int spbIndex = 0; spbIndex < MachineSetupData.IPB_BoardCount; spbIndex++)
	{
		camMask[spbIndex] = 0;
	}

	for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
	{
		if (globalCamMask & (0x0001 << globalCameraIndex))
		{
			int spbIndex = CameraMapInfo[globalCameraIndex].SPBIndex;
			int camIndex = CameraMapInfo[globalCameraIndex].CamIndex;
			camMask[spbIndex] |= (0x0001 << camIndex);
			if (shutterSpeedList == NULL)
			{
				shutterSpeed[spbIndex][camIndex] = InitialValues.ShutterSpeed[globalCameraIndex];
			}
			else
			{
				shutterSpeed[spbIndex][camIndex] = shutterSpeedList[globalCameraIndex];
			}
		}
	}

	for (int captureIndex = 0; captureIndex < SYSTEM_MACHINE_CAPTURE_COUNT; captureIndex++)
	{
		for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
		{
			if (CameraMapInfo[globalCameraIndex].CameraInspectPosition == CAMERA_POSITION_3D)
			{
				int spbIndex = CameraMapInfo[globalCameraIndex].SPBIndex;
				int camIndex = CameraMapInfo[globalCameraIndex].CamIndex;
				subsamplingMode[spbIndex][camIndex] = RESOLUTION_NORMAL_QUALITY;
			}
			else
			{
				int spbIndex = CameraMapInfo[globalCameraIndex].SPBIndex;
				int camIndex = CameraMapInfo[globalCameraIndex].CamIndex;
				if (UseTestSubsamplingMode)
					subsamplingMode[spbIndex][camIndex] = TestSubsamplingMode;
				else
					subsamplingMode[spbIndex][camIndex] = pProductData->SubSamplingMode;
			}

			if (globalCameraIndex + 1 < HALF_INSPECTION_CAMERA_INDEX)
				defaultTriggerFreq = RANGER_3D_BASE_SHUTTER_SPEED;
			else
				defaultTriggerFreq = RANGER_3D_BASE_SHUTTER_SPEED2;

			bool ApplyLSFTable = false;
			if (PCProgramOption.ApplyLSFTableSW && bCalib == false)
			{
				if (globalCameraIndex + 1 < HALF_INSPECTION_CAMERA_INDEX)
				{
					if (GlobalSD1LSFTable[disk1TargetSpeed])
					{
						defaultTriggerFreq = GlobalSD1LSFTable[disk1TargetSpeed];
						ApplyLSFTable = true;
					}
				}
				else
				{
					if (GlobalSD2LSFTable[disk2TargetSpeed])
					{
						defaultTriggerFreq = GlobalSD2LSFTable[disk2TargetSpeed];
						ApplyLSFTable = true;
					}
				}
			}

			if (MachineSetupData.MachineCaptureInfo.CamMask[captureIndex] & (0x0001 << globalCameraIndex))
			{
				int spbIndex = CameraMapInfo[globalCameraIndex].SPBIndex;
				int camIndex = CameraMapInfo[globalCameraIndex].CamIndex;

				if (captureIndex < 3)
				{
					if (CameraMapInfo[globalCameraIndex].CameraInspectPosition == CAMERA_POSITION_3D) // 3d camera
					{
						shutterDelay[spbIndex][camIndex] = MachineSetupData.MachineCaptureInfo.IlluminatorDelay[captureIndex]	* disk1TargetSpeed / disk1BaseSpeed;
						if (triggerFreq_3D == 0)
						{
							triggerFreq[spbIndex][camIndex] = defaultTriggerFreq * disk1TargetSpeed / disk1BaseSpeed;

							if (ApplyLSFTable)
							{
								triggerFreq[spbIndex][camIndex] = defaultTriggerFreq;
							}
						}
						else
						{
							triggerFreq[spbIndex][camIndex] = triggerFreq_3D;
						}
					}
					else
					{

						if (0)//MachineSetupData.LasercomplexerInfo.Laser_complexer_Enable)
						{
							shutterDelay[spbIndex][camIndex] = (MachineSetupData.MachineCaptureInfo.IlluminatorDelay[captureIndex]-(pProductData->StudiedSensor1Length/2)) * disk1TargetSpeed / disk1BaseSpeed;
						}
						else
						{
							shutterDelay[spbIndex][camIndex] = (MachineSetupData.MachineCaptureInfo.IlluminatorDelay[captureIndex]) * disk1TargetSpeed / disk1BaseSpeed;
						
						}
						triggerFreq[spbIndex][camIndex] = defaultTriggerFreq * disk1TargetSpeed / disk1BaseSpeed;
					}
				}
				else
				{
					if (CameraMapInfo[globalCameraIndex].CameraInspectPosition == CAMERA_POSITION_3D) // 3d camera
					{
						shutterDelay[spbIndex][camIndex] = MachineSetupData.MachineCaptureInfo.IlluminatorDelay[captureIndex]	* disk2TargetSpeed / disk2BaseSpeed;
						if (triggerFreq_3D == 0)
						{
							triggerFreq[spbIndex][camIndex] = defaultTriggerFreq * disk2TargetSpeed / disk2BaseSpeed;

							if (ApplyLSFTable)
							{
								triggerFreq[spbIndex][camIndex] = defaultTriggerFreq;
							}
						}
						else
						{
							triggerFreq[spbIndex][camIndex] = triggerFreq_3D;
						}
					}
					else
					{
	
						if (0)//MachineSetupData.LasercomplexerInfo.Laser_complexer_Enable)
						{
							shutterDelay[spbIndex][camIndex] = (MachineSetupData.MachineCaptureInfo.IlluminatorDelay[captureIndex]-(pProductData->StudiedSensor2Length/2)) * disk2TargetSpeed / disk2BaseSpeed;
						}
						else
						{
							shutterDelay[spbIndex][camIndex] = (MachineSetupData.MachineCaptureInfo.IlluminatorDelay[captureIndex]) * disk2TargetSpeed / disk2BaseSpeed;
						
						}
						triggerFreq[spbIndex][camIndex] = defaultTriggerFreq * disk2TargetSpeed / disk2BaseSpeed;
					}
				}
			}
		}
	}

	for (int spbIndex = 0; spbIndex < MachineSetupData.IPB_BoardCount; spbIndex++)
	{
		if (!Comm_IsConnected(COMM_SPB + spbIndex))
			continue;
		captureSetupData.CaptureType = CAPTURE_TYPE_FULL_CAPTURE;
		captureSetupData.CaptureMode = CAPTURE_MODE_DEFAULT;
		captureSetupData.FrameBufferCount = frameBufferCount;
		for (int camIndex = 0; camIndex < SYSTEM_SPB_CAMERA_COUNT; camIndex++)
		{
			captureSetupData.ShutterSpeed[camIndex] = shutterSpeed[spbIndex][camIndex];
			captureSetupData.ShutterDelay[camIndex] = shutterDelay[spbIndex][camIndex];
			captureSetupData.TriggerFreq[camIndex] = triggerFreq[spbIndex][camIndex];
			captureSetupData.CameraMask = camMask[spbIndex];
			captureSetupData.SubsamplingMode[camIndex] = subsamplingMode[spbIndex][camIndex];
		}
		captureSetupData.TabletType = pProductData->TabletType;
		captureSetupData.SensorLength= pProductData->StudiedSensor1Length;
		if (!Comm_Request(COMM_SPB + spbIndex, CMD_CAPTURE_SETUP, &captureSetupData, sizeof(TCaptureSetupData),
		                  NULL, 0))
		{
			returnValue = false;
		}
	}

	if (0)//MachineSetupData.LasercomplexerInfo.Laser_complexer_Enable)
	{
		// CAPTURE_TYPE_SINGLE_CAPTURE 모드에서는 함수가 호출되어서는 안됨
		SendThreeDCameraSensorOnOffSignal(1, RecentDisk1ThreeDCameraLSFValue, RecentDisk2ThreeDCameraLSFValue);
	}

	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall EnabledThreeDLaserSensor(int globalCameraIndex, int LSFValue, int calibrationMode)
{
	bool returnValue = true;
	int spbIndex, camIndex;
	int data[2];

	spbIndex = CameraMapInfo[globalCameraIndex].SPBIndex;
	camIndex = CameraMapInfo[globalCameraIndex].CamIndex;

	data[0] = camIndex;
	data[1] = LSFValue;
	data[2] = calibrationMode;

	if (!Comm_Request(COMM_SPB + spbIndex, CMD_SPB_THREED_SENSORMODE_ON, &data, sizeof(int) * 3, NULL, 0))
	{
		returnValue = false;
	}

	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall DisabledThreeDLaserSensor(int globalCameraIndex)
{
	bool returnValue = true;
	int spbIndex, camIndex;
	int data[2];

	spbIndex = CameraMapInfo[globalCameraIndex].SPBIndex;

	if (!Comm_Request(COMM_SPB + spbIndex, CMD_SPB_THREED_SENSORMODE_OFF))
	{
		returnValue = false;
	}

	return returnValue;
}
//---------------------------------------------------------------------------
void __fastcall SendThreeDCameraSensorOnOffSignal(int SensorOn, int Disk1LSFValue, int Disk2LSFValue)
{
	// 카메라 셋업이 진행된 기계 동작 시 해당 함수 호출
	bool bError;

	int SD1ThreeDCameraSPBIndex, SD2ThreeDCameraSPBIndex;
	SD1ThreeDCameraSPBIndex = CameraMapInfo[SD1_3D_FRONT_FACE_CAMERA_INDEX - 1].SPBIndex;
	SD2ThreeDCameraSPBIndex = CameraMapInfo[SD2_3D_FRONT_FACE_CAMERA_INDEX - 1].SPBIndex;

	Disk1ThreeDSensorErrorCode = THREED_SENSOR_ERROR_CODE_GOOD;
	Disk2ThreeDSensorErrorCode = THREED_SENSOR_ERROR_CODE_GOOD;

	bError = false;

	if (!Comm_IsConnected(COMM_SPB + SD1ThreeDCameraSPBIndex))
	{
		bError = false;
		Disk1ThreeDSensorErrorCode = THREED_SENSOR_ERROR_CODE_BRD_DISCONNECTED;
	}
	else if (CameraMapInfo[SD1_3D_FRONT_FACE_CAMERA_INDEX - 1].CameraInspectPosition != CAMERA_POSITION_3D)
	{
		bError = true;
		Disk1ThreeDSensorErrorCode = THREED_SENSOR_ERROR_CODE_INVALID_MAPPING;
	}
	else if (CameraMapInfo[SD1_3D_FRONT_FACE_CAMERA_INDEX - 1].CameraInspectPosition == CAMERA_POSITION_DISCONNECT || SystemLinkCameraInfo[SD1_3D_FRONT_FACE_CAMERA_INDEX - 1] == 0)
	{
		bError = true;
		Disk1ThreeDSensorErrorCode = THREED_SENSOR_ERROR_CODE_CAMERA_DISCONNECTED;
	}

	/*
	if (!Comm_IsConnected(COMM_SPB + SD2ThreeDCameraSPBIndex))
	{
	  bError = true;
	  Disk2ThreeDSensorErrorCode = THREED_SENSOR_ERROR_CODE_BRD_DISCONNECTED;
	}
	else if (CameraMapInfo[SD2_3D_FRONT_FACE_CAMERA_INDEX - 1].CameraInspectPosition != CAMERA_POSITION_3D)
	{
	  bError = true;
	  Disk2ThreeDSensorErrorCode = THREED_SENSOR_ERROR_CODE_INVALID_MAPPING;
	}
	else if (CameraMapInfo[SD2_3D_FRONT_FACE_CAMERA_INDEX - 1].CameraInspectPosition == CAMERA_POSITION_DISCONNECT)
	{
	  bError = true;
	  Disk2ThreeDSensorErrorCode = THREED_SENSOR_ERROR_CODE_CAMERA_DISCONNECTED;
	}
	*/

	if (!bError)
	{
		if (SensorOn)
		{
			EnabledThreeDLaserSensor(SD1_3D_FRONT_FACE_CAMERA_INDEX - 1, Disk1LSFValue, THREED_SENSOR_NONE_MODE);
			EnabledThreeDLaserSensor(SD2_3D_FRONT_FACE_CAMERA_INDEX - 1, Disk2LSFValue, THREED_SENSOR_NONE_MODE);

			ThreeDSensorActiveStatus = THREED_SENSOR_ON;
		}
		else
		{
			ThreeDSensorActiveStatus = THREED_SENSOR_OFF;

			Disk1ThreeDSensorErrorCode = THREED_SENSOR_ERROR_CODE_GOOD;
			Disk2ThreeDSensorErrorCode = THREED_SENSOR_ERROR_CODE_GOOD;

			RecentDisk1ThreeDCameraLSFValue = -1;
			RecentDisk2ThreeDCameraLSFValue = -1;
		}
	}
	else
	{
		ThreeDSensorActiveStatus = THREED_SENSOR_OFF;

		RecentDisk1ThreeDCameraLSFValue = -1;
		RecentDisk2ThreeDCameraLSFValue = -1;
	}
}
//---------------------------------------------------------------------------
AnsiString __fastcall GetDefectDataPath(AnsiString productCode)
{
	return (ProgramPath.Defect + "\\" + productCode);
}
//---------------------------------------------------------------------------
AnsiString __fastcall GetDefectDataPath(AnsiString productCode, AnsiString lotName)
{
	return (ProgramPath.Defect + "\\" + productCode + "\\" + lotName);
}
//---------------------------------------------------------------------------
AnsiString __fastcall GetProductImagePath(void)
{
	return (ProgramPath.Product + "\\" + ProductData.ProductCode + "\\Image");
}
//---------------------------------------------------------------------------
AnsiString __fastcall GetProductDataFileName(AnsiString productCode)
{
	return (ProgramPath.Product + "\\" + productCode + "\\" + productCode + ".dat");
}
//---------------------------------------------------------------------------
AnsiString __fastcall GetUserMachineEnvDataFileName(void)
{
	return (ProgramPath.Env + "\\UserMachineInfor.ini");
}
//---------------------------------------------------------------------------
void __fastcall SaveDSMInfo(void)
{
	WriteDSMInfo(ProgramPath.Env + "\\DSMInfor.ini", DSMInfo);
}
//---------------------------------------------------------------------------
void __fastcall ConnectCSVLogFile(void)
{
	unsigned short year;
	unsigned short month;
	unsigned short day;
	Now().DecodeDate(&year, &month, &day);
	int logFileIndex = 1;
	ForceDirectories(ProgramPath.Log + "\\CSV Log");
	AnsiString lastFileName = "";
	AnsiString newFileName = "";
	while (true)
	{
		AnsiString dateStr = Format("%.4d-%.2d-%.2d-%.4d", ARRAYOFCONST((year, month, day, logFileIndex)));
		newFileName = ProgramPath.Log + "\\CSV Log\\" + dateStr + ".clg";
		if (!FileExists(newFileName))
		{
			break;
		}
		else
		{
			lastFileName = newFileName;
			logFileIndex++;
		}
	}
	if (lastFileName == "")
	{
		TCSVLogFileHeader *csvLogFileHeader = new TCSVLogFileHeader(Now().Val);
		LogFileStream = new TFileStream(newFileName, fmCreate | fmShareDenyWrite);
		csvLogFileHeader->SaveToFileStream(LogFileStream);
		LogFileName = newFileName;
		delete csvLogFileHeader;
	}
	else
	{
		LogFileStream = NULL;
		TCSVLogFileHeader *csvLogFileHeader = NULL;

		try
		{
			LogFileStream = new TFileStream(lastFileName, fmOpenReadWrite);
			//LogFileStream = new TFileStream(lastFileName, fmShareDenyNone);
			csvLogFileHeader = new TCSVLogFileHeader(Now().Val);
			csvLogFileHeader->LoadFromFileStream(LogFileStream);
			LogFileName = lastFileName;
			delete csvLogFileHeader;
			csvLogFileHeader = NULL;
			LogFileStream->Seek(LogFileStream->Size, soFromBeginning);
		}
		catch (CSVLogException &ec)
		{
			ShowMessageW(ec.Message);
			if (LogFileStream)
				delete LogFileStream;
			if (csvLogFileHeader)
				delete csvLogFileHeader;

			TCSVLogFileHeader *csvLogFileHeader = new TCSVLogFileHeader(Now().Val);
			LogFileStream = new TFileStream(newFileName, fmCreate | fmShareDenyWrite);
			csvLogFileHeader->SaveToFileStream(LogFileStream);
			LogFileName = newFileName;
			delete csvLogFileHeader;
			csvLogFileHeader = NULL;
		}
		catch (Exception &ec)
		{
			ShowMessageW(ec.Message);
		}
	}
}
//---------------------------------------------------------------------------
void __fastcall DisconnectCSVLogFile(void)
{
	if (LogFileStream)
	{
		delete LogFileStream;
		LogFileStream = NULL;
	}
}
//---------------------------------------------------------------------------
void __fastcall StopCSVLogFile(void)
{
	if (LogFileStream)
	{
		delete LogFileStream;
		LogFileStream = NULL;
	}
}
//---------------------------------------------------------------------------
void __fastcall ResumeCSVLogFile(void)
{
	LogFileStream = new TFileStream(LogFileName, fmOpenReadWrite);
	LogFileStream->Seek(LogFileStream->Size, soFromBeginning);
}
//---------------------------------------------------------------------------
bool __fastcall AddCSVEventLog(ECSVEvent event, unsigned char *params, int paramSize)
{
	bool returnValue = true;
	try
	{
		TCSVEventLog *csvEventLog = new TCSVEventLog(event);
		csvEventLog->SetParams(params, paramSize);
		/*
		if (event == ECSV_EVENT_LOGIN || event == ECSV_EVENT_LOGOUT)
		{
		csvEventLog->SetParams(params, paramSize);
		//csvEventLog->SetLogInfoParam(param);
		}
		*/
		csvEventLog->SaveToFileStream(LogFileStream);
		delete csvEventLog;
	}
	catch (Exception &ec)
	{
		returnValue = false;
		ShowMessageW(ec.Message);
	}
	catch (...)
	{
		returnValue = false;
		ShowMessageW(ENVIRONMENT_RETURNSTR_09);
	}

	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall AddCSVActionLog(ECSVAction action, AnsiString userName, AnsiString productName, unsigned char *params, int paramSize)
{
	bool returnValue = true;
	try
	{
		TCSVActionLog *csvActionLog = new TCSVActionLog(action);
		csvActionLog->SetParams(userName.c_str(), productName.c_str(), params, paramSize);
		csvActionLog->SaveToFileStream(LogFileStream);
		delete csvActionLog;
	}
	catch (Exception &ec)
	{
		returnValue = false;
		ShowMessageW(ec.Message);
	}
	catch (...)
	{
		returnValue = false;
		ShowMessageW(ENVIRONMENT_RETURNSTR_09);
	}

	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall ReadComputerSystemInfo(AnsiString fileName, TComputerSystemInfo &computerSystemInfo)
{
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		computerSystemInfo.InactivityLogoutEnabled = iniFile->ReadBool("Computer System Info", "Inactivity Logout Enabled", false);
		computerSystemInfo.InactivityTimeout = iniFile->ReadInteger("Computer System Info", "Inactivity Timeout", 5);
		computerSystemInfo.PasswordExpirationEnabled = iniFile->ReadBool("Computer System Info", "Password Expiration Enabled", false);
		computerSystemInfo.PasswordExpirationTime = iniFile->ReadInteger("Computer System Info", "Password Expiration Time", 60);
		computerSystemInfo.PasswordMinLength = iniFile->ReadInteger("Computer System Info", "Password Min Length", 1);
		computerSystemInfo.FirstLoginChangePW = iniFile->ReadInteger("Computer System Info", "FirstLoginChangePW", false);
		computerSystemInfo.PasswordFailAvailableCount = iniFile->ReadInteger("Computer System Info", "PasswordFailAvailableCount", 3);
		delete iniFile;
	}
	else
	{
		computerSystemInfo.InactivityLogoutEnabled = false;
		computerSystemInfo.InactivityTimeout = 5;
		computerSystemInfo.PasswordExpirationEnabled = false;
		computerSystemInfo.PasswordExpirationTime = 60;
		computerSystemInfo.PasswordMinLength = 1;
		computerSystemInfo.FirstLoginChangePW = false;
		computerSystemInfo.PasswordFailAvailableCount = 3;

		return false;
	}
	return true;
}
//---------------------------------------------------------------------------
void __fastcall WriteComputerSystemInfo(AnsiString fileName, TComputerSystemInfo &computerSystemInfo)
{
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		iniFile->WriteBool("Computer System Info", "Inactivity Logout Enabled", computerSystemInfo.InactivityLogoutEnabled);
		iniFile->WriteInteger("Computer System Info", "Inactivity Timeout", computerSystemInfo.InactivityTimeout);
		iniFile->WriteBool("Computer System Info", "Password Expiration Enabled", computerSystemInfo.PasswordExpirationEnabled);
		iniFile->WriteInteger("Computer System Info", "Password Expiration Time", computerSystemInfo.PasswordExpirationTime);
		iniFile->WriteInteger("Computer System Info", "Password Min Length", computerSystemInfo.PasswordMinLength);
		iniFile->WriteInteger("Computer System Info", "FirstLoginChangePW", computerSystemInfo.FirstLoginChangePW);
		iniFile->WriteInteger("Computer System Info", "PasswordFailAvailableCount", computerSystemInfo.PasswordFailAvailableCount);


		delete iniFile;
	}
}
//---------------------------------------------------------------------------
bool __fastcall BackupProductData(EProductDataBackupReason proudctDataBackupReason)
{
	AnsiString fileName = GetProductDataFileName(ProductData.ProductCode);
	AnsiString backupPath = ProgramPath.Product + "\\" + ProductData.ProductCode + "\\Backup";
	if (!DirectoryExists(backupPath))
	{
		ForceDirectories(backupPath);
	}
	// get backup file name
	int backupFileIndex = 0;
	AnsiString backupFileName = "";
	while (true)
	{
		backupFileIndex++;
		backupFileName = backupPath + "\\Backup" + IntToStr(backupFileIndex) + ".dat";
		if (!FileExists(backupFileName))
			break;
	}
	CopyFileA(fileName.c_str(), backupFileName.c_str(), FALSE);

	bool tabletInfoModified, machineInfoModified, inspectionInfoModified;
	GetDataModificationInfo(ProductData, &tabletInfoModified, &machineInfoModified, &inspectionInfoModified);
	TIniFile *iniFile = new TIniFile(backupFileName);
	if (iniFile)
	{
		iniFile->WriteFloat("Backup Info", "Backup Date", Now().Val);
		iniFile->WriteInteger("Backup Info", "Backup Reason", proudctDataBackupReason);
		iniFile->WriteBool("Backup Info", "Tablet Info Modified", tabletInfoModified);
		iniFile->WriteBool("Backup Info", "Machine Info Modified", machineInfoModified);
		iniFile->WriteBool("Backup Info", "Inspection Info Modified", inspectionInfoModified);
		iniFile->WriteString("Backup Info", "Operator Name", UserInfo.Name);
		delete iniFile;
	}
	return true;
}
//---------------------------------------------------------------------------
void __fastcall GetDataModificationInfo(TProductData DestProductData, bool *tabletInfoModified, bool *machineInfoModified, bool *inspectionInfoModified)
{
	bool tiModified = false, miModified = false, iiModified = false;
	TProductData tempProductData;
	AnsiString fileName = GetProductDataFileName(DestProductData.ProductCode);
	ReadProductData(fileName, tempProductData, MachineParams, MachineSetupData);

	if (tempProductData.TabletType != DestProductData.TabletType)
		tiModified = true;
	if (tempProductData.TabletShape != DestProductData.TabletShape)
		tiModified = true;
	if (tempProductData.TabletLength != DestProductData.TabletLength)
		tiModified = true;
	if (tempProductData.TabletWidth != DestProductData.TabletWidth)
		tiModified = true;
	if (tempProductData.TabletThick != DestProductData.TabletThick)
		tiModified = true;
	if (tempProductData.TabletSideThick != DestProductData.TabletSideThick)
		tiModified = true;
	if (tempProductData.EngraveType != DestProductData.EngraveType)
		tiModified = true;
	if (tempProductData.EngravePos != DestProductData.EngravePos)
		tiModified = true;
	if (tempProductData.TabletColorCode != DestProductData.TabletColorCode)
		tiModified = true;
	if (tempProductData.PrintColorCode != DestProductData.PrintColorCode)
		tiModified = true;
	if (tempProductData.PlateTablet != DestProductData.PlateTablet)
		tiModified = true;
	if (tempProductData.TabletLayerCount != DestProductData.TabletLayerCount)
		tiModified = true;
	if (tempProductData.DivisionLineInfo != DestProductData.DivisionLineInfo)
		tiModified = true;
	if (tempProductData.SubSamplingMode != DestProductData.SubSamplingMode)
		tiModified = true;


	for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
	{
		if (tempProductData.BoundaryLeft[globalCameraIndex] != DestProductData.BoundaryLeft[globalCameraIndex])
			iiModified = true;
		if (tempProductData.BoundaryTop[globalCameraIndex] != DestProductData.BoundaryTop[globalCameraIndex])
			iiModified = true;
		if (tempProductData.BoundaryRight[globalCameraIndex] != DestProductData.BoundaryRight[globalCameraIndex])
			iiModified = true;
		if (tempProductData.BoundaryBottom[globalCameraIndex] != DestProductData.BoundaryBottom[globalCameraIndex])
			iiModified = true;
		if (tempProductData.ShutterSpeed[globalCameraIndex] != DestProductData.ShutterSpeed[globalCameraIndex])
			iiModified = true;
		if (tempProductData.ThresholdFor3D[globalCameraIndex] != DestProductData.ThresholdFor3D[globalCameraIndex])
			iiModified = true;
	}

	if (tempProductData.MachineRunOption.MaxSpeedTrainingMode != DestProductData.MachineRunOption.MaxSpeedTrainingMode)
		miModified = true;
	if (tempProductData.MachineRunOption.ManualMaxSpeed != DestProductData.MachineRunOption.ManualMaxSpeed)
		miModified = true;
	if (tempProductData.MachineRunOption.ManualModeSensorIndex != DestProductData.MachineRunOption.ManualModeSensorIndex)
		miModified = true;
	if (tempProductData.MachineRunOption.ManualModeSensorActiveRatio != DestProductData.MachineRunOption.ManualModeSensorActiveRatio)
		miModified = true;
	if (tempProductData.MachineRunOption.ManualLimitSpeed != DestProductData.MachineRunOption.ManualLimitSpeed)
		miModified = true;
	if (tempProductData.MachineRunOption.ManualModeLimitSensorIndex != DestProductData.MachineRunOption.ManualModeLimitSensorIndex)
		miModified = true;
	if (tempProductData.MachineRunOption.ManualModeLimitSensorActiveRatio != DestProductData.MachineRunOption.ManualModeLimitSensorActiveRatio)
		miModified = true;
	if (tempProductData.MachineRunOption.EmptySensorActiveRatio != DestProductData.MachineRunOption.EmptySensorActiveRatio)
		miModified = true;
	if (tempProductData.MachineRunOption.FullSensorActiveRatio != DestProductData.MachineRunOption.FullSensorActiveRatio)
		miModified = true;
	if (tempProductData.MachineRunOption.StartSpeed != DestProductData.MachineRunOption.StartSpeed)
		miModified = true;
	if (tempProductData.MachineRunOption.SuctionDisk1InverterSpeed != DestProductData.MachineRunOption.SuctionDisk1InverterSpeed)
		miModified = true;
	if (tempProductData.MachineRunOption.SuctionDisk2InverterSpeed != DestProductData.MachineRunOption.SuctionDisk2InverterSpeed)
		miModified = true;
	if (tempProductData.MachineRunOption.AirKnifeSpeed != DestProductData.MachineRunOption.AirKnifeSpeed)
		miModified = true;
	if (tempProductData.StudiedSensor1Length != DestProductData.StudiedSensor1Length)
		miModified = true;
	if (tempProductData.StudiedSensor2Length != DestProductData.StudiedSensor2Length)
		miModified = true;
	if (tempProductData.StudiedSensor3Length != DestProductData.StudiedSensor3Length)
		miModified = true;
	if (tempProductData.StudiedSensorIntervalA != DestProductData.StudiedSensorIntervalA)
		miModified = true;
	if (tempProductData.StudiedSensorIntervalB != DestProductData.StudiedSensorIntervalB)
		miModified = true;

	for (int stepMotorIndex = 0; stepMotorIndex < MAX_STEP_MOTOR_COUNT; stepMotorIndex++)
	{
		if (tempProductData.NCMotorPos[stepMotorIndex] != DestProductData.NCMotorPos[stepMotorIndex])
			miModified = true;
	}


	*tabletInfoModified = tiModified;
	*machineInfoModified = miModified;
	*inspectionInfoModified = iiModified;
}
//---------------------------------------------------------------------------
bool __fastcall ProductDataModified(void)
{
	bool bModified = false;
	TProductData tempProductData;
	AnsiString fileName = GetProductDataFileName(ProductData.ProductCode);
	ReadProductData(fileName, tempProductData, MachineParams, MachineSetupData);

	if (tempProductData.TabletType != ProductData.TabletType)
		return true;
	if (tempProductData.TabletType != ProductData.TabletType)
		return true;
	if (tempProductData.TabletShape != ProductData.TabletShape)
		return true;
	if (tempProductData.TabletLength != ProductData.TabletLength)
		return true;
	if (tempProductData.TabletWidth != ProductData.TabletWidth)
		return true;
	if (tempProductData.TabletThick != ProductData.TabletThick)
		return true;
	if (tempProductData.TabletSideThick != ProductData.TabletSideThick)
		return true;
	if (tempProductData.EngraveType != ProductData.EngraveType)
		return true;
	if (tempProductData.EngravePos != ProductData.EngravePos)
		return true;
	//	if (tempProductData.PrintBrightness != ProductData.PrintBrightness) return true;
	if (tempProductData.TabletColorCode != ProductData.TabletColorCode)
		return true;
	if (tempProductData.PrintColorCode != ProductData.PrintColorCode)
		return true;
	//int MotorSpeedList[MAX_SERVO_MOTOR_COUNT][MOTOR_SPEED_STEP_COUNT_FOR_PRODUCT];
	//int ProductionCount;
	if (tempProductData.PlateTablet != ProductData.PlateTablet)
		return true;
	if (tempProductData.TabletLayerCount != ProductData.TabletLayerCount)
		return true;
	if (tempProductData.DivisionLineInfo != ProductData.DivisionLineInfo)
		return true;

	for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
	{
		if (tempProductData.BoundaryLeft[globalCameraIndex] != ProductData.BoundaryLeft[globalCameraIndex])
			return true;
		if (tempProductData.BoundaryTop[globalCameraIndex] != ProductData.BoundaryTop[globalCameraIndex])
			return true;
		if (tempProductData.BoundaryRight[globalCameraIndex] != ProductData.BoundaryRight[globalCameraIndex])
			return true;
		if (tempProductData.BoundaryBottom[globalCameraIndex] != ProductData.BoundaryBottom[globalCameraIndex])
			return true;
		if (tempProductData.BoundaryLeft[globalCameraIndex] != ProductData.BoundaryLeft[globalCameraIndex])
			return true;
		if (tempProductData.ShutterSpeed[globalCameraIndex] != ProductData.ShutterSpeed[globalCameraIndex])
			return true;
		if (tempProductData.ThresholdFor3D[globalCameraIndex] != ProductData.ThresholdFor3D[globalCameraIndex])
			return true;
	}

	if (tempProductData.MachineRunOption.MaxSpeedTrainingMode != ProductData.MachineRunOption.MaxSpeedTrainingMode)
		return true;
	if (tempProductData.MachineRunOption.ManualMaxSpeed != ProductData.MachineRunOption.ManualMaxSpeed)
		return true;
	if (tempProductData.MachineRunOption.ManualModeSensorIndex != ProductData.MachineRunOption.ManualModeSensorIndex)
		return true;
	if (tempProductData.MachineRunOption.ManualModeSensorActiveRatio != ProductData.MachineRunOption.ManualModeSensorActiveRatio)
		return true;
	if (tempProductData.MachineRunOption.ManualLimitSpeed != ProductData.MachineRunOption.ManualLimitSpeed)
		return true;
	if (tempProductData.MachineRunOption.ManualModeLimitSensorIndex != ProductData.MachineRunOption.ManualModeLimitSensorIndex)
		return true;
	if (tempProductData.MachineRunOption.ManualModeLimitSensorActiveRatio != ProductData.MachineRunOption.ManualModeLimitSensorActiveRatio)
		return true;
	//	if (tempProductData.MachineRunOption.EmptySensorIndex != ProductData.MachineRunOption.EmptySensorIndex) return true;
	if (tempProductData.MachineRunOption.EmptySensorActiveRatio != ProductData.MachineRunOption.EmptySensorActiveRatio)
		return true;
	//	if (tempProductData.MachineRunOption.FullSensorIndex != ProductData.MachineRunOption.FullSensorIndex) return true;
	if (tempProductData.MachineRunOption.FullSensorActiveRatio != ProductData.MachineRunOption.FullSensorActiveRatio)
		return true;
	if (tempProductData.MachineRunOption.StartSpeed != ProductData.MachineRunOption.StartSpeed)
		return true;
	if (tempProductData.MachineRunOption.SuctionDisk1InverterSpeed != ProductData.MachineRunOption.SuctionDisk1InverterSpeed)
		return true;
	if (tempProductData.MachineRunOption.SuctionDisk2InverterSpeed != ProductData.MachineRunOption.SuctionDisk2InverterSpeed)
		return true;
	if (tempProductData.MachineRunOption.AirKnifeSpeed != ProductData.MachineRunOption.AirKnifeSpeed)
		return true;
	if (tempProductData.StudiedSensor1Length != ProductData.StudiedSensor1Length)
		return true;
	if (tempProductData.StudiedSensor2Length != ProductData.StudiedSensor2Length)
		return true;
	//sjm add 깨진정제
	if (tempProductData.StudiedSensor3Length != ProductData.StudiedSensor3Length)
		return true;
	if (tempProductData.StudiedSensorIntervalA != ProductData.StudiedSensorIntervalA)
		return true;
	if (tempProductData.StudiedSensorIntervalB != ProductData.StudiedSensorIntervalB)
		return true;

	for (int stepMotorIndex = 0; stepMotorIndex < MAX_STEP_MOTOR_COUNT; stepMotorIndex++)
	{
		if (tempProductData.NCMotorPos[stepMotorIndex] != ProductData.NCMotorPos[stepMotorIndex])
			return true;
	}

	return bModified;
}
//---------------------------------------------------------------------------
bool __fastcall ReadPCSystemHeader(AnsiString fileName)
{
	if (!FileExists(fileName))
	{
		return false;
	}

	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		PCSystemHeader.TargetHCBDataRev = TARGET_HCB_PROGRAM_REV;
		PCSystemHeader.TargetSPBDataRev = TARGET_SPB_PROGRAM_REV;
		PCSystemHeader.TargetProjectName = PROJECT_NAME_ELMA_100;
		PCSystemHeader.TargetMachineName = iniFile->ReadString("Machine Info", "Machine Name", "UNKNOWN");

		delete iniFile;
	}

	return true;
}
//---------------------------------------------------------------------------
void __fastcall WritePCSystemHeader(AnsiString fileName)
{
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		iniFile->WriteString("Machine Info", "Machine Name", PCSystemHeader.TargetMachineName);

		delete iniFile;
	}
}
//---------------------------------------------------------------------------
bool __fastcall ReadInitialValues(AnsiString fileName)
{
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		for (int globalCamIndex = 0; globalCamIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCamIndex++)
		{
			InitialValues.ShutterSpeed[globalCamIndex] = iniFile->ReadInteger("Camera", "Shutter Speed " + IntToStr(globalCamIndex + 1), 17);
			InitialValues.DigitalGain[globalCamIndex] = iniFile->ReadInteger("Camera", "Digital Gain " + IntToStr(globalCamIndex + 1), 1);
		}

		delete iniFile;
	}

	return true;
}
//---------------------------------------------------------------------------
void __fastcall WriteInitialValues(AnsiString fileName)
{
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		for (int globalCamIndex = 0; globalCamIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCamIndex++)
		{
			iniFile->WriteInteger("Camera", "Shutter Speed " + IntToStr(globalCamIndex + 1), InitialValues.ShutterSpeed[globalCamIndex]);
			iniFile->WriteInteger("Camera", "Digital Gain " + IntToStr(globalCamIndex + 1), InitialValues.DigitalGain[globalCamIndex]);
		}

		delete iniFile;
	}
}
//---------------------------------------------------------------------------
bool __fastcall ExtractImage(Graphics::TBitmap *bitmap, int imageNumber, int globalCameraNumber, bool offsetSW, unsigned char *offsetImage, int SamplingMode, EImageKind imageKind)
{
	testGlobalCameraNumber = globalCameraNumber;

	globalCameraNumber = CameraIndexSubstitutionForTest(globalCameraNumber);

	AnsiString containerFileName = GetProductImagePath() + "\\Image" + IntToStr(imageNumber) + ".FAC";
	AnsiString bitmapName;
	if (imageKind == EIK_NORMAL)
	{
		bitmapName = "Image" + IntToStr(imageNumber) + "_" + IntToStr(globalCameraNumber) + ".fbm";
	}
	else	// EIK_OPTION
	{
		bitmapName = "Image" + IntToStr(imageNumber) + "_" + IntToStr(globalCameraNumber) + "_O.fbm";
	}

	return ExtractImageFromContainer(bitmap, containerFileName, bitmapName, offsetSW, offsetImage, SamplingMode);

}
//---------------------------------------------------------------------------
bool __fastcall ExtractBayerImage(unsigned char *data, int imageNumber, int globalCameraNumber, EImageKind imageKind)
{
	testGlobalCameraNumber = globalCameraNumber;

	globalCameraNumber = CameraIndexSubstitutionForTest(globalCameraNumber);

	AnsiString containerFileName = GetProductImagePath() + "\\Image" + IntToStr(imageNumber) + ".FAC";
	AnsiString bitmapName;
	if (imageKind == EIK_NORMAL)
	{
		bitmapName = "Image" + IntToStr(imageNumber) + "_" + IntToStr(globalCameraNumber) + ".fbm";
	}
	else	// EIK_OPTION
	{
		bitmapName = "Image" + IntToStr(imageNumber) + "_" + IntToStr(globalCameraNumber) + "_O.fbm";
	}
	return ExtractImageDataFromContainer(data, containerFileName, bitmapName);
}
//---------------------------------------------------------------------------
bool __fastcall ExtractProductImage(AnsiString productName, Graphics::TBitmap *bitmap, int imageNumber, int globalCameraNumber, EImageKind imageKind)
{
	testGlobalCameraNumber = globalCameraNumber;

	globalCameraNumber = CameraIndexSubstitutionForTest(globalCameraNumber);

	AnsiString containerFileName = ProgramPath.Product + "\\" + productName + "\\Image\\Image" + IntToStr(imageNumber) + ".FAC";
	AnsiString bitmapName;
	if (imageKind == EIK_NORMAL)
	{
		bitmapName = "Image" + IntToStr(imageNumber) + "_" + IntToStr(globalCameraNumber) + ".fbm";
	}
	else	// EIK_OPTION
	{
		bitmapName = "Image" + IntToStr(imageNumber) + "_" + IntToStr(globalCameraNumber) + "_O.fbm";
	}

	return ExtractImageFromContainer(bitmap, containerFileName, bitmapName, false, NULL, 0);

}
//---------------------------------------------------------------------------
bool __fastcall ExtractImageFromContainer(Graphics::TBitmap *bitmap, AnsiString containerFileName, AnsiString bitmapName, bool offsetSW, unsigned char *offsetImage, int SamplingMode)
{
	TFileContainer fileContainer;
	// get container file name
	if (!fileContainer.Open(containerFileName))
	{
		return false;
	}

	if (fileContainer.FileContains(bitmapName))
	{
		TBitmapHeader bitmapHeader;
		if (!fileContainer.GetBitmapHeader(&bitmapHeader, bitmapName))
		{
			return false;
		}
		unsigned char *bitmapData = new unsigned char[bitmapHeader.Width * bitmapHeader.Height * bitmapHeader.BitsPerPixel / 8];
		if (bitmapData == NULL)
			return false;
		fileContainer.ExtractData(bitmapName, bitmapData);
		int bitmapWidth = bitmapHeader.Width;
		int bitmapHeight = bitmapHeader.Height;
		int globalCameraNumber = bitmapHeader.CameraIndex + 1;

		if (bitmapHeader.BitmapKind == EBK_2D)
		{
			bitmap->PixelFormat = pf24bit;
			bitmap->Width = bitmapWidth;
			bitmap->Height = bitmapHeight;

			GetNFACamera2DColorImage(bitmap, bitmapData, bitmapHeader.Width, bitmapHeader.Height, bitmapHeader.CameraIndex, offsetSW, offsetImage, SamplingMode);
			//Bayer_Conversion_BGGR(bitmap, bitmapData, bitmapHeader.Width, bitmapHeader.Height, 2);

			// For SELMA200, 영상 반전 수정 예정
			if (globalCameraNumber == SD2_2D_SIDE_FACE_P45_CAMERA_INDEX ||
			        globalCameraNumber == SD2_2D_SIDE_FACE_M45_CAMERA_INDEX)
			{
				byte *pTempLine = new byte[bitmap->Width * 3];
				for (int y = 0; y < (bitmap->Height); y++)
				{
					byte *pBitmap = (byte *)bitmap->ScanLine[y];

					for (int x = 0; x < bitmap->Width; x++)
					{
						pTempLine[x * 3 + 0] = pBitmap[(bitmap->Width - 1 - x) * 3 + 0];
						pTempLine[x * 3 + 1] = pBitmap[(bitmap->Width - 1 - x) * 3 + 1];
						pTempLine[x * 3 + 2] = pBitmap[(bitmap->Width - 1 - x) * 3 + 2];
					}
					memcpy(pBitmap, pTempLine, bitmap->Width * 3);
				}
				delete[] pTempLine;
			}
			else if (globalCameraNumber == SD1_2D_FRONT_FACE_CAMERA_INDEX ||
			         globalCameraNumber == SD2_2D_FRONT_FACE_CAMERA_INDEX ||
			         globalCameraNumber == SD1_2D_SIDE_FACE_00_CAMERA_INDEX ||
			         globalCameraNumber == SD1_2D_OTHER_SIDE_FACE_00_CAMERA_INDEX ||
			         globalCameraNumber == SD1_2D_SIDE_FACE_P45_CAMERA_INDEX ||
			         globalCameraNumber == SD1_2D_OTHER_SIDE_FACE_P45_CAMERA_INDEX ||
			         globalCameraNumber == SD1_2D_SIDE_FACE_M45_CAMERA_INDEX ||
			         globalCameraNumber == SD1_2D_OTHER_SIDE_FACE_M45_CAMERA_INDEX)
			{
				byte *pTempLineT = new byte[bitmap->Width * 3];
				byte *pTempLineB = new byte[bitmap->Width * 3];
				for (int y = 0; y < (bitmap->Height + 1) / 2; y++)
				{
					byte *pBitmapT = (byte *)bitmap->ScanLine[y];
					byte *pBitmapB = (byte *)bitmap->ScanLine[bitmap->Height - 1 - y];

					memcpy(pTempLineT, pBitmapB, bitmap->Width * 3);
					memcpy(pTempLineB, pBitmapT, bitmap->Width * 3);
					memcpy(pBitmapT, pTempLineT, bitmap->Width * 3);
					memcpy(pBitmapB, pTempLineB, bitmap->Width * 3);
				}
				delete[] pTempLineT;
				delete[] pTempLineB;
			}
		}
		else		// 3D
		{
			bitmap->PixelFormat = pf8bit;
			bitmap->Width = IMAGE_WIDTH_3D;
			bitmap->Height = IMAGE_HEIGHT_3D;
			SetGrayPalette(bitmap);

			ImageConversion_3D(bitmap, IMAGE_WIDTH_3D, IMAGE_HEIGHT_3D, bitmapData, bitmapWidth, bitmapHeight);


		}

		delete[] bitmapData;
	}
	else
	{
		return false;
	}
	return true;
}
//---------------------------------------------------------------------------
bool __fastcall ExtractImageDataFromContainer(unsigned char *data, AnsiString containerFileName, AnsiString bitmapName)
{
	TFileContainer fileContainer;
	// get container file name
	if (!fileContainer.Open(containerFileName))
	{
		return false;
	}

	if (fileContainer.FileContains(bitmapName))
	{
		TBitmapHeader bitmapHeader;
		if (!fileContainer.GetBitmapHeader(&bitmapHeader, bitmapName))
		{
			return false;
		}
		fileContainer.ExtractData(bitmapName, data);
	}
	else
	{
		return false;
	}
	return true;
}
//---------------------------------------------------------------------------
AnsiString __fastcall GetDefectImageContainerFileName(int imageIndex, AnsiString productCode, AnsiString lotName)
{
	int containerIndex = imageIndex / DEFECT_DATA_CONTAINER_SIZE;
	AnsiString defectDataDir = GetDefectDataPath(productCode, lotName);
	return defectDataDir + "\\DefectImage" + IntToStr(containerIndex + 1) + ".FAC";
}
//---------------------------------------------------------------------------
AnsiString __fastcall GetDefectDataContainerFileName(int imageIndex, AnsiString productCode, AnsiString lotName)
{
	int containerIndex = imageIndex / DEFECT_DATA_CONTAINER_SIZE;
	AnsiString defectDataDir = GetDefectDataPath(productCode, lotName);
	return defectDataDir + "\\DefectData" + IntToStr(containerIndex + 1) + ".FAC";
}
//---------------------------------------------------------------------------
bool __fastcall ReadPCProgramOption(AnsiString fileName, TPCProgramOption &pcProgramOption)
{
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		pcProgramOption.InspectionResetOnRestart = iniFile->ReadBool("PC Program Option", "Inspection Reset On Restart", false);
		pcProgramOption.QuickStartEnabled = iniFile->ReadBool("PC Program Option", "Quick Start Enabled", false);
		pcProgramOption.FPGAVersionEnabled = iniFile->ReadBool("PC Program Option", "FPGA Version Enabled", false);
		pcProgramOption.AppButtonEnabled = iniFile->ReadBool("PC Program Option", "App Button Enabled", false);
		pcProgramOption.PrintModeOption = iniFile->ReadInteger("PC Program Option", "Print Mode Option", 0);
		pcProgramOption.PrintThreeDHeightOption = iniFile->ReadInteger("PC Program Option", "Print 3D Height Option", 0);
		pcProgramOption.MotorMinSpeed[0] = iniFile->ReadInteger("PC Program Option", "Suction Disk Min Speed", 30);
		pcProgramOption.MotorMinSpeed[1] = iniFile->ReadInteger("PC Program Option", "Bowl Feeder In Disk Min Speed", 30);
		pcProgramOption.MotorMinSpeed[2] = iniFile->ReadInteger("PC Program Option", "Bowl Feeder Out Disk Min Speed", 30);
		pcProgramOption.MotorMaxSpeed[0] = iniFile->ReadInteger("PC Program Option", "Suction Disk Max Speed", 200);
		pcProgramOption.MotorMaxSpeed[1] = iniFile->ReadInteger("PC Program Option", "Bowl Feeder In Disk Max Speed", 200);
		pcProgramOption.MotorMaxSpeed[2] = iniFile->ReadInteger("PC Program Option", "Bowl Feeder Out Disk Max Speed", 200);
		pcProgramOption.DHprogram = iniFile->ReadInteger("PC Program Option", "DHprogram", false);
		pcProgramOption.HIprogram = iniFile->ReadInteger("PC Program Option", "HIprogram", false);

		//한국콜마 2분배기
		pcProgramOption.TwoSplitterEnable = iniFile->ReadInteger("PC Program Option", "Two Splitter Enable", false);
		//한국콜마 유유제약 분배기      UserInfo.ini, PC Program Option
		pcProgramOption.DistributorType1 = iniFile->ReadBool("PC Program Option", "DistributorType1", false);
		pcProgramOption.DistributorType2 = iniFile->ReadBool("PC Program Option", "DistributorType2", false);
		pcProgramOption.DistributorType3 = iniFile->ReadBool("PC Program Option", "DistributorType3", false);
		pcProgramOption.DistributorType4 = iniFile->ReadBool("PC Program Option", "DistributorType4", false);

		pcProgramOption.DHGradeHideProgram = iniFile->ReadInteger("PC Program Option", "DH Grade Hide program", false);
		pcProgramOption.SensorOutputSettingOption = iniFile->ReadInteger("PC Program Option", "Sensor Setting Option", false);
		pcProgramOption.SCADASystemSwitchEnabled = iniFile->ReadInteger("PC Program Option", "SCADA System Switch Enabled", false);
		pcProgramOption.DetailRportView = iniFile->ReadInteger("PC Program Option", "Detail Report View", false);
		pcProgramOption.IncludeUnInsTabletCount = iniFile->ReadBool("PC Program Option", "Include Unins", false);
		pcProgramOption.PrintEQName = iniFile->ReadBool("PC Program Option", "PrintEQName", false);
		pcProgramOption.UVLaserEnabled = iniFile->ReadBool("PC Program Option", "UVLaser Enabled", false);
		pcProgramOption.AjantaLocalNameNum = iniFile->ReadBool("PC Program Option", "AjantaLocalNameNum", 0);
		pcProgramOption.InitSubSamplingMode = iniFile->ReadBool("PC Program Option", "InitSubSamplingMode", 0);
		pcProgramOption.ActiveResolutionSetting = iniFile->ReadBool("PC Program Option", "ActiveResolutionSetting", 0);
		pcProgramOption.Nameofmachine = iniFile->ReadString("PC Program Option", "Name of machine", "");
		pcProgramOption.MachineID = iniFile->ReadString("PC Program Option", "Machine ID", "");
		pcProgramOption.UVLaserUpstreamEnabled = iniFile->ReadBool("PC Program Option", "UVLaser Upstream Enabled", false);
		pcProgramOption.UVLaserDownstreamEnabled = iniFile->ReadBool("PC Program Option", "UVLaser Downstream Enabled", false);

		pcProgramOption.ApplyLSFTableSW = iniFile->ReadBool("PC Program Option", "LSF Table Enabled", false);
    pcProgramOption.DistributorConveyerEnable =iniFile->ReadBool("PC Program Option", "Distributor Conveyer Enabled", false);
	pcProgramOption.CareUpperLowCasePasswordEnabled=iniFile->ReadBool("PC Program Option", "CareUpperLowCasePassword Enabled", false);
	pcProgramOption.TcpIpMonitorActive =iniFile->ReadBool("PC Program Option", "TcpIpMonitorActive Enabled", false);
	pcProgramOption.IncludeUnInsTabletCount =iniFile->ReadBool("PC Program Option", "IncludeUnInsTabletCount Enabled", false);	
	pcProgramOption.InsRepOpt.SPB_HCB_InsCntMatchingOptionOff = iniFile->ReadBool("PC Program Option", "SPB HCB Cnt Matching Option OFF", false);
	pcProgramOption.CSV_PrintMaxPageChangeActive = iniFile->ReadBool("PC Program Option", "CSV_PrintMaxPageChangeActive", false);	 
	pcProgramOption.CSV_PrintMaxPageCnt = iniFile->ReadInteger("PC Program Option", "CSV_PrintMaxPageCnt", 10);	
	pcProgramOption.BackupSpeedMode = iniFile->ReadInteger("PC Program Option", "BackupSpeedMode", 0);		
    pcProgramOption.PrintInsResUserDisplayOpt 	= iniFile->ReadInteger("PC Program Option", "Print LOT Operator Display", 0);
    pcProgramOption.AllAuthorityNotActive 		= iniFile->ReadBool("PC Program Option", "Authority Not Active", false);
    pcProgramOption.VibratorFeederSpeedControlOpt = iniFile->ReadBool("PC Program Option", "Vibrator Feeder Speed Control Option", false);
    pcProgramOption.SendCompleteSigDistributor = iniFile->ReadBool("PC Program Option", "Send Complete Sig Distributor", false);
  	 
		delete iniFile;
	}
	else
	{
		pcProgramOption.InspectionResetOnRestart = false;
		pcProgramOption.QuickStartEnabled = false;
		pcProgramOption.FPGAVersionEnabled = false;
		pcProgramOption.AppButtonEnabled = false;
		pcProgramOption.PrintModeOption = 0;
		pcProgramOption.PrintThreeDHeightOption = 0;
		pcProgramOption.MotorMinSpeed[0] = 30;
		pcProgramOption.MotorMinSpeed[1] = 30;
		pcProgramOption.MotorMinSpeed[2] = 30;
		pcProgramOption.MotorMaxSpeed[0] = 200;
		pcProgramOption.MotorMaxSpeed[1] = 200;
		pcProgramOption.MotorMaxSpeed[2] = 200;
		pcProgramOption.DHprogram = false;
		pcProgramOption.HIprogram = false;

		//한국콜마
		pcProgramOption.TwoSplitterEnable = false;
		//한국콜마 유유제약   UserInfo.ini, PC Program Option
		pcProgramOption.DistributorType1 = false;
		pcProgramOption.DistributorType2 = false;
		pcProgramOption.DistributorType3 = false;
		pcProgramOption.DistributorType4 = false;

		pcProgramOption.DHGradeHideProgram = false;
		pcProgramOption.SensorOutputSettingOption = false;
		pcProgramOption.SCADASystemSwitchEnabled = false;
		pcProgramOption.DetailRportView = false;
		pcProgramOption.IncludeUnInsTabletCount = false;
		pcProgramOption.PrintEQName = false;
		pcProgramOption.UVLaserEnabled = false;
		pcProgramOption.AjantaLocalNameNum = 0;
		pcProgramOption.InitSubSamplingMode = 0;
		pcProgramOption.ActiveResolutionSetting = 0;
		pcProgramOption.Nameofmachine = "";
		pcProgramOption.MachineID = "";
		pcProgramOption.UVLaserUpstreamEnabled = false;
		pcProgramOption.UVLaserDownstreamEnabled = false;

		pcProgramOption.ApplyLSFTableSW = false;
    pcProgramOption.DistributorConveyerEnable = false;
    pcProgramOption.CareUpperLowCasePasswordEnabled= false;
    pcProgramOption.TcpIpMonitorActive = false;    
    pcProgramOption.IncludeUnInsTabletCount = false;    
    pcProgramOption.InsRepOpt.SPB_HCB_InsCntMatchingOptionOff = false;
	  pcProgramOption.CSV_PrintMaxPageChangeActive = false;
	  pcProgramOption.CSV_PrintMaxPageCnt = 10;
	pcProgramOption.BackupSpeedMode = 0;
    pcProgramOption.PrintInsResUserDisplayOpt 	= 0;
    pcProgramOption.AllAuthorityNotActive 		= false;
    pcProgramOption.VibratorFeederSpeedControlOpt = false;
    pcProgramOption.SendCompleteSigDistributor = false;
        	  
		return false;
	}
	return true;
}
//---------------------------------------------------------------------------
void __fastcall WritePCProgramOption(AnsiString fileName, TPCProgramOption &pcProgramOption)
{
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		iniFile->WriteBool("PC Program Option", "Inspection Reset On Restart", pcProgramOption.InspectionResetOnRestart);
		iniFile->WriteBool("PC Program Option", "Quick Start Enabled", pcProgramOption.QuickStartEnabled);
		iniFile->WriteBool("PC Program Option", "FPGA Version Enabled", pcProgramOption.FPGAVersionEnabled);
		iniFile->WriteBool("PC Program Option", "App Button Enabled", pcProgramOption.AppButtonEnabled);
		iniFile->WriteInteger("PC Program Option", "Print Mode Option", pcProgramOption.PrintModeOption);
		iniFile->WriteInteger("PC Program Option", "Print 3D Height Option", pcProgramOption.PrintThreeDHeightOption);
		iniFile->WriteInteger("PC Program Option", "Suction Disk Min Speed", pcProgramOption.MotorMinSpeed[0]);
		iniFile->WriteInteger("PC Program Option", "Bowl Feeder In Disk Min Speed", pcProgramOption.MotorMinSpeed[1]);
		iniFile->WriteInteger("PC Program Option", "Bowl Feeder Out Disk Min Speed", pcProgramOption.MotorMinSpeed[2]);
		iniFile->WriteInteger("PC Program Option", "Suction Disk Max Speed", pcProgramOption.MotorMaxSpeed[0]);
		iniFile->WriteInteger("PC Program Option", "Bowl Feeder In Disk Max Speed", pcProgramOption.MotorMaxSpeed[1]);
		iniFile->WriteInteger("PC Program Option", "Bowl Feeder Out Disk Max Speed", pcProgramOption.MotorMaxSpeed[2]);
		iniFile->WriteInteger("PC Program Option", "DHprogram", pcProgramOption.DHprogram);
		iniFile->WriteInteger("PC Program Option", "HIprogram", pcProgramOption.HIprogram);

		//한국콜마 2분배기
		iniFile->WriteInteger("PC Program Option", "Two Splitter Enable", pcProgramOption.TwoSplitterEnable);
		//한국콜마 유유제약 분배기  UserInfo.ini, PC Program Option
		iniFile->WriteBool("PC Program Option", "DistributorType1", pcProgramOption.DistributorType1);
		iniFile->WriteBool("PC Program Option", "DistributorType2", pcProgramOption.DistributorType2);
		iniFile->WriteBool("PC Program Option", "DistributorType3", pcProgramOption.DistributorType3);
		iniFile->WriteBool("PC Program Option", "DistributorType4", pcProgramOption.DistributorType4);
		
		iniFile->WriteInteger("PC Program Option", "DH Grade Hide program", pcProgramOption.DHGradeHideProgram);
		iniFile->WriteInteger("PC Program Option", "Sensor Setting Option", pcProgramOption.SensorOutputSettingOption);
		iniFile->WriteInteger("PC Program Option", "SCADA System Switch Enabled", pcProgramOption.SCADASystemSwitchEnabled);
		iniFile->WriteInteger("PC Program Option", "Detail Report View", pcProgramOption.DetailRportView);
		iniFile->WriteInteger("PC Program Option", "Include Unins", pcProgramOption.IncludeUnInsTabletCount);
		iniFile->WriteInteger("PC Program Option", "PrintEQName", pcProgramOption.PrintEQName);
		iniFile->WriteInteger("PC Program Option", "UVLaser Enabled", pcProgramOption.UVLaserEnabled);
		iniFile->WriteInteger("PC Program Option", "AjantaLocalNameNum", pcProgramOption.AjantaLocalNameNum);
		iniFile->WriteBool("PC Program Option", "InitSubSamplingMode", pcProgramOption.InitSubSamplingMode);
		iniFile->WriteBool("PC Program Option", "ActiveResolutionSetting", pcProgramOption.ActiveResolutionSetting);
		iniFile->WriteString("PC Program Option", "Name of machine", pcProgramOption.Nameofmachine);
		iniFile->WriteString("PC Program Option", "Machine ID", pcProgramOption.MachineID);
		iniFile->WriteBool("PC Program Option", "UVLaser Upstream Enabled", pcProgramOption.UVLaserUpstreamEnabled);
		iniFile->WriteBool("PC Program Option", "UVLaser Downstream Enabled", pcProgramOption.UVLaserDownstreamEnabled);

		iniFile->WriteBool("PC Program Option", "LSF Table Enabled", pcProgramOption.ApplyLSFTableSW);
    iniFile->WriteBool("PC Program Option", "Distributor Conveyer Enabled", pcProgramOption.DistributorConveyerEnable);
	iniFile->WriteBool("PC Program Option", "CareUpperLowCasePassword Enabled", pcProgramOption.CareUpperLowCasePasswordEnabled);
	iniFile->WriteBool("PC Program Option", "TcpIpMonitorActive Enabled", pcProgramOption.TcpIpMonitorActive);  	
	iniFile->WriteBool("PC Program Option", "IncludeUnInsTabletCount Enabled", pcProgramOption.IncludeUnInsTabletCount); 	
	iniFile->WriteBool("PC Program Option", "SPB HCB Cnt Matching Option OFF", pcProgramOption.InsRepOpt.SPB_HCB_InsCntMatchingOptionOff);
	iniFile->WriteBool("PC Program Option", "CSV_PrintMaxPageChangeActive", pcProgramOption.CSV_PrintMaxPageChangeActive); 	
	iniFile->WriteInteger("PC Program Option", "CSV_PrintMaxPageCnt", pcProgramOption.CSV_PrintMaxPageCnt);   
	iniFile->WriteInteger("PC Program Option", "BackupSpeedMode", pcProgramOption.BackupSpeedMode);
    iniFile->WriteInteger("PC Program Option", "Print LOT Operator Display", pcProgramOption.PrintInsResUserDisplayOpt);
    iniFile->WriteBool("PC Program Option", "Authority Not Active", pcProgramOption.AllAuthorityNotActive);
    iniFile->WriteBool("PC Program Option", "Vibrator Feeder Speed Control Option", pcProgramOption.VibratorFeederSpeedControlOpt);
    iniFile->WriteBool("PC Program Option", "Send Complete Sig Distributor", pcProgramOption.SendCompleteSigDistributor);

		delete iniFile;
	}
}
//---------------------------------------------------------------------------
void __fastcall WritePCProgram3DCameraOption(AnsiString fileName, TPCProgramOption &pcProgramOption)
{
	// 전체 write 시 기존 시스템에 영향을 미칠까 싶어 함수를 따로 관리하도록 변경함
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		iniFile->WriteBool("PC Program Option", "LSF Table Enabled", pcProgramOption.ApplyLSFTableSW);

		delete iniFile;
	}
}
//---------------------------------------------------------------------------

void ComponentSetFontName(TComponent *pComponent, const AnsiString aFontName)
{
	int i;
	for (i = 0; i < pComponent->ComponentCount; i++)
	{
		if (pComponent->Components[i]->InheritsFrom(__classid(TButton)))
			((TButton *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TLabel)))
			((TLabel *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TEdit)))
			((TEdit *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TMemo)))
			((TMemo *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TButton)))
			((TButton *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TGroupBox)))
			((TGroupBox *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TRadioGroup)))
			((TRadioGroup *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TComboBox)))
			((TComboBox *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TCheckBox)))
			((TCheckBox *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TRadioButton)))
			((TRadioButton *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TListBox)))
			((TListBox *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TPanel)))
			((TPanel *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TStringGrid)))
			((TStringGrid *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TStaticText)))
			((TStaticText *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntLabel)))
			((TTntLabel *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntEdit)))
			((TTntEdit *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntButton)))
			((TTntButton *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntMemo)))
			((TTntMemo *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntStaticText)))
			((TTntStaticText *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntGroupBox)))
			((TTntGroupBox *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntRadioGroup)))
			((TTntRadioGroup *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntComboBox)))
			((TTntComboBox *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntCheckBox)))
			((TTntCheckBox *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntRadioButton)))
			((TTntRadioButton *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntListBox)))
			((TTntListBox *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntPanel)))
			((TTntPanel *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntStringGrid)))
			((TTntStringGrid *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntMemo)))
			((TTntMemo *)(pComponent->Components[i]))->Font->Name = aFontName;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TQRLabel)))
			((TQRLabel *)(pComponent->Components[i]))->Font->Name = aFontName;
    else if (pComponent->Components[i]->InheritsFrom(__classid(TTntBitBtn)))
			((TTntBitBtn *)(pComponent->Components[i]))->Font->Name = aFontName;


		// 재귀호출
		ComponentSetFontName(pComponent->Components[i], aFontName);
	}
}

void ComponentSetMultiLine(TComponent *pComponent)
{
  int i;
  long style;
	for (i = 0; i < pComponent->ComponentCount; i++)
	{
    if (pComponent->Components[i]->InheritsFrom(__classid(TButton)))
    {
      style = GetWindowLong(((TButton *)(pComponent->Components[i]))->Handle, GWL_STYLE);
      style = style | BS_MULTILINE;
      SetWindowLong(((TButton *)(pComponent->Components[i]))->Handle, GWL_STYLE, style);
    }
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntButton)))
    {
      style = GetWindowLong(((TTntButton *)(pComponent->Components[i]))->Handle, GWL_STYLE);
      style = style | BS_MULTILINE;
      SetWindowLong(((TTntButton *)(pComponent->Components[i]))->Handle, GWL_STYLE, style);
    }
    else if (pComponent->Components[i]->InheritsFrom(__classid(TTntBitBtn)))
    {
      style = GetWindowLong(((TTntBitBtn *)(pComponent->Components[i]))->Handle, GWL_STYLE);
      style = style | BS_MULTILINE;
      SetWindowLong(((TTntBitBtn *)(pComponent->Components[i]))->Handle, GWL_STYLE, style);
    }

		ComponentSetMultiLine(pComponent->Components[i]);
  }
}

int __fastcall CameraIndexSubstitutionForTest(int cameraIndex) // For SELMA200, TEST전용
{
	return cameraIndex;


	int retIndex;

	switch (cameraIndex)
	{
	case SD1_2D_FRONT_FACE_CAMERA_INDEX:
		retIndex = 1;
		break;

	case SD1_2D_SIDE_FACE_P45_CAMERA_INDEX:
		retIndex = 3;
		break;

	case SD1_2D_SIDE_FACE_00_CAMERA_INDEX:
		retIndex = 4;
		break;

	case SD1_2D_SIDE_FACE_M45_CAMERA_INDEX:
		retIndex = 5;
		break;

	case SD1_3D_FRONT_FACE_CAMERA_INDEX:
		retIndex = 2;
		break;

	case SD1_2D_OTHER_SIDE_FACE_P45_CAMERA_INDEX:
		retIndex = 3;
		break;

	case SD1_2D_OTHER_SIDE_FACE_00_CAMERA_INDEX:
		retIndex = 4;
		break;

	case SD1_2D_OTHER_SIDE_FACE_M45_CAMERA_INDEX:
		retIndex = 5;
		break;

	case SD2_2D_FRONT_FACE_CAMERA_INDEX:
		retIndex = 6;
		break;

	case SD2_2D_SIDE_FACE_P45_CAMERA_INDEX:
		retIndex = 8;
		break;

	case SD2_2D_SIDE_FACE_00_CAMERA_INDEX:
		retIndex = 9;
		break;

	case SD2_2D_SIDE_FACE_M45_CAMERA_INDEX:
		retIndex = 10;
		break;

	case SD2_3D_FRONT_FACE_CAMERA_INDEX:
		retIndex = 7;
		break;

	case SD2_2D_OTHER_SIDE_FACE_P45_CAMERA_INDEX:
		retIndex = 8;
		break;

	case SD2_2D_OTHER_SIDE_FACE_00_CAMERA_INDEX:
		retIndex = 9;
		break;

	case SD2_2D_OTHER_SIDE_FACE_M45_CAMERA_INDEX:
		retIndex = 10;
		break;
	}

	return retIndex;
}

//---------------------------------------------------------------------------
void __fastcall RefreshCameraInfoForInspectionSetting(TProductData *productData, int ShutterSpeed, int writeMask, int camIndex, bool *cameraEnabled, bool bROIDefault)
{
	TROIInfo DefaultROIInfo, ApplyROIInfo;
	AnsiString filePath;
	int TargetSPBIndex = CameraMapInfo[camIndex].SPBIndex;

	if (bROIDefault)
	{
		filePath = ProgramPath.Env + "\\NFACameraInformation.ini";
		DefaultROIInfo = ReadCameraInformation(filePath, camIndex);

		if (CameraMapInfo[camIndex].CameraInspectPosition != CAMERA_POSITION_3D)
		{
			memcpy(&ApplyROIInfo, &DefaultROIInfo, sizeof(TROIInfo));
		}
		else
		{
			ApplyROIInfo = SetThreeDCameraROI(DefaultROIInfo, productData);
		}
	}
	else
	{
		int tempStartX, tempEndX, tempStartY, tempEndY;
		// ROI 설정방식은 2D와 3D에서 차이가 날것
		if (CameraMapInfo[camIndex].CameraInspectPosition != CAMERA_POSITION_3D)
		{
			/*
			tempStartX = max(0, (productData->BoundaryLeft[camIndex] * 2) / 8 - 4);
			tempEndX   = min(159, (productData->BoundaryRight[camIndex] * 2) / 8 + 4);
			tempStartY = max(0, productData->BoundaryTop[camIndex] * 2 - 32);
			tempEndY   = min(1023, productData->BoundaryBottom[camIndex] * 2 + 32);

			ApplyROIInfo.StartX = tempStartX;
			ApplyROIInfo.EndX = tempEndX;
			ApplyROIInfo.StartY = tempStartY;
			ApplyROIInfo.EndY = tempEndY;
			*/

			/******************************************************************************************************************/
			// 임시 코드

			int minY, maxY;
			minY = SYSTEM_CAMERA_HEIGHT;
			maxY = 0;

			for (int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
			{
				if (TargetSPBIndex == CameraMapInfo[globalCameraIndex].SPBIndex)
				{
					if (!cameraEnabled[globalCameraIndex])
						continue;
					if (CameraMapInfo[globalCameraIndex].CameraInspectPosition != CAMERA_POSITION_3D)
					{
						if (minY > productData->BoundaryTop[globalCameraIndex])
							minY = productData->BoundaryTop[globalCameraIndex];
						if (maxY < productData->BoundaryBottom[globalCameraIndex])
							maxY = productData->BoundaryBottom[globalCameraIndex];
					}
				}
			}

			int imageTop, imageBottom;
			imageTop = minY;
			imageBottom = maxY;

			switch (camIndex + 1)
			{
			case SD1_2D_FRONT_FACE_CAMERA_INDEX:  // #1 SPB

			case SD2_2D_FRONT_FACE_CAMERA_INDEX:  // #4 SPB

			case SD1_2D_SIDE_FACE_P45_CAMERA_INDEX:  // #2 SPB
			case SD1_2D_SIDE_FACE_00_CAMERA_INDEX:
			case SD1_2D_SIDE_FACE_M45_CAMERA_INDEX:

			case SD1_2D_OTHER_SIDE_FACE_P45_CAMERA_INDEX:  // #3 SPB
			case SD1_2D_OTHER_SIDE_FACE_00_CAMERA_INDEX:
			case SD1_2D_OTHER_SIDE_FACE_M45_CAMERA_INDEX:

				tempStartY = SYSTEM_CAMERA_HEIGHT - imageTop;
				tempEndY = SYSTEM_CAMERA_HEIGHT - imageBottom;
				break;
			default:  // #5, 6 SPB

				tempStartY = imageTop;
				tempEndY = imageBottom;
				break;
			}

			// 480 -> 960
			tempStartY *= 2;
			tempEndY *= 2;

			// 방향
			imageTop = min(tempStartY, tempEndY);
			imageBottom = max(tempStartY, tempEndY);

			// 32배수
			tempStartY = imageTop / 32 * 32;
			tempEndY = imageBottom / 32 * 32;

			if (tempStartY > imageTop)
			{
				tempStartY -= 32;
			}

			if (tempEndY < imageBottom)
			{
				tempEndY += 32;
			}

			filePath = ProgramPath.Env + "\\NFACameraInformation.ini";
			DefaultROIInfo = ReadCameraInformation(filePath, camIndex);

			if (tempStartY < DefaultROIInfo.StartY || tempStartY > DefaultROIInfo.EndY)
			{
				tempStartY = DefaultROIInfo.StartY;
			}

			if (tempEndY < DefaultROIInfo.StartY || tempEndY > DefaultROIInfo.EndY)
			{
				tempEndY = DefaultROIInfo.EndY;
			}

			ApplyROIInfo.StartX = 0;
			ApplyROIInfo.EndX = 159;
			ApplyROIInfo.StartY = tempStartY;
			ApplyROIInfo.EndY = tempEndY;
			/******************************************************************************************************************/
		}
		else
		{
			filePath = ProgramPath.Env + "\\NFACameraInformation.ini";
			DefaultROIInfo = ReadCameraInformation(filePath, camIndex);

			ApplyROIInfo = SetThreeDCameraROI(DefaultROIInfo, productData);

			//180509 Calibration에서 세팅한 값을 사용
			//tempStartX = max(0, (productData->BoundaryTop[camIndex] * 2) / 8 - 4);
			//tempEndX   = min(159, (productData->BoundaryBottom[camIndex] * 2) / 8 + 4);
			//ApplyROIInfo.StartX = tempStartX;
			//ApplyROIInfo.EndX = tempEndX;
		}
	}

	if (CameraMapInfo[camIndex].CameraInspectPosition != CAMERA_POSITION_3D)
	{
		int Data[2];
		Data[0] = ApplyROIInfo.StartY;
		Data[1] = ApplyROIInfo.EndY;
		Comm_Request(COMM_SPB + TargetSPBIndex, CMD_NFA_2D_CAM_PARTIAL_AREA, &Data, sizeof(int) * 2, NULL, 0);
	}

	if (CameraMapInfo[camIndex].CameraInspectPosition != CAMERA_POSITION_3D)
	{
		writeMask |= CAMERA_WRITE_MASK_2D_SUBSAMPLING_MODE;
	}

	SetCameraInformation(ApplyROIInfo, ShutterSpeed, productData->ThresholdFor3D[camIndex], productData->SubSamplingMode, camIndex, writeMask);
}

//---------------------------------------------------------------------------
TROIInfo __fastcall ReadCameraInformation(AnsiString fileName, int cameraIndex)
{
	TROIInfo DefaultROI;
	TIniFile *iniFile = new TIniFile(fileName);

	if (CameraMapInfo[cameraIndex].CameraInspectPosition != CAMERA_POSITION_3D)
	{
		if (iniFile)
		{
			DefaultROI.StartX = iniFile->ReadInteger("Variable Camera Info " + IntToStr(cameraIndex + 1), "ROI StartX", 0);
			DefaultROI.EndX = iniFile->ReadInteger("Variable Camera Info " + IntToStr(cameraIndex + 1), "ROI EndX", 159);
			DefaultROI.StartY = iniFile->ReadInteger("Variable Camera Info " + IntToStr(cameraIndex + 1), "ROI StartY", 0);
			DefaultROI.EndY = iniFile->ReadInteger("Variable Camera Info " + IntToStr(cameraIndex + 1), "ROI EndY", 959);

			delete iniFile;
		}
		else
		{
			DefaultROI.StartX = 0;
			DefaultROI.EndX = 159;
			DefaultROI.StartY = 0;
			DefaultROI.EndY = 959;
		}
	}
	else
	{
		if (iniFile)
		{
			DefaultROI.StartX = iniFile->ReadInteger("Variable Camera Info " + IntToStr(cameraIndex + 1), "ROI StartX", 320);
			DefaultROI.EndX = iniFile->ReadInteger("Variable Camera Info " + IntToStr(cameraIndex + 1), "ROI EndX", 831);
			DefaultROI.StartY = iniFile->ReadInteger("Variable Camera Info " + IntToStr(cameraIndex + 1), "ROI StartY", 384);
			DefaultROI.EndY = iniFile->ReadInteger("Variable Camera Info " + IntToStr(cameraIndex + 1), "ROI EndY", 512);

			delete iniFile;
		}
		else
		{
			DefaultROI.StartX = 320;
			DefaultROI.EndX = 831;
			DefaultROI.StartY = 384;
			DefaultROI.EndY = 512;
		}
	}

	return DefaultROI;
}
//---------------------------------------------------------------------------
bool __fastcall WriteCameraInformation(AnsiString fileName, int cameraIndex)
{
	bool returnValue = true;
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		iniFile->WriteInteger("Variable Camera Info " + IntToStr(cameraIndex + 1), "ROI StartX", VariableCameraInformation[cameraIndex].ROIStartX);
		iniFile->WriteInteger("Variable Camera Info " + IntToStr(cameraIndex + 1), "ROI EndX", VariableCameraInformation[cameraIndex].ROIEndX);
		iniFile->WriteInteger("Variable Camera Info " + IntToStr(cameraIndex + 1), "ROI StartY", VariableCameraInformation[cameraIndex].ROIStartY);
		iniFile->WriteInteger("Variable Camera Info " + IntToStr(cameraIndex + 1), "ROI EndY", VariableCameraInformation[cameraIndex].ROIEndY);
		iniFile->WriteInteger("Variable Camera Info " + IntToStr(cameraIndex + 1), "SubSampling Mode", VariableCameraInformation[cameraIndex].SubSamplingMode);

		delete iniFile;
	}
	else
	{
		returnValue = false;
	}
	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall Read3DCameraDefaultInformation(AnsiString fileName, int cameraIndex)
{
	bool returnValue = true;
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		ThreeDCameraDefaultInformation[cameraIndex].BiningMode = iniFile->ReadInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Binning Mode", 0);

		ThreeDCameraDefaultInformation[cameraIndex].ROIStartX = iniFile->ReadInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "ROI StartX", 0);
		ThreeDCameraDefaultInformation[cameraIndex].ROIWidth = iniFile->ReadInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "ROI Width", 479);
		ThreeDCameraDefaultInformation[cameraIndex].ROIStartY = iniFile->ReadInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "ROI StartY", 0);
		ThreeDCameraDefaultInformation[cameraIndex].ROIHeight = iniFile->ReadInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "ROI Height", 127);

		ThreeDCameraDefaultInformation[cameraIndex].ImageOutputMode = iniFile->ReadInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Image Output Mode", 2);

		ThreeDCameraDefaultInformation[cameraIndex].ExposureTime = iniFile->ReadInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Exposure Time", 50000);
		ThreeDCameraDefaultInformation[cameraIndex].Thresold3D = iniFile->ReadInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Threshold3D", 50);

		ThreeDCameraDefaultInformation[cameraIndex].AnalogCameraGain = iniFile->ReadInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Analog Gain", 0);

		ThreeDCameraDefaultInformation[cameraIndex].TriggerMode = iniFile->ReadInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Capture Trigger Mode", 1);

		ThreeDCameraDefaultInformation[cameraIndex].WaveTableIndex = iniFile->ReadInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Wave Table", 3); // Profiling = 3, 2D = 11

		ThreeDCameraDefaultInformation[cameraIndex].DataSettingSW = iniFile->ReadInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Data Setting SW", 0);
		delete iniFile;
	}
	else
	{
		ThreeDCameraDefaultInformation[cameraIndex].BiningMode = 0;

		ThreeDCameraDefaultInformation[cameraIndex].ROIStartX = 0;
		ThreeDCameraDefaultInformation[cameraIndex].ROIWidth = 479;
		ThreeDCameraDefaultInformation[cameraIndex].ROIStartY = 0;
		ThreeDCameraDefaultInformation[cameraIndex].ROIHeight = 127;

		ThreeDCameraDefaultInformation[cameraIndex].ImageOutputMode = 2;

		ThreeDCameraDefaultInformation[cameraIndex].ExposureTime = 50000;
		ThreeDCameraDefaultInformation[cameraIndex].Thresold3D = 50;

		ThreeDCameraDefaultInformation[cameraIndex].AnalogCameraGain = 0;

		ThreeDCameraDefaultInformation[cameraIndex].TriggerMode = 1;

		ThreeDCameraDefaultInformation[cameraIndex].WaveTableIndex = 3;

		ThreeDCameraDefaultInformation[cameraIndex].DataSettingSW = 0;
	}

	if (ThreeDCameraDefaultInformation[cameraIndex].DataSettingSW == 0)
		returnValue = false;

	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall Write3DCameraDefaultInformation(AnsiString fileName, int cameraIndex)
{
	bool returnValue = true;
	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		iniFile->WriteInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Binning Mode", ThreeDCameraDefaultInformation[cameraIndex].BiningMode);

		iniFile->WriteInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "ROI StartX", ThreeDCameraDefaultInformation[cameraIndex].ROIStartX);
		iniFile->WriteInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "ROI Width", ThreeDCameraDefaultInformation[cameraIndex].ROIWidth);

		iniFile->WriteInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "ROI StartY", ThreeDCameraDefaultInformation[cameraIndex].ROIStartY);
		iniFile->WriteInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "ROI Height", ThreeDCameraDefaultInformation[cameraIndex].ROIHeight);

		iniFile->WriteInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Image Output Mode", ThreeDCameraDefaultInformation[cameraIndex].ImageOutputMode);

		iniFile->WriteInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Exposure Time", ThreeDCameraDefaultInformation[cameraIndex].ExposureTime);
		iniFile->WriteInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Thresold3D", ThreeDCameraDefaultInformation[cameraIndex].Thresold3D);

		iniFile->WriteInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Analog Gain", ThreeDCameraDefaultInformation[cameraIndex].AnalogCameraGain);

		iniFile->WriteInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Capture Trigger Mode", ThreeDCameraDefaultInformation[cameraIndex].TriggerMode);

		iniFile->WriteInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Wave Table", ThreeDCameraDefaultInformation[cameraIndex].WaveTableIndex);

		iniFile->WriteInteger("ThreeD Camera Default Info " + IntToStr(cameraIndex + 1), "Data Setting SW", ThreeDCameraDefaultInformation[cameraIndex].DataSettingSW);

		delete iniFile;
	}
	else
	{
		returnValue = false;
	}
	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall SetCameraInformation(TROIInfo ROIInfo, int ShutterSpeed, int ThresholdFor3D, int SubSamplingMode, int cameraIndex, int wMask)
{
	// Write Camera Information
	const int MAX_COMM_DATA_LENGTH = 20;
	char TxData[MAX_COMM_DATA_LENGTH];
	char RxData[MAX_COMM_DATA_LENGTH];

	bool bRet = true;
	unsigned short dataLength;

	TCommDataLength CommDataLength;

	if (wMask & CAMERA_WRITE_MASK_2D_SUBSAMPLING_MODE)
	{
		if (SubSamplingMode == 1)
			VariableCameraInformation[cameraIndex].SubSamplingMode = 0;
		else if (SubSamplingMode == 0)
			VariableCameraInformation[cameraIndex].SubSamplingMode = 3;

		CommDataLength = eMakeCameraDataPacket(TxData, cameraIndex, CAMERA_INFO_WRITE_SUBSAMPLING_MODE);
		if (!RequestCameraCommand(TxData, RxData, CommDataLength.SendDataLength, CommDataLength.ReceivedDataLength, cameraIndex))
		{
			bRet = false;
		}

		if (RxData[0] == 'T' && RxData[1] == 'O')
		{
			bRet = false;
		}
	}

	if (wMask & CAMERA_WRITE_MASK_2D_ROI)
	{
		VariableCameraInformation[cameraIndex].ROIStartX = ROIInfo.StartX;
		VariableCameraInformation[cameraIndex].ROIEndX = ROIInfo.EndX;
		VariableCameraInformation[cameraIndex].ROIStartY = ROIInfo.StartY;
		VariableCameraInformation[cameraIndex].ROIEndY = ROIInfo.EndY;

		CommDataLength = eMakeCameraDataPacket(TxData, cameraIndex, CAMERA_INFO_WRITE_ROI_2D);
		if (!RequestCameraCommand(TxData, RxData, CommDataLength.SendDataLength, CommDataLength.ReceivedDataLength, cameraIndex))
		{
			bRet = false;
		}

		if (RxData[0] == 'T' && RxData[1] == 'O')
		{
			bRet = false;
		}
	}

	if (wMask & CAMERA_WRITE_MASK_3D_ROI)
	{
		if (0) // 2018-10-09 ROI 값은 일단 변경하지 않는다.
		{
			VariableCameraInformation[cameraIndex].ROIStartX = ROIInfo.StartX;
			VariableCameraInformation[cameraIndex].ROIEndX = ROIInfo.EndX;
			VariableCameraInformation[cameraIndex].ROIStartY = ROIInfo.StartY;
			VariableCameraInformation[cameraIndex].ROIEndY = ROIInfo.EndY;

			CommDataLength = eMakeCameraDataPacket(TxData, cameraIndex, CAMERA_INFO_WRITE_ROI_3D);
			if (!RequestCameraCommand(TxData, RxData, CommDataLength.SendDataLength, CommDataLength.ReceivedDataLength, cameraIndex))
			{
				bRet = false;
			}

			if (RxData[0] == 'T' && RxData[1] == 'O')
			{
				bRet = false;
			}
		}
	}

	if (wMask & CAMERA_WRITE_MASK_2D_SH)
	{
		VariableCameraInformation[cameraIndex].ShutterSpeed = ShutterSpeed;
		CommDataLength = eMakeCameraDataPacket(TxData, cameraIndex, CAMERA_INFO_WRITE_SHUTTER_2D);
		if (!RequestCameraCommand(TxData, RxData, CommDataLength.SendDataLength, CommDataLength.ReceivedDataLength, cameraIndex))
		{
			bRet = false;
		}

		if (RxData[0] == 'T' && RxData[1] == 'O')
		{
			bRet = false;
		}
	}

	if (wMask & CAMERA_WRITE_MASK_3D_SH)
	{
		if (0) // 2018-10-09 Shutter Speed 단위가 바뀌어 일단은 막아놓음
		{
			VariableCameraInformation[cameraIndex].ShutterSpeed = ShutterSpeed;
			CommDataLength = eMakeCameraDataPacket(TxData, cameraIndex, CAMERA_INFO_WRITE_SHUTTER_3D);
			if (!RequestCameraCommand(TxData, RxData, CommDataLength.SendDataLength, CommDataLength.ReceivedDataLength, cameraIndex))
			{
				bRet = false;
			}

			if (RxData[0] == 'T' && RxData[1] == 'O')
			{
				bRet = false;
			}
		}
	}

	if (wMask & CAMERA_WRITE_MASK_TH)
	{
		if (0) // 2018-10-09 Threshold 적용 방법을 몰라 임시로 막아놓음
		{
			if (CameraMapInfo[cameraIndex].CameraInspectPosition == CAMERA_POSITION_3D)
			{
				VariableCameraInformation[cameraIndex].Threshold = ThresholdFor3D;
				CommDataLength = eMakeCameraDataPacket(TxData, cameraIndex, CAMERA_INFO_WRITE_THRESHOLD);
				if (!RequestCameraCommand(TxData, RxData, CommDataLength.SendDataLength, CommDataLength.ReceivedDataLength, cameraIndex))
				{
					bRet = false;
				}

				if (RxData[0] == 'T' && RxData[1] == 'O')
				{
					bRet = false;
				}
			}
		}
	}

	return bRet;
}

//---------------------------------------------------------------------------
TCommDataLength eMakeCameraDataPacket(char *code, int cameraIndex, int dataIndex)
{
	/*********************************************************************************
	B1      B2      B3      B4      B5      B6      B7      ~Bn     Bn+1      Bn+2
	Header  Length          ID      Cmd             Data            Tail      Chk
	**********************************************************************************/
	TCommDataLength CommDataLength;

	int spbIndex = CameraMapInfo[cameraIndex].SPBIndex;
	int camIndex = CameraMapInfo[cameraIndex].CamIndex;

	unsigned int pLength;
	unsigned char LCmd, HCmd;

	const int HEADER_ST_PTR = 0;
	const int LENGTH_ST_PTR = 1;
	const int CAM_INFO_ST_PTR = 3;
	const int CMD_ST_PTR = 4;
	const int DATA_ST_PTR = 6;

	const int FIXED_PACKET_LENGTH = 8;

	const int FULL_SIZE_WIDTH_ST_X = 0;
	const int FULL_SIZE_WIDTH_ED_X = 159;


	if (dataIndex == CAMERA_INFO_WRITE_ROI_2D)
	{
		LCmd = CAMERA_DATA_CMD_ROI_L;
		HCmd = CAMERA_DATA_CMD_ROI_H;

		CommDataLength.SendDataLength = 7;
		CommDataLength.ReceivedDataLength = 1;

		//code[DATA_ST_PTR + 1] = VariableCameraInformation[cameraIndex].ROIStartX;
		//code[DATA_ST_PTR + 2] = VariableCameraInformation[cameraIndex].ROIEndX;

		//180509
		//SPB에서 X축 기준 Add 변경이 구조상 어려움이 있으므로 Width는 최대 크기로 ROI를 설정한다
		code[DATA_ST_PTR + 1] = FULL_SIZE_WIDTH_ST_X;
		code[DATA_ST_PTR + 2] = FULL_SIZE_WIDTH_ED_X;

		code[DATA_ST_PTR + 3] = (0x00FF & VariableCameraInformation[cameraIndex].ROIStartY);
		code[DATA_ST_PTR + 4] = (0xFF00 & VariableCameraInformation[cameraIndex].ROIStartY) >> 8;
		code[DATA_ST_PTR + 5] = (0x00FF & VariableCameraInformation[cameraIndex].ROIEndY);
		code[DATA_ST_PTR + 6] = (0xFF00 & VariableCameraInformation[cameraIndex].ROIEndY) >> 8;

		code[DATA_ST_PTR + 0] = 0x00; // CH
	}
	else if (dataIndex == CAMERA_INFO_WRITE_ROI_3D)
	{
		LCmd = CAMERA_DATA_CMD_ACTIVE_WINDOW_L;
		HCmd = CAMERA_DATA_CMD_ACTIVE_WINDOW_H;

		CommDataLength.SendDataLength = 9;
		CommDataLength.ReceivedDataLength = 1;

		code[DATA_ST_PTR + 1] = (0x00FF & VariableCameraInformation[cameraIndex].ROIStartX);
		code[DATA_ST_PTR + 2] = (0xFF00 & VariableCameraInformation[cameraIndex].ROIStartX) >> 8;
		code[DATA_ST_PTR + 3] = (0x00FF & VariableCameraInformation[cameraIndex].ROIEndX);
		code[DATA_ST_PTR + 4] = (0xFF00 & VariableCameraInformation[cameraIndex].ROIEndX) >> 8;

		code[DATA_ST_PTR + 5] = (0x00FF & VariableCameraInformation[cameraIndex].ROIStartY);
		code[DATA_ST_PTR + 6] = (0xFF00 & VariableCameraInformation[cameraIndex].ROIStartY) >> 8;
		code[DATA_ST_PTR + 7] = (0x00FF & VariableCameraInformation[cameraIndex].ROIEndY);
		code[DATA_ST_PTR + 8] = (0xFF00 & VariableCameraInformation[cameraIndex].ROIEndY) >> 8;

		code[DATA_ST_PTR + 0] = 0x00; // CH
	}
	else if (dataIndex == CAMERA_INFO_WRITE_SHUTTER_2D)
	{
		CommDataLength.SendDataLength = 2;
		CommDataLength.ReceivedDataLength = 1;

		LCmd = CAMERA_DATA_CMD_SHUTTER_L;
		HCmd = CAMERA_DATA_CMD_SHUTTER_H;

		code[DATA_ST_PTR + 0] = (0x00FF & VariableCameraInformation[cameraIndex].ShutterSpeed);
		code[DATA_ST_PTR + 1] = (0xFF00 & VariableCameraInformation[cameraIndex].ShutterSpeed) >> 8;
	}
	else if (dataIndex == CAMERA_INFO_WRITE_SUBSAMPLING_MODE)
	{
		CommDataLength.SendDataLength = 1;
		CommDataLength.ReceivedDataLength = 1;

		LCmd = CAMERA_DATA_CMD_SUBSAMPLING_MODE_L;
		HCmd = CAMERA_DATA_CMD_SUBSAMPLING_MODE_H;

		code[DATA_ST_PTR + 0] = (0x00FF & VariableCameraInformation[cameraIndex].SubSamplingMode);  // 0x01  0x03  x,y subsampling on // 0x00 subsampling off
	}
	else if (dataIndex == CAMERA_INFO_WRITE_SHUTTER_3D)
	{
		// 확인필요!!!
		CommDataLength.SendDataLength = 4;
		CommDataLength.ReceivedDataLength = 1;

		LCmd = CAMERA_DATA_CMD_SHUTTER_L;
		HCmd = CAMERA_DATA_CMD_SHUTTER_H;

		code[DATA_ST_PTR + 0] = (0x000000FF & VariableCameraInformation[cameraIndex].ShutterSpeed);
		code[DATA_ST_PTR + 1] = (0x0000FF00 & VariableCameraInformation[cameraIndex].ShutterSpeed) >> 8;
		code[DATA_ST_PTR + 2] = (0x00FF0000 & VariableCameraInformation[cameraIndex].ShutterSpeed) >> 16;
		code[DATA_ST_PTR + 3] = (0xFF000000 & VariableCameraInformation[cameraIndex].ShutterSpeed) >> 24;
	}
	else if (dataIndex == CAMERA_INFO_WRITE_THRESHOLD)
	{
		// 확인필요!!!
		CommDataLength.SendDataLength = 1;
		CommDataLength.ReceivedDataLength = 1;

		LCmd = CAMERA_DATA_CMD_THR_L;
		HCmd = CAMERA_DATA_CMD_THR_H;

		code[DATA_ST_PTR] = VariableCameraInformation[cameraIndex].Threshold;
	}

	code[HEADER_ST_PTR] = CAMERA_DATA_HEADER;

	code[LENGTH_ST_PTR + 0] = (0x00FF & CommDataLength.SendDataLength);
	code[LENGTH_ST_PTR + 1] = (0xFF00 & CommDataLength.SendDataLength) >> 8;

	code[CMD_ST_PTR + 0] = LCmd;
	code[CMD_ST_PTR + 1] = HCmd;

	code[CAM_INFO_ST_PTR + 0] = (camIndex + 1) << 4;

	code[DATA_ST_PTR + CommDataLength.SendDataLength + 0] = 0xAE; // Tail
	code[DATA_ST_PTR + CommDataLength.SendDataLength + 1] = 0x00; // CheckSum

	CommDataLength.SendDataLength += FIXED_PACKET_LENGTH;
	CommDataLength.ReceivedDataLength += FIXED_PACKET_LENGTH;

	return CommDataLength;
}

//---------------------------------------------------------------------------
bool __fastcall RequestCameraCommand(char *sendData, char *receivedData, unsigned int SendDataLength, unsigned int ReceiveDataLength, int cameraIndex)
{
	int spbIndex = CameraMapInfo[cameraIndex].SPBIndex;

	const int MAX_COMM_DATA_LENGTH = 20;
	char tempSendData[MAX_COMM_DATA_LENGTH];
	memcpy(tempSendData + 2, sendData, sizeof(char) * SendDataLength);
	*(tempSendData + 0) = SendDataLength;
	*(tempSendData + 1) = ReceiveDataLength;
	SendDataLength += 2;

	 Comm_SetMaxWaitingTime(COMM_SPB + spbIndex, 30000);
	if (!Comm_Request(COMM_SPB + spbIndex, CMD_CAMERA_CONTROL_PROCESSING_MODE, tempSendData, SendDataLength, receivedData, ReceiveDataLength))
	{
	 	Comm_SetDefaultMaxWaitingTime(COMM_SPB + spbIndex);
		return false;
	}
	else
	{
	 	Comm_SetDefaultMaxWaitingTime(COMM_SPB + spbIndex);
		return true;
	}
}
//---------------------------------------------------------------------------

TROIInfo __fastcall SetThreeDCameraROI(TROIInfo srcInfo, TProductData *productData)
{
	TROIInfo retROIInfo;

	retROIInfo.StartX = srcInfo.StartX;
	retROIInfo.EndX = srcInfo.EndX;

	int DiskBaseHeight;
	int HtoPxConvValue;
	int tempStartY, tempEndY;
	int tempRowCount;

	DiskBaseHeight = srcInfo.EndY;
	HtoPxConvValue = productData->TabletThick * UNIT_CONVERT_CONSTANT_VALUE_FOR_3D;

	tempStartY = DiskBaseHeight - HtoPxConvValue - 15; // 임의로 오차를 고려한 값을 넣어줌.. 10 , 20170927 170%넘어가면 이미지 왜곡발생하여 크기 줄여줌 15 -> 12
	tempRowCount = ROW_COUNT_FOR_HIGH_SPEED;

	if (productData->TabletThick > productData->TabletSideThick * 2)
	{
		// 정제의 배가 많이 나와 틸팅이 심한 경우 이미지 왜곡 발생
		tempStartY = DiskBaseHeight - HtoPxConvValue - 12;
		tempRowCount = ROW_COUNT_FOR_HIGH_SPEED + SUB_ROI_COUNT;
	}

	if (productData->TabletShape == TABLET_SHAPE_OBLONG ||
	        productData->TabletShape == TABLET_SHAPE_OVAL ||
	        productData->TabletShape == TABLET_SHAPE_ETC)
	{
		if (productData->TabletLength > HARD_TILTING_STD_TABLET_LENGTH)
		{
			// 정제의 배가 많이 나와 틸팅이 심한 경우 이미지 왜곡 발생
			// 타원형, 장방형의 경우에는 어차피 정렬이 잘안되서 석션속도를 많이 올리지못함
			tempStartY = DiskBaseHeight - HtoPxConvValue - 12;
			tempRowCount = ROW_COUNT_FOR_HIGH_SPEED + SUB_ROI_COUNT;
		}
	}

	if (tempStartY + tempRowCount > DiskBaseHeight)
	{
		tempEndY = tempStartY + tempRowCount;
		tempRowCount = ROW_COUNT_FOR_HIGH_SPEED - (tempEndY - DiskBaseHeight);
	}

	tempEndY = tempStartY + tempRowCount;

	//retROIInfo.StartY = tempStartY;
	//retROIInfo.EndY = tempEndY;

	retROIInfo.StartY = srcInfo.StartY;
	retROIInfo.EndY = srcInfo.EndY;

	return retROIInfo;
}

//---------------------------------------------------------------------------

void ComponentSetEnabledStatus(TComponent *pComponent, bool bEnabled)
{
	int i;
	for (i = 0; i < pComponent->ComponentCount; i++)
	{
		if (pComponent->Components[i]->InheritsFrom(__classid(TButton)))
			((TButton *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TLabel)))
			((TLabel *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TEdit)))
			((TEdit *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TMemo)))
			((TMemo *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TButton)))
			((TButton *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TGroupBox)))
			((TGroupBox *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TRadioGroup)))
			((TRadioGroup *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TComboBox)))
			((TComboBox *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TCheckBox)))
			((TCheckBox *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TRadioButton)))
			((TRadioButton *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TListBox)))
			((TListBox *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TPanel)))
			((TPanel *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TStringGrid)))
			((TStringGrid *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TStaticText)))
			((TStaticText *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntLabel)))
			((TTntLabel *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntEdit)))
			((TTntEdit *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntButton)))
			((TTntButton *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntMemo)))
			((TTntMemo *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntStaticText)))
			((TTntStaticText *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntGroupBox)))
			((TTntGroupBox *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntRadioGroup)))
			((TTntRadioGroup *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntComboBox)))
			((TTntComboBox *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntCheckBox)))
			((TTntCheckBox *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntRadioButton)))
			((TTntRadioButton *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntListBox)))
			((TTntListBox *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntPanel)))
			((TTntPanel *)(pComponent->Components[i]))->Enabled = bEnabled;
		else if (pComponent->Components[i]->InheritsFrom(__classid(TTntStringGrid)))
			((TTntStringGrid *)(pComponent->Components[i]))->Enabled = bEnabled;

		// 재귀호출
		ComponentSetEnabledStatus(pComponent->Components[i], bEnabled);
	}
}
//---------------------------------------------------------------------------

void __fastcall GetNFACamera2DColorImage(Graphics::TBitmap *DstImage, unsigned char *srcImage, int ImageWidth, int ImageHeight, int cameraIndex, bool offsetSW, unsigned char *offsetImage, int SamplingMode)
{
	Graphics::TBitmap *tempImage = new Graphics::TBitmap;
	tempImage->Width = ImageWidth;
	tempImage->Height = ImageHeight;
	tempImage->PixelFormat = pf24bit;

	memcpy(DefectBayerImage, srcImage, SYSTEM_CAMERA_WIDTH * SYSTEM_CAMERA_HEIGHT);

	if (offsetSW)
	{
		if (SamplingMode == RESOLUTION_NORMAL_QUALITY)
		{
			int value;
			int x, y;
			int tempAddress, tempAddress2;
			int halfImageWidth;

			unsigned char restoreScaleImage[SYSTEM_CAMERA_WIDTH * SYSTEM_CAMERA_HEIGHT];
			memset(restoreScaleImage, 0, SYSTEM_CAMERA_WIDTH * SYSTEM_CAMERA_HEIGHT);

			halfImageWidth = ImageWidth / 2;

			for (y = 0; y < ImageHeight; y++)
			{
				for (x = 0; x < ImageWidth ; x++)
				{
					tempAddress = ImageWidth * y + x;
					tempAddress2 = halfImageWidth * (y / 2) + (x / 2);

					restoreScaleImage[tempAddress] = offsetImage[tempAddress2];
				}
			}

			for (y = 0; y < ImageHeight; y++)
			{
				for (x = 0; x < ImageWidth; x++)
				{
					tempAddress = ImageWidth * y + x;
					value = srcImage[tempAddress] - restoreScaleImage[tempAddress];
					if (value < 4)
						value = 4;

					srcImage[tempAddress] = value;

				}
			}
		}
		else if (SamplingMode == RESOLUTION_HIGH_QUALITY)
		{
			int value;
			int x, y;
			int tempAddress, tempAddress2;
			int halfImageWidth;

			unsigned char restoreLargeScaleImage[SYSTEM_CAMERA_HD_WIDTH * SYSTEM_CAMERA_HD_HEIGHT];
			memset(restoreLargeScaleImage, 0, SYSTEM_CAMERA_HD_WIDTH * SYSTEM_CAMERA_HD_HEIGHT);

			halfImageWidth = SYSTEM_CAMERA_HD_WIDTH / 4;

			for (y = 0; y < SYSTEM_CAMERA_HD_HEIGHT; y++)
			{
				for (x = 0; x < SYSTEM_CAMERA_HD_WIDTH ; x++)
				{
					tempAddress = SYSTEM_CAMERA_HD_WIDTH * y + x;
					tempAddress2 = halfImageWidth * (y / 4) + (x / 4);

					restoreLargeScaleImage[tempAddress] = offsetImage[tempAddress2];
				}
			}

			for (y = 0; y < SYSTEM_CAMERA_HD_HEIGHT; y++)
			{
				for (x = 0; x < SYSTEM_CAMERA_HD_WIDTH; x++)
				{
					tempAddress = SYSTEM_CAMERA_HD_WIDTH * y + x;
					value = srcImage[tempAddress] - restoreLargeScaleImage[tempAddress];
					if (value < 4)
						value = 4;

					srcImage[tempAddress] = value;

				}
			}
		}
	}

	Bayer_Conversion_GBRG(tempImage, srcImage, ImageWidth, ImageHeight, 2);
	ApplyWhiteBalance(cameraIndex, tempImage, DstImage);
	delete tempImage;
}
/*
*  2018-05-04 ldh
*  유저 아이디 Lock용 레지스트리 조작 함수 생성
*
*  _CreateReg(const char* PATH ,const char* ID) : 레지스트리가 있는지 검사하고 없으면 생성한다.
*
*  [INPUT]
*  PATH : 레지스트리 폴더 주소
*  ID : 유저 아이디
*/
void __fastcall _CreateReg(const char* PATH, const char* ID)
{

	LONG lResult;
	char buffer[100];
	HKEY hKey;
	DWORD dwDesc;
	int LengthSize = 0;
	String data = "";
	// 레지스트리 열고
	RegOpenKeyExA(HKEY_CURRENT_USER,
	              PATH,
	              0, KEY_ALL_ACCESS, &hKey);

	// Set Registry Key & Value
	lResult = RegCreateKeyExA(HKEY_CURRENT_USER,
	                          PATH,
	                          0, buffer,
	                          REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
	                          &hKey, &dwDesc);


	if (lResult == ERROR_SUCCESS)
	{
		LengthSize = strlen(ID);

		// 레지스트리 ID 값
		for (int z = 0; z < LengthSize; ++z)
		{
			data += (char)(ID[z] - 2);
		}

		String Tempword = (char)((ID[0] / 2) + 1);
		/*char m_v = new char;
		m_v = wordchar;*/
		RegSetValueExA(hKey, data.c_str(), 0, REG_SZ, (BYTE*)(Tempword.c_str()), 1); //strlen(wordchar)
	}

	//레지스트리 닫고
	RegCloseKey(hKey);
}
/*
*  _DeleteReg(const char* PATH ,const char* ID)  : 레지스트리를 삭제한다.
*
*  [INPUT]
*  PATH : 레지스트리 폴더 주소
*  ID : 유저 아이디
*/
void __fastcall _DeleteReg(const char* PATH, const char* ID)
{
	LONG lResult;
	HKEY hKey;
	DWORD dwBytes = 100;
	int LengthSize = 0;
	String data = "";
	// open Regstry Key
	lResult = RegOpenKeyExA(HKEY_CURRENT_USER,
	                        PATH,
	                        0, KEY_ALL_ACCESS, &hKey);

	if (lResult == ERROR_SUCCESS)
	{
		LengthSize = strlen(ID);

		// 레지스트리 ID 값
		for (int z = 0; z < LengthSize; ++z)
		{
			data += (char)(ID[z] - 2);
		}
	}



	lResult = RegDeleteValueA(hKey, data.c_str());  // 삭제

	RegCloseKey(hKey);
}
/*
*  _ReadReg(const char* PATH ,const char* ID)  : 레지스트리 값을 읽는다.
*
*  [INPUT]
*  PATH : 레지스트리 폴더 주소
*  ID : 유저 아이디
*
*  [RETURN]
*  불량  = 0 , 정상 : 1이상
*/
int __fastcall _ReadReg(const char* PATH, const char* ID)
{
	LONG lResult;
	HKEY hKey;
	DWORD dwType;
	DWORD dwBytes = 100;
	char buffer[100];
	String data = "";
	int LengthSize = 0;
	int iUnlockCode = 0;

	// 레지스트리 열고
	lResult = RegOpenKeyExA(HKEY_CURRENT_USER,
	                        PATH,
	                        0, KEY_ALL_ACCESS, &hKey);

	LengthSize = strlen(ID);

	if (lResult != ERROR_SUCCESS)
		return 0;
	// 레지스트리 ID 값

	for (int z = 0; z < LengthSize; ++z)
	{
		data += (char)(ID[z] - 2);
		iUnlockCode += ID[z];
	}

	int wordint = ((int)(ID[0] / 2));
	lResult = RegQueryValueExA(hKey, data.c_str(), 0, &dwType, (LPBYTE)buffer, &dwBytes);
	int Loadint = (int)(buffer[0]);
	String buffer_str = "";

	for (int i = 0; i < 100; ++i)
	{
		if (buffer[i] == '\0')
			break;

		buffer_str += IntToStr((int)(buffer[i] - '0'));
	}

	if (IntToStr(iUnlockCode + 9500) == buffer_str)
	{
		lResult = 99999999; // 락 해제 코드 비교 했을때 해제 코드가 들어있으면 99999999(8) return ;
	}
	else
	{
		if (lResult == ERROR_SUCCESS)
			lResult = abs(wordint - Loadint);
		else
			lResult = 0;
	}

	return lResult; //0 이면 불량 애초에 처음 생성때 1을 집어넣고 상승 시키기 때문에 가능
}
/*
*  _SetValueReg(const char* PATH ,const char* ID , int value)  : 레지스트리 값을 셋팅한다.
*
*  [INPUT]
*  PATH : 레지스트리 폴더 주소
*  ID : 유저 아이디
*  Value : 셋팅할 값  ( 로그인 실패횟수 ) or 그 외
*  [RETURN]
*  불량  = 0 , 정상 : 1
*/
int __fastcall _SetValueReg(const char* PATH, const char* ID, int value)
{
	HKEY hkey;
	LONG lResult;
	int LengthSize = 0;
	char buffer;
	DWORD dwDesc;
	String data = "";
	int iUnlockCode = 0;

	// 레지스트리 열고
	RegOpenKeyExA(HKEY_CURRENT_USER,
	              PATH,
	              0, KEY_ALL_ACCESS, &hkey);

	LengthSize = strlen(ID);

	// 레지스트리 ID 값
	for (int z = 0; z < LengthSize; ++z)
	{
		data += (char)(ID[z] - 2);
		iUnlockCode += ID[z];
	}

	// Value 값이 0일때는 언락을 위한 값 강제 셋팅
	if (value == 0)
	{
		String strUnlockCode = IntToStr((iUnlockCode + 9500));
		lResult = RegSetValueExA(hkey, data.c_str(), 0, REG_SZ, (BYTE*)strUnlockCode.c_str(), strlen(strUnlockCode.c_str()));

		if (lResult == ERROR_SUCCESS)
			lResult = 1;
		else
			lResult = 0;
	}
	else
	{
		// 레지스트리 값
		String Tempword = (char)((ID[0] / 2) + value);

		lResult = RegSetValueExA(hkey, data.c_str(), 0, REG_SZ, (BYTE*)Tempword.c_str(), 1);

		if (lResult == ERROR_SUCCESS)
			lResult = 1;
		else
			lResult = 0;
	}

	//레지스트리 닫고
	RegCloseKey(hkey);
	return lResult;
}
/*
*  _IDUnlockCheckReg(const char* PATH ,const char* ID )  : ID 언락 조건을 만족하면 언락 전용 값을 레지스트리에 작성한다.
*
*  [INPUT]
*  PATH : 레지스트리 폴더 주소
*  ID : 유저 아이디
*  [RETURN]
*  불량  = 0 , 정상 : 1
*/
int __fastcall _IDUnlockCheckReg(const char* PATH, const char* ID)
{
	LONG lResult;
	HKEY hKey;
	DWORD dwType;
	DWORD dwBytes = 100;
	char buffer[100];
	String data = "";
	int LengthSize = 0;

	int iUnlockCode = 0;
	String strUnlockCode = "";

	// 레지스트리 열고
	lResult = RegOpenKeyExA(HKEY_CURRENT_USER,
	                        PATH,
	                        0, KEY_ALL_ACCESS, &hKey);

	LengthSize = strlen(ID);

	if (lResult != ERROR_SUCCESS)
		return 0;

	// 레지스트리 ID 값
	for (int z = 0; z < LengthSize; ++z)
	{
		data += (char)(ID[z] - 2);
		iUnlockCode += ID[z];
	}

	strUnlockCode = IntToStr((iUnlockCode + 9500));
	lResult = RegQueryValueExA(hKey, data.c_str(), 0, &dwType, (LPBYTE)buffer, &dwBytes);

	String strBuf = buffer;
	for (int k = 0; k < strUnlockCode.Length(); ++k)
	{
		if (strUnlockCode.SubString(k, 1) != strBuf.SubString(k, 1))
		{
			return 0;
		}
	}

	return 1;
}
//---------------------------------------------------------------------------
bool __fastcall checkCameraArea(TProductData *pProductData, bool *pErrorCamera)
{
	int globalCameraIndex;
	int left, right, top, bottom;
	int width, height;
	bool bErrorOccur = false;

	for (globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
	{
    if(GlobalProgramID == PROGRAM_ID_150P)
    {
      if(SystemLinkCameraInfo[globalCameraIndex] == false)
      {
        continue;
      }
    }

		left = pProductData->BoundaryLeft[globalCameraIndex];
		right = pProductData->BoundaryRight[globalCameraIndex];
		top = pProductData->BoundaryTop[globalCameraIndex];
		bottom = pProductData->BoundaryBottom[globalCameraIndex];

		width = right - left;
		height = bottom - top;

		pErrorCamera[globalCameraIndex] = false;
		if (width < 0)
		{
			pErrorCamera[globalCameraIndex] = true;
			bErrorOccur = true;
		}
		if (height < 0)
		{
			pErrorCamera[globalCameraIndex] = true;
			bErrorOccur = true;
		}
	}

	return bErrorOccur;
}
//---------------------------------------------------------------------------
bool __fastcall WritePCProgramErrorLog(AnsiString ClassName, int ErrorLine)
{
	bool returnValue = true;
	int ErrorIndex;

	AnsiString fileName;
	fileName = ProgramPath.Env + "\\PC_Error_Log.ini";

	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		ErrorIndex = iniFile->ReadInteger("Index", "Current Log Index", 0);
		ErrorIndex++;

		if (ErrorIndex >= 500)
			ErrorIndex = 1;

		iniFile->WriteInteger("Index", "Current Log Index", ErrorIndex);

		iniFile->WriteString(IntToStr(ErrorIndex), "Class Name", ClassName);
		iniFile->WriteInteger(IntToStr(ErrorIndex), "Error Line", ErrorLine);
		iniFile->WriteString(IntToStr(ErrorIndex), "Time", Now().DateTimeString());

		delete iniFile;
	}
	else
	{
		returnValue = false;
	}
	return returnValue;
}

//---------------------------------------------------------------------------
bool __fastcall ReductionImageScale(Graphics::TBitmap *bitmap)
{
	bool returnValue = true;

	int x, y;
	int tempX, tempY;
	int prevImageWidth;
	int prevImageHeight;

	Byte *ptr1, *ptr2;

	Graphics::TBitmap *tempImage;

	try
	{
		tempImage = new Graphics::TBitmap();

		tempImage->Width = SYSTEM_CAMERA_WIDTH;
		tempImage->Height = SYSTEM_CAMERA_HEIGHT;
		tempImage->PixelFormat = pf24bit;

		prevImageWidth = bitmap->Width;
		prevImageHeight = bitmap->Height;

		if (prevImageWidth == SYSTEM_CAMERA_HD_WIDTH)
		{
			for (y = 0; y < prevImageHeight; y += 2)
			{
				tempY = y / 2;

				ptr1 = (Byte*)bitmap->ScanLine[y];
				ptr2 = (Byte*)tempImage->ScanLine[tempY];

				for (x = 0; x < prevImageWidth; x += 2)
				{
					tempX = x / 2;

					ptr2[tempX * 3 + 0] = ptr1[x * 3 + 0];
					ptr2[tempX * 3 + 1] = ptr1[x * 3 + 1];
					ptr2[tempX * 3 + 2] = ptr1[x * 3 + 2];
				}
			}

			bitmap->Assign(tempImage);
		}
		else
		{
			returnValue = false;
		}

		delete tempImage;
	}
	catch (...)
	{
		if (tempImage)
			delete tempImage;

		returnValue = false;
	}

	return returnValue;
}
//---------------------------------------------------------------------------
bool __fastcall ReadGlobalLSFTable(AnsiString fileName)
{
	if (!FileExists(fileName))
	{
		return false;
	}

	TFileStream *fileStream = new TFileStream(fileName, fmOpenRead);
	if (fileStream)
	{
		fileStream->Read(GlobalSD1LSFTable, sizeof(int) * MAX_MOTOR_SPEED);
		fileStream->Read(GlobalSD2LSFTable, sizeof(int) * MAX_MOTOR_SPEED);
		delete fileStream;
	}
	else
	{
		return false;
	}

	return true;
}
//---------------------------------------------------------------------------
bool __fastcall ReadCameraID(AnsiString fileName)
{
	// 초기값
	int SequentialCount = 0;
	for (int cameraIndex = 1; cameraIndex <= SYSTEM_TOTAL_CAMERA_COUNT; cameraIndex++)
	{
		if (SystemLinkCameraInfo[cameraIndex - 1])
		{
			SequentialCount++;
			SystemCameraID[cameraIndex - 1] = "C" + IntToStr(SequentialCount);
		}
	}

	if (!FileExists(fileName))
	{
		return false;
	}

	TIniFile *iniFile = new TIniFile(fileName);
	if (iniFile)
	{
		for (int cameraIndex = 1; cameraIndex <= SYSTEM_TOTAL_CAMERA_COUNT; cameraIndex++)
		{
			if (SystemLinkCameraInfo[cameraIndex - 1])
			{
				if (GlobalProgramID == PROGRAM_ID_150P)
				{
					SystemCameraID[cameraIndex - 1] = iniFile->ReadString("TVM150P Camera ID", "System Camera " + IntToStr(cameraIndex), SystemCameraID[cameraIndex - 1]);
				}
				else
				{
					SystemCameraID[cameraIndex - 1] = iniFile->ReadString("TVM200 Camera ID", "System Camera " + IntToStr(cameraIndex), SystemCameraID[cameraIndex - 1]);
				}
			}
		}

		delete iniFile;
	}
	else
	{
		return false;
	}
	return true;
}

bool __fastcall IsExistProcess(AnsiString ProcessName)
{
	bool ret = false;
	HANDLE hProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

	if (hProcess != NULL)
	{
		PROCESSENTRY32 pe32 = {0};
		pe32.dwSize = sizeof(PROCESSENTRY32);

		if (Process32First(hProcess, &pe32))
		{
			do
			{
				if (AnsiString(pe32.szExeFile) == ProcessName)
				{
					ret = true;
					break;
				}
			}
			while (Process32Next(hProcess, &pe32));
		}
		CloseHandle(hProcess);
	}

	return ret;
}
//---------------------------------------------------------------------------------------------------
void __fastcall _SetKeyHookReg(const char* First_PATH , const char* Second_PATH ,bool AccessState)
{
  LONG lResult;
  char buffer[100];
  HKEY hKey;
  DWORD dwDesc;
  int LengthSize= 0;
  String data="";
  // 레지스트리 폴더 확인 후 생성
  lResult =RegOpenKeyExA(HKEY_CURRENT_USER,
              First_PATH,
              0, KEY_ALL_ACCESS, &hKey);

  if(lResult != ERROR_SUCCESS)
  {
    lResult = RegCreateKeyExA(HKEY_CURRENT_USER,
                            First_PATH,
                            0, buffer,
                            REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
                            &hKey, &dwDesc);
    RegCloseKey(hKey);
  }

  lResult =RegOpenKeyExA(HKEY_CURRENT_USER,
              Second_PATH,
              0, KEY_ALL_ACCESS, &hKey);

  if(lResult != ERROR_SUCCESS)
  {
    lResult = RegCreateKeyExA(HKEY_CURRENT_USER,
                            Second_PATH,
                            0, buffer,
                            REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
                            &hKey, &dwDesc);
    RegCloseKey(hKey);
  }

  lResult =RegOpenKeyExA(HKEY_CURRENT_USER,
              First_PATH,
              0, KEY_ALL_ACCESS, &hKey);

  if(lResult == ERROR_SUCCESS)
  {
    DWORD Val = 1;

    if(AccessState)
      Val = 0;

    RegSetValueExA(hKey,"DisableChangePassword", 0, REG_DWORD, (LPBYTE)&Val, sizeof(Val));   //(BYTE*)(Tempword.c_str())
    RegSetValueExA(hKey,"DisableLockWorkstation", 0, REG_DWORD, (LPBYTE)&Val, sizeof(Val));   //(BYTE*)(Tempword.c_str())
    RegSetValueExA(hKey,"DisableTaskMgr", 0, REG_DWORD, (LPBYTE)&Val, sizeof(Val));   //(BYTE*)(Tempword.c_str())

    RegCloseKey(hKey);
  }

  lResult =RegOpenKeyExA(HKEY_CURRENT_USER,
              Second_PATH,
              0, KEY_ALL_ACCESS, &hKey);

  if(lResult == ERROR_SUCCESS)
  {
    lResult = RegCreateKeyExA(HKEY_CURRENT_USER,
                            Second_PATH,
                            0, buffer,
                            REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
                            &hKey, &dwDesc);
    DWORD Val = 1;

    if(AccessState)
      Val = 0;

    if(lResult == ERROR_SUCCESS)
    {
      lResult = RegSetValueExA(hKey,"NoLogoff", 0, REG_DWORD, (LPBYTE)&Val, sizeof(Val));   //(BYTE*)(Tempword.c_str())
    }
    RegCloseKey(hKey);
}
}
//-----------------------------------------------------------------------------------------
void __fastcall KeyMonitorActive(bool DestoryOption)
{
  HWND hWnd = FindWindowA(NULL,"NFAKeyMonitor"); 

  if(FileExists("NFAKeyMonitor.exe"))// SELMA H프로그램으로 실행하면 경로를 다르게 잡나?
  {
    if(DestoryOption)
    {
      _SetKeyHookReg("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
      "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer",false);
      if(!hWnd)
        ShellExecuteA(NULL,"open","NFAKeyMonitor.exe",NULL,NULL,SW_SHOW);
      return;
    }

    if(UserInfo.AccessLevel == SYSTEM_HIGHEST_ACCESS_LEVEL) 
    {
      _SetKeyHookReg("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
      "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer",true);
      if(hWnd) 
      { 
        HWND hWndt = ::FindWindowA(0,"NFAKeyMonitor");
        if(hWndt)
        {
          SendMessage(hWndt,WM_CLOSE,0,0);
        }
      }

    }
    else
    {
      _SetKeyHookReg("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
      "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer",false);
      if(!hWnd)
        ShellExecuteA(NULL,"open","NFAKeyMonitor.exe",NULL,NULL,SW_SHOW);
    }

  }
}
//---------------------------------------------------------------------------
void __fastcall WriteBackupProgramOption(AnsiString fileName, TPCProgramOption &pcProgramOption)
{
	TIniFile *iniFile = new TIniFile(fileName);
	
	if (iniFile)
	{
		iniFile->WriteInteger("Process Speed", "BackupSpeedMode", pcProgramOption.BackupSpeedMode);   	
		delete iniFile;
	}
}
//---------------------------------------------------------------------------
void __fastcall InitQueryTime()
{
  QueryPerformanceFrequency( &Frequency );
}
//---------------------------------------------------------------------------
void __fastcall WriteProcessingBeginTime()
{
  QueryPerformanceCounter( &TotalBeginTime );
}
//---------------------------------------------------------------------------
void __fastcall WriteProcessingEndTime()
{
  QueryPerformanceCounter( &TotalEndtime );
}
//---------------------------------------------------------------------------
double __fastcall GetProcessingElapsedTime()
{
  __int64 elapsed = TotalEndtime.QuadPart- TotalBeginTime.QuadPart;
  double duringtime = ((double)elapsed / (double)Frequency.QuadPart) * 1000; //ms로 변환
  return duringtime;
}
//---------------------------------------------------------------------------
void __fastcall WriteCheckBeginTime()
{
  QueryPerformanceCounter( &CheckBeginTime );
}
//---------------------------------------------------------------------------
void __fastcall WriteCheckEndTime()
{
  QueryPerformanceCounter( &CheckEndtime );
}
//---------------------------------------------------------------------------
double __fastcall GetCheckElapsedTime(int mode)
{
  __int64 elapsed;
  double duringtime;
  if (mode == 1)
  {
    elapsed = CheckBeginTime.QuadPart- TotalBeginTime.QuadPart; // 1 = 전체 프로세싱 시작부터 체크 시작까지의 소요시간.
  }
  else if (mode == 2)
  {
    elapsed = TotalEndtime.QuadPart- CheckEndtime.QuadPart; // 2 = 체크 끝부터 체크 전체 프로세팅 끝까지의 소요시간.
  }
  else
  {
    elapsed = CheckEndtime.QuadPart- CheckBeginTime.QuadPart; // 0 = 체크 시작부터 끝의 소요시간.
  }

  duringtime = ((double)elapsed / (double)Frequency.QuadPart) * 1000; //ms로 변환
  return duringtime;
}
//---------------------------------------------------------------------------
void __fastcall ShowHintByName(TWinControl *winControl)
{
  for (int c = 0, cmax = winControl->ControlCount; c < cmax; c++)
  {
    TControl* ctrl = winControl->Controls[c];
    if (ctrl->Hint == NULL || ctrl->Hint == "")
    {
      ctrl->Hint = ctrl->Name;
    }
    ctrl->ShowHint = true;

    // Check if it's grouping component
    TWinControl* wc = dynamic_cast<TWinControl*>(ctrl);
    if (wc != NULL)
    {
      ShowHintByName(wc);
    }
  }
}
//---------------------------------------------------------------------------
