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

#include <vcl.h>
#pragma hdrstop

#include "OffSetImageExtract_Form.h"
#include "Environment.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "TntExtCtrls"
#pragma link "TntStdCtrls"
#pragma resource "*.dfm"
TOffSetImageExtractForm *OffSetImageExtractForm;



//---------------------------------------------------------------------------
__fastcall TOffSetImageExtractForm::TOffSetImageExtractForm(TComponent* Owner)
  : TTntForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TOffSetImageExtractForm::InitCaptureComponentOffSetImage()
{
   //**
   for(int globalCameraIndex = 0; globalCameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; globalCameraIndex++)
   {
      if(globalCameraIndex != 4 && globalCameraIndex != 12)
      {
        TTntImage *tempImage;
        tempImage = (TTntImage *) FindComponent("Image" + IntToStr(globalCameraIndex + 1));

        if(tempImage)
        {
          tempImage->Picture->Bitmap->Width = CAM_Width;
          tempImage->Picture->Bitmap->Height = CAM_Height;
          tempImage->Picture->Bitmap->PixelFormat = pf24bit;

          tempImage->Canvas->Brush->Color = clBlue;
          tempImage->Canvas->Brush->Style = bsSolid;
	        tempImage->Canvas->FillRect(Rect(0, 0, tempImage->Picture->Bitmap->Width, tempImage->Picture->Bitmap->Height));

          tempImage->Refresh();
        }

      }
   }

}
//---------------------------------------------------------------------------
void __fastcall TOffSetImageExtractForm::RefreshCameraInfoOffSetImage(int cameraIndex,int gainCount)
{
  //**
  // ShutterSpeedList
  // CameraGain
  // Writemask
  // DefaultROIInfo
  // SetCameraInformation
  // SetCameraGain

  int ShutterSpeed = 0;
  int Threshold = 0;
  int WriteMask = 0;
  int cameraGain = 1;

  //TTntEdit *shutterSpeedEdit = (TTntEdit *) FindComponent("ShutterSpeedEdit" + IntToStr(cameraIndex + 1));
  //TTntEdit *CameraGainEdit = (TTntEdit *) FindComponent("CameraGainEdit" + IntToStr(cameraIndex + 1));

  ShutterSpeed = 1;
 // if(CameraGainEdit)  cameraGain = StrToInt(CameraGainEdit->Text);
  cameraGain = gainCount;
  WriteMask |= CAMERA_WRITE_MASK_2D_SH;

  TROIInfo DefaultROIInfo, ApplyROIInfo;
  AnsiString filePath;
  filePath = ProgramPath.Env + "\\NFACameraInformation.ini";
  DefaultROIInfo = ReadCameraInformation(filePath, cameraIndex);
  memcpy(&ApplyROIInfo, &DefaultROIInfo, sizeof(TROIInfo));

  WriteMask |= CAMERA_WRITE_MASK_2D_ROI;

  //일반화질로 Set
  SetCameraInformation(ApplyROIInfo, ShutterSpeed, Threshold, 0, cameraIndex, WriteMask);

  // 이부분을 1~10까지 변경 (cameraGain)
  SetCameraGain(cameraIndex + 1, SYSTEM_DEFAULT_ANLOG_GAIN, cameraGain, 0);

}
//---------------------------------------------------------------------------

void __fastcall TOffSetImageExtractForm::FormCreate(TObject *Sender)
{

  for(int CameraIndex = 0; CameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; CameraIndex++)
  {
    ShutterSpeedList[CameraIndex] = 5;
  }
  
  //SubsamplingModeList
  if(ProductData.SubSamplingMode == 0)
  {
    CAM_Width = SYSTEM_CAMERA_WIDTH;
    CAM_Height = SYSTEM_CAMERA_HEIGHT;
    for(int i = 0; i < SYSTEM_TOTAL_CAMERA_COUNT; i++)
    {
      SubsamplingModeList[i] = RESOLUTION_NORMAL_QUALITY;
    }
  }
  else
  {
    CAM_Width = SYSTEM_CAMERA_HD_WIDTH;
    CAM_Height = SYSTEM_CAMERA_HD_HEIGHT;
    for(int i = 0; i < SYSTEM_TOTAL_CAMERA_COUNT ; i++)
    {
      SubsamplingModeList[i] = RESOLUTION_HIGH_QUALITY;
    }
  }

  InitCaptureComponentOffSetImage();

}
//---------------------------------------------------------------------------

