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

#include <vcl.h>
#include <inifiles.hpp>
#pragma hdrstop

#include "Main_Form.h"
#include "FileContainer.h"
#include "Bayer.h"
#include "Common_PC.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "CGAUGES"
#pragma link "TntButtons"
#pragma link "TntExtCtrls"
#pragma link "TntForms"
#pragma link "TntStdCtrls"
#pragma resource "*.dfm"
TMainForm *MainForm;

#define IMAGE_WIDTH_3D 			320
#define IMAGE_HEIGHT_3D			480
const int cProductImageCount = 100;
const int cTotalCameraCount = 10;
#define DEFECT_DATA_CONTAINER_SIZE			1000

typedef struct
{
	int Version;
	int dummy[3];
} TDefectDataHeader;

typedef struct
{
	TDefectDataHeader DefectDataHeader;
	TDefectData_PC DefectData;
} TDefectFileData;
//---------------------------------------------------------------------------
__fastcall TMainForm::TMainForm(TComponent* Owner)
	: TTntForm(Owner)
{
	BreakProcess = false;
	SelectedFACFileName = "";

	ImagePanel->BringToFront();
	ApplyDirChange();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ApplyDirChange(void)
{
	DirectoryEdit->Text = DirectoryListBox->Directory;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::StartButtonClick(TObject *Sender)
{
	BreakProcess = false;
	if (DataCompressSpeedButton->Down)
	{
		// compress
		CompressFolder();
	}
	else if (DataExtractSpeedButton->Down)
	{
		// extract
		ExtractBitmap();
	}
	else if (DataUpConversionSpeedButton->Down)
	{
		DataUpConversion();
	}
	else if (DataDownConversionSpeedButton->Down)
	{
		DataDownConversion();
	}

	if (!BreakProcess)
	{
		ShowMessage("작업이 완료되었습니다.");
	}
	else
	{
		ShowMessage("작업이 중단되었습니다.");
	}
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::DirectoryListBoxChange(TObject *Sender)
{
	ApplyDirChange();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::CompressData(AnsiString srcDir, bool bRemoveSrc, bool bCompressProductImage, bool bCompressDefectImage)
{
	SrcDirLabel->Caption = srcDir;
	
	if (bCompressProductImage)
	{
		// compress product image
		ProductImageProgressCGauge->MaxValue = cProductImageCount;
		ProductImageProgressCGauge->Progress = 0;
		for (int imageIndex = 0; imageIndex < cProductImageCount; imageIndex++)
		{
			AnsiString containerFileName = srcDir + "\\Image" + IntToStr(imageIndex + 1) + ".FAC";
			TFileContainer *productImageFileContainer = new TFileContainer;
			bool bContainerCreated = false;
			for (int globalCameraIndex = 0; globalCameraIndex < cTotalCameraCount; globalCameraIndex++)
			{
				AnsiString imageFileName = srcDir + "\\Image" + IntToStr(imageIndex + 1) + "_" + IntToStr(globalCameraIndex + 1) + ".bmp";
				AnsiString compressedBitmapName = "Image" + IntToStr(imageIndex + 1) + "_" + IntToStr(globalCameraIndex + 1) + ".fbm";
				if (FileExists(imageFileName))
				{
					if (!bContainerCreated)
					{
						productImageFileContainer->Create(containerFileName, cTotalCameraCount + 2);
						bContainerCreated = true;
					}

					if (globalCameraIndex == 0 || globalCameraIndex == 5)	// 1번 6번 카메라
					{
						Graphics::TBitmap *colorBitmap = new Graphics::TBitmap;
						colorBitmap->LoadFromFile(imageFileName);
						// convert to bayer image
						unsigned char *bayerData = new unsigned char[colorBitmap->Width * colorBitmap->Height];
						for (int y = 0; y < colorBitmap->Height; y++)
						{
							byte *pBitmap = (byte *) colorBitmap->ScanLine[colorBitmap->Height - 1 - y];
							for (int x = 0; x < colorBitmap->Width; x++)
							{
								if ((y & 0x01) == 0)
								{
									if ((x & 0x01) == 0)	// B
									{
										bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x];
									}
									else					// G
									{
										bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 1];
									}
								}
								else
								{
									if ((x & 0x01) == 0)	// G
									{
										bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 1];
									}
									else					// R
									{
										bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 2];
									}
								}
							}
						}
						productImageFileContainer->SaveBitmapData(compressedBitmapName, ECM_ZIP,
							bayerData, colorBitmap->Width, colorBitmap->Height, 8, globalCameraIndex, EBK_2D);

						delete[] bayerData;
						delete colorBitmap;
					}
					else if (globalCameraIndex == 2 || globalCameraIndex == 4)	// 3번 5번 카메라
					{
						Graphics::TBitmap *colorBitmap = new Graphics::TBitmap;
						colorBitmap->LoadFromFile(imageFileName);
						// convert to bayer image
						unsigned char *bayerData = new unsigned char[colorBitmap->Width * colorBitmap->Height];
						for (int y = 0; y < colorBitmap->Height; y++)
						{
							byte *pBitmap = (byte *) colorBitmap->ScanLine[colorBitmap->Height - 1 - y];
							for (int x = 0; x < colorBitmap->Width; x++)
							{
								if ((y & 0x01) == 0)
								{
									if ((x & 0x01) == 0)	// B
									{
										bayerData[y * colorBitmap->Width + x] = pBitmap[3 * (colorBitmap->Width - 1 - x)];
									}
									else					// G
									{
										bayerData[y * colorBitmap->Width + x] = pBitmap[3 * (colorBitmap->Width - 1 - x) + 1];
									}
								}
								else
								{
									if ((x & 0x01) == 0)	// G
									{
										bayerData[y * colorBitmap->Width + x] = pBitmap[3 * (colorBitmap->Width - 1 - x) + 1];
									}
									else					// R
									{
										bayerData[y * colorBitmap->Width + x] = pBitmap[3 * (colorBitmap->Width - 1 - x) + 2];
									}
								}
							}
						}
						productImageFileContainer->SaveBitmapData(compressedBitmapName, ECM_ZIP,
							bayerData, colorBitmap->Width, colorBitmap->Height, 8, globalCameraIndex, EBK_2D);

						delete[] bayerData;
						delete colorBitmap;
					}
					else if (globalCameraIndex == 3 || globalCameraIndex == 7 || globalCameraIndex == 8 || globalCameraIndex == 9)	// 4번 8번 9번 10번 카메라
					{
						Graphics::TBitmap *colorBitmap = new Graphics::TBitmap;
						colorBitmap->LoadFromFile(imageFileName);
						// convert to bayer image
						unsigned char *bayerData = new unsigned char[colorBitmap->Width * colorBitmap->Height];
						for (int y = 0; y < colorBitmap->Height; y++)
						{
							byte *pBitmap = (byte *) colorBitmap->ScanLine[y];
							for (int x = 0; x < colorBitmap->Width; x++)
							{
								if ((y & 0x01) == 0)
								{
									if ((x & 0x01) == 0)	// B
									{
										bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x];
									}
									else					// G
									{
										bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 1];
									}
								}
								else
								{
									if ((x & 0x01) == 0)	// G
									{
										bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 1];
									}
									else					// R
									{
										bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 2];
									}
								}
							}
						}
						productImageFileContainer->SaveBitmapData(compressedBitmapName, ECM_ZIP,
							bayerData, colorBitmap->Width, colorBitmap->Height, 8, globalCameraIndex, EBK_2D);

						delete[] bayerData;
						delete colorBitmap;
					}
					else 	// 3D camera image
					{
						Graphics::TBitmap *colorBitmap = new Graphics::TBitmap;
						colorBitmap->LoadFromFile(imageFileName);
						// convert to bayer image
						unsigned char *threeDData = new unsigned char[colorBitmap->Width * colorBitmap->Height];
						for (int y = 0; y < colorBitmap->Height; y++)
						{
							byte *pBitmap = (byte *) colorBitmap->ScanLine[y];
							for (int x = 0; x < colorBitmap->Width; x++)
							{
								threeDData[x * colorBitmap->Height + y] = pBitmap[x];
							}
						}
						productImageFileContainer->SaveBitmapData(compressedBitmapName, ECM_ZIP,
							threeDData, colorBitmap->Height, colorBitmap->Width, 8, globalCameraIndex, EBK_3D);

						delete[] threeDData;
						delete colorBitmap;
					}
					if (bRemoveSrc)
					{
						DeleteFile(imageFileName);
					}
				}
			}

			AnsiString imageFileName = srcDir + "\\Image" + IntToStr(imageIndex + 1) + "_1_O.bmp";
			AnsiString compressedBitmapName = "Image" + IntToStr(imageIndex + 1) + "_1_O.fbm";
			if (FileExists(imageFileName))
			{
				if (!bContainerCreated)
				{
					productImageFileContainer->Create(containerFileName, cTotalCameraCount + 2);
					bContainerCreated = true;
				}
				Graphics::TBitmap *colorBitmap = new Graphics::TBitmap;
				colorBitmap->LoadFromFile(imageFileName);
				// convert to bayer image
				unsigned char *bayerData = new unsigned char[colorBitmap->Width * colorBitmap->Height];
				for (int y = 0; y < colorBitmap->Height; y++)
				{
					byte *pBitmap = (byte *) colorBitmap->ScanLine[colorBitmap->Height - 1 - y];
					for (int x = 0; x < colorBitmap->Width; x++)
					{
						if ((y & 0x01) == 0)
						{
							if ((x & 0x01) == 0)	// B
							{
								bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x];
							}
							else					// G
							{
								bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 1];
							}
						}
						else
						{
							if ((x & 0x01) == 0)	// G
							{
								bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 1];
							}
							else					// R
							{
								bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 2];
							}
						}
					}
				}
				productImageFileContainer->SaveBitmapData(compressedBitmapName, ECM_ZIP,
					bayerData, colorBitmap->Width, colorBitmap->Height, 8, 0, EBK_2D);
				delete[] bayerData;
				delete colorBitmap;
				if (bRemoveSrc)
				{
					DeleteFile(imageFileName);
				}
			}

			imageFileName = srcDir + "\\Image" + IntToStr(imageIndex + 1) + "_6_O.bmp";
			compressedBitmapName = "Image" + IntToStr(imageIndex + 1) + "_6_O.fbm";
			if (FileExists(imageFileName))
			{
				if (!bContainerCreated)
				{
					productImageFileContainer->Create(containerFileName, cTotalCameraCount + 2);
					bContainerCreated = true;
				}
				Graphics::TBitmap *colorBitmap = new Graphics::TBitmap;
				colorBitmap->LoadFromFile(imageFileName);
				// convert to bayer image
				unsigned char *bayerData = new unsigned char[colorBitmap->Width * colorBitmap->Height];
				for (int y = 0; y < colorBitmap->Height; y++)
				{
					byte *pBitmap = (byte *) colorBitmap->ScanLine[colorBitmap->Height - 1 - y];
					for (int x = 0; x < colorBitmap->Width; x++)
					{
						if ((y & 0x01) == 0)
						{
							if ((x & 0x01) == 0)	// B
							{
								bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x];
							}
							else					// G
							{
								bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 1];
							}
						}
						else
						{
							if ((x & 0x01) == 0)	// G
							{
								bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 1];
							}
							else					// R
							{
								bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 2];
							}
						}
					}
				}
				productImageFileContainer->SaveBitmapData(compressedBitmapName, ECM_ZIP,
					bayerData, colorBitmap->Width, colorBitmap->Height, 8, 5, EBK_2D);
				delete[] bayerData;
				delete colorBitmap;
				if (bRemoveSrc)
				{
					DeleteFile(imageFileName);
				}
			}
			delete productImageFileContainer;
			ProductImageProgressCGauge->Progress++;
			Application->ProcessMessages();
			if (BreakProcess)
			{
				BreakProcess = false;
				break;
			}
		}
	}

	if (bCompressDefectImage)
	{
		// compress defect image
		int defectDataCount = 0;
		TIniFile *iniFile = new TIniFile(srcDir + "\\DBInfor.ini");
		if (iniFile)
		{
			defectDataCount = iniFile->ReadInteger("Information", "Data Count", 0);
			delete iniFile;
		}
		ProductImageProgressCGauge->MaxValue = defectDataCount;
		ProductImageProgressCGauge->Progress = 0;


		bool bContainerCreated = false;
		int containerIndex = 0;
		TFileContainer defectDataFileContainer;
		TFileContainer defectImageFileContainer;

		for (int defectIndex = 0; defectIndex < defectDataCount; defectIndex++)
		{
			if (defectIndex >= (containerIndex + 1) * DEFECT_DATA_CONTAINER_SIZE)
			{
				defectDataFileContainer.Close();
				defectImageFileContainer.Close();
				bContainerCreated = false;
				containerIndex++;

				Application->ProcessMessages();
				if (BreakProcess) break;
			}
			AnsiString imageFileName = srcDir + "\\Image" + IntToStr(defectIndex + 1) + ".bmp";
			AnsiString defectDataFileName = srcDir + "\\Data" + IntToStr(defectIndex + 1) + ".dat";
			AnsiString compressedBitmapName = "Image" + IntToStr(defectIndex + 1) + ".fbm";
			AnsiString dataName = "Data" + IntToStr(defectIndex + 1) + ".dat";

			if (FileExists(imageFileName) && FileExists(defectDataFileName))
			{
				if (!bContainerCreated)
				{
					AnsiString imageContainerFileName = srcDir + "\\DefectImage" + IntToStr(containerIndex + 1) + ".FAC";
	//				defectImageFileContainer.Open(imageContainerFileName, true, DEFECT_DATA_CONTAINER_SIZE);
					defectImageFileContainer.Create(imageContainerFileName, DEFECT_DATA_CONTAINER_SIZE);
					AnsiString dataContainerFileName = srcDir + "\\DefectData" + IntToStr(containerIndex + 1) + ".FAC";
	//				defectDataFileContainer.Open(dataContainerFileName, true, DEFECT_DATA_CONTAINER_SIZE);
					defectDataFileContainer.Create(dataContainerFileName, DEFECT_DATA_CONTAINER_SIZE);
					bContainerCreated = true;
				}


				TDefectFileData defectFileData;
				TFileStream *fileStream = new TFileStream(defectDataFileName, fmOpenRead);
				if (fileStream)
				{
					fileStream->Read(&defectFileData, sizeof(TDefectFileData));
					delete fileStream;
				}
				else
				{
					// defect data cannot read
					continue;
				}

				defectDataFileContainer.SaveData(dataName, ECM_NONE, &defectFileData, sizeof(TDefectFileData));
				int globalCameraIndex = defectFileData.DefectData.GlobalCameraIndex;

				if (globalCameraIndex == 0 || globalCameraIndex == 5)	// 1번 6번 카메라
				{
					Graphics::TBitmap *colorBitmap = new Graphics::TBitmap;
					colorBitmap->LoadFromFile(imageFileName);
					// convert to bayer image
					unsigned char *bayerData = new unsigned char[colorBitmap->Width * colorBitmap->Height];
					for (int y = 0; y < colorBitmap->Height; y++)
					{
						byte *pBitmap = (byte *) colorBitmap->ScanLine[colorBitmap->Height - 1 - y];
						for (int x = 0; x < colorBitmap->Width; x++)
						{
							if ((y & 0x01) == 0)
							{
								if ((x & 0x01) == 0)	// B
								{
									bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x];
								}
								else					// G
								{
									bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 1];
								}
							}
							else
							{
								if ((x & 0x01) == 0)	// G
								{
									bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 1];
								}
								else					// R
								{
									bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 2];
								}
							}
						}
					}
					defectImageFileContainer.SaveBitmapData(compressedBitmapName, ECM_ZIP,
						bayerData, colorBitmap->Width, colorBitmap->Height, 8, globalCameraIndex, EBK_2D);

					delete[] bayerData;
					delete colorBitmap;
				}
				else if (globalCameraIndex == 2 || globalCameraIndex == 4)	// 3번 5번 카메라
				{
					Graphics::TBitmap *colorBitmap = new Graphics::TBitmap;
					colorBitmap->LoadFromFile(imageFileName);
					// convert to bayer image
					unsigned char *bayerData = new unsigned char[colorBitmap->Width * colorBitmap->Height];
					for (int y = 0; y < colorBitmap->Height; y++)
					{
						byte *pBitmap = (byte *) colorBitmap->ScanLine[colorBitmap->Height - 1 - y];
						for (int x = 0; x < colorBitmap->Width; x++)
						{
							if ((y & 0x01) == 0)
							{
								if ((x & 0x01) == 0)	// B
								{
									bayerData[y * colorBitmap->Width + x] = pBitmap[3 * (colorBitmap->Width - 1 - x)];
								}
								else					// G
								{
									bayerData[y * colorBitmap->Width + x] = pBitmap[3 * (colorBitmap->Width - 1 - x) + 1];
								}
							}
							else
							{
								if ((x & 0x01) == 0)	// G
								{
									bayerData[y * colorBitmap->Width + x] = pBitmap[3 * (colorBitmap->Width - 1 - x) + 1];
								}
								else					// R
								{
									bayerData[y * colorBitmap->Width + x] = pBitmap[3 * (colorBitmap->Width - 1 - x) + 2];
								}
							}
						}
					}
					defectImageFileContainer.SaveBitmapData(compressedBitmapName, ECM_ZIP,
						bayerData, colorBitmap->Width, colorBitmap->Height, 8, globalCameraIndex, EBK_2D);

					delete[] bayerData;
					delete colorBitmap;
				}
				else if (globalCameraIndex == 3 || globalCameraIndex == 7 || globalCameraIndex == 8 || globalCameraIndex == 9)	// 4번 8번 9번 10번 카메라
				{
					Graphics::TBitmap *colorBitmap = new Graphics::TBitmap;
					colorBitmap->LoadFromFile(imageFileName);
					// convert to bayer image
					unsigned char *bayerData = new unsigned char[colorBitmap->Width * colorBitmap->Height];
					for (int y = 0; y < colorBitmap->Height; y++)
					{
						byte *pBitmap = (byte *) colorBitmap->ScanLine[y];
						for (int x = 0; x < colorBitmap->Width; x++)
						{
							if ((y & 0x01) == 0)
							{
								if ((x & 0x01) == 0)	// B
								{
									bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x];
								}
								else					// G
								{
									bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 1];
								}
							}
							else
							{
								if ((x & 0x01) == 0)	// G
								{
									bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 1];
								}
								else					// R
								{
									bayerData[y * colorBitmap->Width + x] = pBitmap[3 * x + 2];
								}
							}
						}
					}
					defectImageFileContainer.SaveBitmapData(compressedBitmapName, ECM_ZIP,
						bayerData, colorBitmap->Width, colorBitmap->Height, 8, globalCameraIndex, EBK_2D);

					delete[] bayerData;
					delete colorBitmap;
				}
				else 	// 3D camera image
				{
					Graphics::TBitmap *colorBitmap = new Graphics::TBitmap;
					colorBitmap->LoadFromFile(imageFileName);
					// convert to bayer image
					unsigned char *threeDData = new unsigned char[colorBitmap->Width * colorBitmap->Height];
					for (int y = 0; y < colorBitmap->Height; y++)
					{
						byte *pBitmap = (byte *) colorBitmap->ScanLine[y];
						for (int x = 0; x < colorBitmap->Width; x++)
						{
							threeDData[x * colorBitmap->Height + y] = pBitmap[x];
						}
					}
					defectImageFileContainer.SaveBitmapData(compressedBitmapName, ECM_ZIP,
						threeDData, colorBitmap->Height, colorBitmap->Width, 8, globalCameraIndex, EBK_3D);

					delete[] threeDData;
					delete colorBitmap;
				}
				if (bRemoveSrc)
				{
					DeleteFile(imageFileName);
					DeleteFile(defectDataFileName);
				}
				ProductImageProgressCGauge->Progress++;
			}
		}
		defectImageFileContainer.Close();
		defectDataFileContainer.Close();
	}
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::CompressFolder(void)
{
	AnsiString targetDir = DirectoryEdit->Text;
	bool bRemoveSrc = RemoveSourceCheckBox->Checked;
	CompressData(targetDir, bRemoveSrc, true, true);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ExtractBitmap(void)
{
	AnsiString targetDir = DirectoryEdit->Text;
	bool bRemoveSrc = RemoveSourceCheckBox->Checked;
	ExtractData(targetDir, bRemoveSrc, true, true);
}
//---------------------------------------------------------------------------
bool __fastcall TMainForm::ExtractImageFromContainer(Graphics::TBitmap *bitmap, 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;
		}
		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;
			Bayer_Conversion_BGGR(bitmap, bitmapData, bitmapHeader.Width, bitmapHeader.Height, 2);

			if (globalCameraNumber == 3 || globalCameraNumber == 5)	// rotate 180 degree
			{
				byte *pTempLineT = new byte[bitmapWidth * 3];
				byte *pTempLineB = new byte[bitmapWidth * 3];
				for (int y = 0; y < (bitmapHeight + 1) / 2; y++)
				{
					byte *pBitmapT = (byte *)bitmap->ScanLine[y];
					byte *pBitmapB = (byte *)bitmap->ScanLine[bitmapHeight - 1 - y];

					for (int x = 0; x < bitmapWidth; x++)
					{
						pTempLineT[x * 3 + 0] = pBitmapB[(bitmapWidth - 1 - x) * 3 + 0];
						pTempLineB[x * 3 + 0] = pBitmapT[(bitmapWidth - 1 - x) * 3 + 0];
						pTempLineT[x * 3 + 1] = pBitmapB[(bitmapWidth - 1 - x) * 3 + 1];
						pTempLineB[x * 3 + 1] = pBitmapT[(bitmapWidth - 1 - x) * 3 + 1];
						pTempLineT[x * 3 + 2] = pBitmapB[(bitmapWidth - 1 - x) * 3 + 2];
						pTempLineB[x * 3 + 2] = pBitmapT[(bitmapWidth - 1 - x) * 3 + 2];
					}
					memcpy(pBitmapT, pTempLineT, bitmapWidth * 3);
					memcpy(pBitmapB, pTempLineB, bitmapWidth * 3);
				}
				delete[] pTempLineT;
				delete[] pTempLineB;
			}
			else if (globalCameraNumber == 1 || globalCameraNumber == 6)	// mirror upside down
			{
				byte *pTempLineT = new byte[bitmapWidth * 3];
				byte *pTempLineB = new byte[bitmapWidth * 3];
				for (int y = 0; y < (bitmapHeight + 1) / 2; y++)
				{
					byte *pBitmapT = (byte *)bitmap->ScanLine[y];
					byte *pBitmapB = (byte *)bitmap->ScanLine[bitmapHeight - 1 - y];

					memcpy(pTempLineT, pBitmapB, bitmapWidth * 3);
					memcpy(pTempLineB, pBitmapT, bitmapWidth * 3);
					memcpy(pBitmapT, pTempLineT, bitmapWidth * 3);
					memcpy(pBitmapB, pTempLineB, bitmapWidth * 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;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::BreakButtonClick(TObject *Sender)
{
	BreakProcess = true;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FileListBoxChange(TObject *Sender)
{
	if (FileListBox->ItemIndex < 0 || FileListBox->ItemIndex >= FileListBox->Count) return;
	AnsiString selectedFileName = FileListBox->FileName;
	TFileContainer fileContainer;
	if (ExtractFileExt(selectedFileName).LowerCase() == ".fac")
	{
		ContentsListBox->Clear();
		if (fileContainer.Open(selectedFileName))
		{
			int fileCount = fileContainer.GetContainFileCount();
			for (int fileIndex = 0; fileIndex < fileCount; fileIndex++)
			{
				TFilePackHeader *filePackHeader = fileContainer.GetFilePackHeaderByIndex(fileIndex);
				ContentsListBox->AddItem(AnsiString(filePackHeader->FileName), NULL);
			}
		}
		SelectedFACFileName = selectedFileName;
	}
	else
	{
		ContentsListBox->Clear();
	}
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::ContentsListBoxClick(TObject *Sender)
{
/*
	if (fileContainer.Open(SelectedFACFileName))
	{
		ContentsListBox->Items-> ContentsListBox->ItemIndex
		int fileIndex =
		int fileCount = fileContainer.GetContainFileCount();
		for (int fileIndex = 0; fileIndex < fileCount; fileIndex++)
		{
			TFilePackHeader *filePackHeader = fileContainer.GetFilePackHeaderByIndex(fileIndex);
			ContentsListBox->AddItem(AnsiString(filePackHeader->FileName), NULL);
		}
	}
*/	
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::DataCompressSpeedButtonClick(TObject *Sender)
{
	ImagePanel->BringToFront();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::DataExtractSpeedButtonClick(TObject *Sender)
{
	ImagePanel->BringToFront();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::DataUpConversionSpeedButtonClick(TObject *Sender)
{
	DataConversionPanel->BringToFront();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::DataDownConversionSpeedButtonClick(TObject *Sender)
{
	DataConversionPanel->BringToFront();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ExtractData(AnsiString srcDir, bool bRemoveSrc, bool bExtractProductImage, bool bExtractDefectImage)
{
	SrcDirLabel->Caption = srcDir;
	if (BreakProcess) return;
	if (bExtractProductImage)
	{
		// extract product image
		ProductImageProgressCGauge->MaxValue = cProductImageCount;
		ProductImageProgressCGauge->Progress = 0;
		for (int imageIndex = 0; imageIndex < cProductImageCount; imageIndex++)
		{
			if (BreakProcess) break;
			AnsiString containerFileName = srcDir + "\\Image" + IntToStr(imageIndex + 1) + ".FAC";
			for (int globalCameraIndex = 0; globalCameraIndex < cTotalCameraCount; globalCameraIndex++)
			{
				AnsiString imageFileName = srcDir + "\\Image" + IntToStr(imageIndex + 1) + "_" + IntToStr(globalCameraIndex + 1) + ".bmp";
				AnsiString compressedBitmapName = "Image" + IntToStr(imageIndex + 1) + "_" + IntToStr(globalCameraIndex + 1) + ".fbm";
				Graphics::TBitmap *colorBitmap = new Graphics::TBitmap;
				if (ExtractImageFromContainer(colorBitmap, containerFileName, compressedBitmapName))
				{
					colorBitmap->SaveToFile(imageFileName);
				}
				delete colorBitmap;
			}

			AnsiString imageFileName = srcDir + "\\Image" + IntToStr(imageIndex + 1) + "_1_O.bmp";
			AnsiString compressedBitmapName = "Image" + IntToStr(imageIndex + 1) + "_1_O.fbm";
			Graphics::TBitmap *colorBitmap = new Graphics::TBitmap;
			if (ExtractImageFromContainer(colorBitmap, containerFileName, compressedBitmapName))
			{
				colorBitmap->SaveToFile(imageFileName);
			}
			delete colorBitmap;

			imageFileName = srcDir + "\\Image" + IntToStr(imageIndex + 1) + "_6_O.bmp";
			compressedBitmapName = "Image" + IntToStr(imageIndex + 1) + "_6_O.fbm";
			colorBitmap = new Graphics::TBitmap;
			if (ExtractImageFromContainer(colorBitmap, containerFileName, compressedBitmapName))
			{
				colorBitmap->SaveToFile(imageFileName);
			}
			delete colorBitmap;

			if (bRemoveSrc)
			{
				DeleteFile(containerFileName);
			}
			ProductImageProgressCGauge->Progress++;
			Application->ProcessMessages();
		}
	}

	if (bExtractDefectImage)
	{
		// extract defect image
		// get defect image count
		int defectContainerCount = 0;
		int totalDefectImageCount = 0;
		while (true)
		{
			AnsiString containerFileName = srcDir + "\\DefectImage" + IntToStr(defectContainerCount + 1) + ".FAC";
			if (!FileExists(containerFileName)) break;
			else
			{
				TFileContainer fileContainer;
				fileContainer.Open(containerFileName, false);
				totalDefectImageCount += fileContainer.GetContainFileCount();
				fileContainer.Close();
			}
			defectContainerCount++;
		}

		ProductImageProgressCGauge->MaxValue = totalDefectImageCount;
		ProductImageProgressCGauge->Progress = 0;

		for (int containerIndex = 0; containerIndex < defectContainerCount; containerIndex++)
		{
			if (BreakProcess) break;
			AnsiString containerFileName = srcDir + "\\DefectImage" + IntToStr(containerIndex + 1) + ".FAC";
			AnsiString defectContainerFileName = srcDir + "\\DefectData" + IntToStr(containerIndex + 1) + ".FAC";

			TFileContainer fileContainer;
			fileContainer.Open(containerFileName, false);
			int defectImageCount = fileContainer.GetContainFileCount();
			fileContainer.Close();

			TFileContainer defectDataContainer;
			defectDataContainer.Open(defectContainerFileName, true, DEFECT_DATA_CONTAINER_SIZE);
			for (int imageIndex = 0; imageIndex < defectImageCount; imageIndex++)
			{
				if (BreakProcess) break;
				AnsiString imageFileName = srcDir + "\\Image" + IntToStr(containerIndex * DEFECT_DATA_CONTAINER_SIZE + imageIndex + 1) + ".bmp";
				AnsiString compressedBitmapName = "Image" + IntToStr(containerIndex * DEFECT_DATA_CONTAINER_SIZE + imageIndex + 1) + ".fbm";
				Graphics::TBitmap *colorBitmap = new Graphics::TBitmap;
				if (ExtractImageFromContainer(colorBitmap, containerFileName, compressedBitmapName))
				{
					colorBitmap->SaveToFile(imageFileName);
				}
				delete colorBitmap;

				AnsiString dataName = "Data" + IntToStr(containerIndex * DEFECT_DATA_CONTAINER_SIZE + imageIndex + 1) + ".dat";

				if (defectDataContainer.FileContains(dataName))
				{
					TDefectFileData defectFileData;
					if (defectDataContainer.ExtractData(dataName, &defectFileData, sizeof(TDefectFileData)))
					{
						AnsiString saveDataFileName = srcDir + "\\Data" + IntToStr(containerIndex * DEFECT_DATA_CONTAINER_SIZE + imageIndex + 1) + ".dat";
						TFileStream *fileStream = new TFileStream(saveDataFileName, fmCreate);
						if (fileStream)
						{
							fileStream->Write(&defectFileData, sizeof(TDefectFileData));
							delete fileStream;
						}
					}
				}

				ProductImageProgressCGauge->Progress++;
				Application->ProcessMessages();
			}
			/*
			TIniFile *iniFile = new TIniFile(srcDir + "\\DBInfor.ini");
			if (iniFile)
			{
				iniFile->WriteInteger("Information", "Data Count", containerIndex * DEFECT_DATA_CONTAINER_SIZE + defectImageCount);
				delete iniFile;
			}
			*/
			defectDataContainer.Close();

			if (BreakProcess) break;
			if (bRemoveSrc)
			{
				DeleteFile(containerFileName);
				DeleteFile(defectContainerFileName);
			}
		}
	}
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ExtractDataRecursively(AnsiString srcDir, bool bRemoveSrc, bool bExtractProductImage, bool bExtractDefectImage)
{
	TSearchRec sr;
	int iAttributes = faDirectory;
	if (FindFirst(srcDir + "\\*.*", iAttributes, sr) == 0)
	{
		do
		{
			if (sr.Name == "." || sr.Name == "..") continue;
			if ((sr.Attr & faDirectory))
			{
				ExtractDataRecursively(srcDir + "\\" + sr.Name, bRemoveSrc, bExtractProductImage, bExtractDefectImage);
			}
		} while (FindNext(sr) == 0);
		FindClose(sr);
	}
	ExtractData(srcDir, bRemoveSrc, bExtractProductImage, bExtractDefectImage);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::CompressDataRecursively(AnsiString srcDir, bool bRemoveSrc, bool bExtractProductImage, bool bExtractDefectImage)
{
	TSearchRec sr;
	int iAttributes = faDirectory;
	if (FindFirst(srcDir + "\\*.*", iAttributes, sr) == 0)
	{
		do
		{
			if (sr.Name == "." || sr.Name == "..") continue;
			if ((sr.Attr & faDirectory))
			{
				CompressDataRecursively(srcDir + "\\" + sr.Name, bRemoveSrc, bExtractProductImage, bExtractDefectImage);
			}
		} while (FindNext(sr) == 0);
		FindClose(sr);
	}
	CompressData(srcDir, bRemoveSrc, bExtractProductImage, bExtractDefectImage);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::DataDownConversion(void)
{
	AnsiString targetDir = DirectoryEdit->Text;
	bool bRemoveSrc = RemoveSourceCheckBox->Checked;
	bool bExtractProductImage = ExtractProductImageCheckBox->Checked;
	bool bExtractDefectImage = ExtractDefectImageCheckBox->Checked;
	ExtractDataRecursively(targetDir, bRemoveSrc, bExtractProductImage, bExtractDefectImage);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::DataUpConversion(void)
{
	AnsiString targetDir = DirectoryEdit->Text;
	bool bRemoveSrc = RemoveSourceCheckBox->Checked;
	bool bExtractProductImage = ExtractProductImageCheckBox->Checked;
	bool bExtractDefectImage = ExtractDefectImageCheckBox->Checked;
	CompressDataRecursively(targetDir, bRemoveSrc, bExtractProductImage, bExtractDefectImage);
}
//---------------------------------------------------------------------------