void __fastcall TOffSetImageExtractForm::CloseButtonClick(TObject *Sender)
{
  this->Close();
}
//---------------------------------------------------------------------------
void __fastcall TOffSetImageExtractForm::OffSetImageTimerTimer(TObject *Sender)
{
  //Image->Picture->Bitmap->SaveToFile();
  bool TimerEnable = OffSetImageTimer->Enabled;
  OffSetImageTimer->Enabled = false;

  int x,y;
  int tempAddress;
  Byte *ptr;

  Graphics::TBitmap *img;
  img = new Graphics::TBitmap();

  AnsiString imageDir, fileName;
  unsigned int receivedData[2];
  bool bCaptureExist;
  unsigned int data[2];


  AnsiString RootPath;
  RootPath = ProgramPath.Env;

  for(int gainCount = 1; gainCount < 11; gainCount++)
  {
    imageDir = RootPath + "\\OFFSETIMAGE\\GAIN" + IntToStr(gainCount);
    if(!DirectoryExists(imageDir))
    {
      ForceDirectories(imageDir);
    }

    for(int CameraIndex = 0; CameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; CameraIndex++)
    {
      if(CameraIndex != (SD1_3D_FRONT_FACE_CAMERA_INDEX - 1)  && CameraIndex != (SD2_3D_FRONT_FACE_CAMERA_INDEX - 1))
      {
        memset(BinaryImage, 0, sizeof(BinaryImage));
        TTntImage *tempImage;
        tempImage = (TTntImage *) FindComponent("Image" + IntToStr(CameraIndex + 1));
        if(CameraMapInfo[CameraIndex].CameraInspectPosition < CAMERA_POSITION_DISCONNECT)
        {
          memset(CheckCaptureCount, 0, sizeof(CheckCaptureCount));
          for(int CameraCaptureCount = 1; CameraCaptureCount < 11; CameraCaptureCount++)
          {
            int spbIndex = CameraMapInfo[CameraIndex].SPBIndex;
            int camIndex = CameraMapInfo[CameraIndex].CamIndex;

            data[0] = camIndex;
            data[1] = CAM_Width * CAM_Height;

            TCaptureCommandParam captureCommandParam;
            captureCommandParam.CaptureMode = CAPTURE_MODE_CONTINUOUS;
            captureCommandParam.CameraMask = 0x01 << camIndex;
            captureCommandParam.FrameBufferCount = 3;

            // shutterspeedlist
            // offset 이미지는 gain에 대한 카메라 센서 노이즈를 제거하는 용도임
            // shutter speed가 큰 경우 필터노이즈 뿐만 아니라 외부빛밝기가 카메라 영상에 반영될것
            // 조명을 터뜨리진 않지만 shutter는 최소화 하는게 맞지 않는가

            //captureCommandParam.ShutterSpeed[camIndex] = ShutterSpeedList[CameraIndex];
            captureCommandParam.ShutterSpeed[camIndex] = 1;
            captureCommandParam.SubsamplingMode[camIndex] = SubsamplingModeList[CameraIndex];

            RefreshCameraInfoOffSetImage(CameraIndex,gainCount);

            if(Comm_Request(COMM_SPB + spbIndex, CMD_CAPTURE_START, &captureCommandParam, sizeof(TCaptureCommandParam)))
            {
            }

            Sleep(100);

            //exist
            if(Comm_Request(COMM_SPB + spbIndex, CMD_CAPTURE_EXIST, data, sizeof(unsigned int), receivedData, sizeof(unsigned int) * 2))
            {
              if(receivedData[0])
              {
                bCaptureExist = true;
              }
              else
              {
                bCaptureExist = false;
              }
            }

            //Upload
            if(bCaptureExist)
            {
              if (!Comm_Request(COMM_SPB + spbIndex, CMD_CAPTURE_UPLOAD, data, 2 * sizeof(unsigned int), CaptureData, CAM_Width * CAM_Height))
              {

              }

              CheckCaptureCount[CameraIndex]++;

              for(y = 0; y < SYSTEM_CAMERA_HEIGHT; y++)
              {
                ptr = (Byte*)tempImage->Picture->Bitmap->ScanLine[y];
                for(x = 0; x < SYSTEM_CAMERA_WIDTH; x++)
                {
                  tempAddress = SYSTEM_CAMERA_WIDTH * y + x;


                  /*
                  ptr[3 * x + 0] = CaptureData[tempAddress];
                  ptr[3 * x + 1] = CaptureData[tempAddress];
                  ptr[3 * x + 2] = CaptureData[tempAddress];

                  // captureData는 1채널 이미지(Bayerimage)일텐데 3채널 버퍼에 wirte하는 의미가 있는건가?

                  // char 자료형의 범위는 255. 최대 10장의 이미지를 누적 sum하게 되면 overflow 발생할텐데
                  // 특히 gain이 클수록
                  BinaryImage[tempAddress * 3 + 0] += ptr[3 * x + 0];
                  BinaryImage[tempAddress * 3 + 1] += ptr[3 * x + 1];
                  BinaryImage[tempAddress * 3 + 2] += ptr[3 * x + 2];
                  */

                  BinaryImage[tempAddress] += CaptureData[tempAddress];

                }
              }

            }
          } // 10번 Capture 완료

          // 왜 나누기 10? 캡쳐 후 업로드한 이미지의 개수가 10장이라는 보장은 누가해주지? bCaptureExist가 false라면?

          for(y = 0; y < SYSTEM_CAMERA_HEIGHT; y++)
          {
            for(x = 0; x < SYSTEM_CAMERA_WIDTH; x++)
            {
              tempAddress = SYSTEM_CAMERA_WIDTH * y + x;

              /*
              BinaryImage[tempAddress * 3 + 0] /= 10;
              BinaryImage[tempAddress * 3 + 1] /= 10;
              BinaryImage[tempAddress * 3 + 2] /= 10;
              */

              BinaryImage[tempAddress] /= CheckCaptureCount[CameraIndex];

            }
          }


          for(y = 0; y < SYSTEM_CAMERA_HEIGHT; y++)
          {
            //ptr = (Byte *)img->ScanLine[y];
            ptr = (Byte*)tempImage->Picture->Bitmap->ScanLine[y];
            for(x = 0; x < SYSTEM_CAMERA_WIDTH; x++)
            {
              tempAddress = SYSTEM_CAMERA_WIDTH * y + x;

              ptr[3 * x + 0] = BinaryImage[tempAddress];
              ptr[3 * x + 1] = BinaryImage[tempAddress];
              ptr[3 * x + 2] = BinaryImage[tempAddress];
            }
          }

          tempImage->Refresh();

          fileName = imageDir + "\\Camera" + IntToStr(CameraIndex + 1) + "_OffSet.bmp";
          tempImage->Picture->Bitmap->SaveToFile(fileName);
        } // DISCONECT 처리 아닌경우만 실행
      }
    }

    if(gainCount == 10)
    {
      TimerEnable = false;
      StartButton->Enabled = true;
      ShowMessage("완료");
    }
  }


  OffSetImageTimer->Enabled = TimerEnable;
}
//---------------------------------------------------------------------------

void __fastcall TOffSetImageExtractForm::StartButtonClick(TObject *Sender)
{
  InitCaptureComponentOffSetImage();
  OffSetImageTimer->Enabled = true;
  StartButton->Enabled = false;
}
//---------------------------------------------------------------------------



void __fastcall TOffSetImageExtractForm::stopClick(TObject *Sender)
{
  TestTimer->Enabled = false;
}
//---------------------------------------------------------------------------

void __fastcall TOffSetImageExtractForm::TestTimerTimer(TObject *Sender)
{
  bool TimerEnable = TestTimer->Enabled;
  TestTimer->Enabled = false;

  int x,y;
  int tempAddress;
  Byte *ptr;

  Graphics::TBitmap *img;
  img = new Graphics::TBitmap();

  AnsiString imageDir, fileName;
  unsigned int receivedData[2];
  bool bCaptureExist;
  unsigned int data[2];

  AnsiString RootPath;
  RootPath = ProgramPath.Env;

 //InitCaptureComponentOffSetImage();

    for(int CameraIndex = 0; CameraIndex < SYSTEM_TOTAL_CAMERA_COUNT; CameraIndex++)
    {
      memset(BinaryImage, 0, sizeof(BinaryImage));
      TTntImage *tempImage;
      tempImage = (TTntImage *) FindComponent("Image" + IntToStr(CameraIndex + 1));
      if(CameraMapInfo[CameraIndex].CameraInspectPosition < CAMERA_POSITION_DISCONNECT)
      {

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

          data[0] = camIndex;
          data[1] = CAM_Width * CAM_Height;

          TCaptureCommandParam captureCommandParam;
          captureCommandParam.CaptureMode = CAPTURE_MODE_CONTINUOUS;
          captureCommandParam.CameraMask = 0x01 << camIndex;
          captureCommandParam.FrameBufferCount = 3;
          captureCommandParam.ShutterSpeed[camIndex] = ShutterSpeedList[CameraIndex];
          captureCommandParam.SubsamplingMode[camIndex] = SubsamplingModeList[CameraIndex];

          RefreshCameraInfoOffSetImage(CameraIndex,1);

          if(Comm_Request(COMM_SPB + spbIndex, CMD_CAPTURE_START, &captureCommandParam, sizeof(TCaptureCommandParam)))
          {

          }

          Sleep(100);
          //exist
          if(Comm_Request(COMM_SPB + spbIndex, CMD_CAPTURE_EXIST, data, sizeof(unsigned int), receivedData, sizeof(unsigned int) * 2))
          {
            if(receivedData[0])
            {
              bCaptureExist = true;
            }
            else
            {
              bCaptureExist = false;
            }
          }

          //Upload
          if(bCaptureExist)
          {
            if (!Comm_Request(COMM_SPB + spbIndex, CMD_CAPTURE_UPLOAD, data, 2 * sizeof(unsigned int), CaptureData, CAM_Width * CAM_Height))
            {

            }


           /*
            GetNFACamera2DColorImage(tempImage->Picture->Bitmap, CaptureData, MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT, CameraIndex);


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

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

                memcpy(pTempLineT, pBitmapB, tempImage->Picture->Bitmap->Width * 3);
                memcpy(pTempLineB, pBitmapT, tempImage->Picture->Bitmap->Width * 3);
                memcpy(pBitmapT, pTempLineT, tempImage->Picture->Bitmap->Width * 3);
                memcpy(pBitmapB, pTempLineB, tempImage->Picture->Bitmap->Width * 3);
              }
              delete[] pTempLineT;
              delete[] pTempLineB;
            }
            tempImage->Repaint();
            */

            for(y = 0; y < SYSTEM_CAMERA_HEIGHT; y++)
            {
              ptr = (Byte*)tempImage->Picture->Bitmap->ScanLine[y];
              //ptr = (Byte *)img->ScanLine[y];
              for(x = 0; x < SYSTEM_CAMERA_WIDTH; x++)
              {
                tempAddress = SYSTEM_CAMERA_WIDTH * y + x;
                ptr[3 * x + 0] = CaptureData[tempAddress];
                ptr[3 * x + 1] = CaptureData[tempAddress];
                ptr[3 * x + 2] = CaptureData[tempAddress];

              }
            }


            tempImage->Refresh();
          }

      } // DISCONECT 처리 아닌경우만 실행
    }


  TestTimer->Enabled = TimerEnable;
}
//---------------------------------------------------------------------------


void __fastcall TOffSetImageExtractForm::timer5startClick(TObject *Sender)
{
  InitCaptureComponentOffSetImage();
  TestTimer->Enabled = true;
}
//---------------------------------------------------------------------------

void __fastcall TOffSetImageExtractForm::Image5Click(TObject *Sender)
{
  if(TestBox->Visible == false)
  {
    TestBox->Visible = true;
  }
  else
  {
    TestBox->Visible = false;
  }
}
//---------------------------------------------------------------------------

void __fastcall TOffSetImageExtractForm::FormActivate(TObject *Sender)
{
  SetScreenPosition(this);  
}
//---------------------------------------------------------------------------

