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

#include <vcl.h>
#pragma hdrstop

#include "HCBMonitoring_Form.h"
#include "Keyboard_Form.h"
#include "math.h"
#include <FileCtrl.hpp>
#include <inifiles.hpp>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "TntGrids"
#pragma link "TntExtCtrls"
#pragma link "TntStdCtrls"
#pragma resource "*.dfm"
THCBMonitoringForm *HCBMonitoringForm;
//---------------------------------------------------------------------------
__fastcall THCBMonitoringForm::THCBMonitoringForm(TComponent* Owner)
  : TForm(Owner)
{
  bRecentFileLoad = false;
  RecentFilePath = "";
}
//---------------------------------------------------------------------------
void __fastcall THCBMonitoringForm::DataLoadButtonClick(TObject *Sender)
{
  AnsiString Dir = ProgramPath.Root + "\\HCB Monitoring";

  if (!DirectoryExists(Dir))
  {
    Dir = ProgramPath.Root;
  }

  if (SelectDirectory(Dir, TSelectDirOpts(), 0 ))
  {
    LoadData(Dir);
  }
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::CloseButtonClick(TObject *Sender)
{
  this->Close();  
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::RefreshDataChart(bool initial)
{  
  if(initial)
  {
    CurrentDataPage = 1;

    PageControl->Max = dataFileCount;
    PageControl->Position = CurrentDataPage;
  }

  PagePanel->Caption = IntToStr(PageControl->Position) + " / " + IntToStr(PageControl->Max);

  HCBTabletUnitList.clear();
  for(int i = MonitoringStringGrid->FixedRows; i < MonitoringStringGrid->RowCount; ++i)
  {
    MonitoringStringGrid->Rows[i]->Clear();
  }
  MonitoringStringGrid->RowCount = 2;

  AnsiString Filename = DataPath + "\\Result" + IntToStr(CurrentDataPage) + ".hmf";

  TFileStream *pFileStream = NULL;
  if(FileExists(Filename))
  {
    pFileStream = new TFileStream(Filename, fmOpenRead);

    THCBDisk2TabletUnit tempData;

    int SpeedPercentage = HCBSetupData.BaseSpeed * 100 / HCBSetupData.DiskSpeed;

    while(1)
    {
      pFileStream->Read(&tempData, sizeof(THCBDisk2TabletUnit));
      HCBTabletUnitList.push_back(tempData);

      if(pFileStream->Position >= pFileStream->Size)
      {
        break;
      }
    }

    delete pFileStream;

    DataFileNamePanel->Caption = Filename;

    AnsiString tempLabel;
    vector<THCBDisk2TabletUnit>::iterator it;
    for (it = HCBTabletUnitList.begin(); it < HCBTabletUnitList.end(); it++)
    {
      memcpy(&tempData, it, sizeof(THCBDisk2TabletUnit));
      MonitoringStringGrid->Cells[0][MonitoringStringGrid->RowCount - 1] = IntToStr(tempData.TabletNumber);

      if (tempData.InspectionResult & TABLET_RESULT_SPB_MASK)
      {
        int spbUnInsResult = (tempData.InspectionResult & ~TABLET_RESULT_SPB_MASK);
        switch (spbUnInsResult)
        {
          case SPB_TABLET_RESULT_NONE:
            tempLabel = "U (SPB None)";
            break;
          case SPB_TABLET_RESULT_GOOD:
            tempLabel = "GOOD";
            break;
          case SPB_TABLET_RESULT_PROCESSING:
            tempLabel = "U (SPB PROCESSING)";
            break;
          case SPB_TABLET_RESULT_DEFECT:
            tempLabel = "D (CPB)";
            break;
          case SPB_TABLET_RESULT_UNINS_IMAGE_BUFFER_FULL:
            tempLabel = "U (SPB BUFFER FULL)";
            break;
          case SPB_TABLET_RESULT_UNINS_TABLET_NUMBER_UNDEFINED:
            tempLabel = "U (SPB UNDEF Number)";
            break;
          case SPB_TABLET_RESULT_UNINS_WRONG_TABLET_NUMBER:
            tempLabel = "U (SPB Wrong Number)";
            break;
          case SPB_TABLET_RESULT_UNINS_CAPTURE_TIMEOUT:
            tempLabel = "U (SPB Capture TO)";
            break;
          case SPB_TABLET_RESULT_UNINS_CAPTURE_NOT_READY:
            tempLabel = "U (SPB Capture NR)";
            break;
          case SPB_TABLET_RESULT_UNINS_PROCESSING_TIMEOUT:
            tempLabel = "U (CPB Processing TO)";
            break;
          case SPB_TABLET_RESULT_UNINS_PROCESSING_ERROR:
            tempLabel = "U (CPB Processing Error)";
            break;
          case SPB_TABLET_RESULT_UNINS_CPB_FULL:
            tempLabel = "U (CPB FULL)";
            break;
          case SPB_TABLET_RESULT_UNINS_CLOSED_TABLET:
            tempLabel = "U (CPB Closed)";
            break;
          case SPB_TABLET_RESULT_UNINS_TABLET_POSITION:
            tempLabel = "U (CPB Position)";
            break;
          case SPB_TABLET_RESULT_UNINS_BRIGHTNESS_DROPPED:
            tempLabel = "U (CPB B Drop)";
            break;
          case SPB_TABLET_RESULT_UNINS_BRIGHTNESS_CHASE:
            tempLabel = "U (CPB B Chase)";
            break;
          default:
            tempLabel = "U (CPB ETC)";
            break;
        }
      }
      else
      {
        switch(tempData.InspectionResult)
        {
          case TABLET_RESULT_NONE:
            tempLabel = "NONE";
            break;
          case TABLET_RESULT_GOOD:
            tempLabel = "GOOD";
            break;
          case TABLET_RESULT_DEFECT:
            tempLabel = "D (CPB)";
            break;
          case TABLET_RESULT_DEFECT_UNPRINT:
            tempLabel = "D (UNPRINT)";
            break;
          case TABLET_RESULT_DEFECT_SPB_PROCESSING_NOT_COMPLETE:
            tempLabel = "D (NC)";
            break;
          case TABLET_RESULT_UNINS_SPB_TIMEOUT:
            tempLabel = "U (TO)";
            break;
          case TABLET_RESULT_UNINS_SPB_PROCESSING_NOT_COMPLETE:
            tempLabel = "U (NC)";
            break;
          case TABLET_RESULT_INSERTED:
            tempLabel = "U (S:INSERT)";
            break;
          case TABLET_RESULT_DISAPPEARED:
            tempLabel = "U (S:DISAPPEAR)";
            break;
          case TABLET_RESULT_CLOSED_UNINS:
            tempLabel = "U (S:CLOSED_I)";
            break;
          case TABLET_RESULT_CLOSED_DEFECT:
            tempLabel = "D (S:CLOSED_D)";
            break;
          case TABLET_RESULT_SENSOR_1_MISFEEDING:
            tempLabel = "U (S:S1 MF)";
            break;
          case TABLET_RESULT_SENSOR_2_MISFEEDING:
            tempLabel = "U (S:S2 MF)";
            break;
          case TABLET_RESULT_MULTI_TABLET_SENSOR_1:
            tempLabel = "U (S:S1 CLOSED)";
            break;
          case TABLET_RESULT_MULTI_TABLET_SENSOR_2:
            tempLabel = "U (S:S2 CLOSED)";
            break;
          case TABLET_RESULT_UNINTENDED_UNINSPECT:
            tempLabel = "U (S:UNINTENDED)";
            break;
          case TABLET_RESULT_DEFECT_FR_MISMATCH:
            tempLabel = "D (FRMS)";
            break;
          default:
            tempLabel = "NONE";
            break;
        }
      }
      
      MonitoringStringGrid->Cells[1][MonitoringStringGrid->RowCount - 1] = tempLabel;

      if(tempData.Ejection == TABLET_EJECTION_NONE)
      {
        tempLabel = "NONE";
      }
      else if(tempData.Ejection == TABLET_EJECTION_UNINSPECT)
      {
        tempLabel = "UNINSPECT";
      }
      else if(tempData.Ejection == TABLET_EJECTION_DEFECT)
      {
        tempLabel = "DEFECT";
      }
      
      MonitoringStringGrid->Cells[2][MonitoringStringGrid->RowCount - 1] = tempLabel;
      MonitoringStringGrid->Cells[3][MonitoringStringGrid->RowCount - 1] = IntToStr(tempData.Sensor1Length);
      MonitoringStringGrid->Cells[4][MonitoringStringGrid->RowCount - 1] = IntToStr(tempData.Sensor2Length);
      MonitoringStringGrid->Cells[5][MonitoringStringGrid->RowCount - 1] = IntToStr(tempData.Sensor3Length);
      MonitoringStringGrid->Cells[6][MonitoringStringGrid->RowCount - 1] = IntToStr((tempData.Sensor2Time - tempData.Sensor1Time) * SpeedPercentage / 100);

      if(tempData.Sensor3Length)
      {
        MonitoringStringGrid->Cells[7][MonitoringStringGrid->RowCount - 1] = IntToStr((tempData.Sensor3Time - tempData.Sensor2Time) * SpeedPercentage / 100);
      }
      else
      {
        MonitoringStringGrid->Cells[7][MonitoringStringGrid->RowCount - 1] = "EJECTED";
      }

      MonitoringStringGrid->RowCount++;
    }
  }
  else
  {
    DataFileNamePanel->Caption = "Data does not exist.";
  }
}
//---------------------------------------------------------------------------
void __fastcall THCBMonitoringForm::PageControlClick(TObject *Sender,
      TUDBtnType Button)
{
  bExecutedFindEvent = false;
  
  CurrentDataPage = PageControl->Position;

  RefreshDataChart(false);

  int currentRow = MonitoringStringGrid->Row;
  MonitoringStringGrid->Row = MonitoringStringGrid->RowCount - 1;
  MonitoringStringGrid->Row = currentRow;
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::FormCreate(TObject *Sender)
{
  IsScrollImageMouseDown = false;
  bExecutedFindEvent = false;
  
  Panel1->DoubleBuffered = true;
  ScrollGroupBox->DoubleBuffered = true;
  
  PageControl->Enabled = false;
  DataFileNamePanel->Caption = "N/A";

  MonitoringStringGrid->Cells[0][0] = "Number";
  MonitoringStringGrid->Cells[1][0] = "Result";
  MonitoringStringGrid->Cells[2][0] = "Ejector State";
  MonitoringStringGrid->Cells[3][0] = "S1 Length";
  MonitoringStringGrid->Cells[4][0] = "S2 Length";
  MonitoringStringGrid->Cells[5][0] = "S3 Length";
  MonitoringStringGrid->Cells[6][0] = "Real Interval A";
  MonitoringStringGrid->Cells[7][0] = "Real Interval B";

  int CellWidth = (MonitoringStringGrid->Width / MonitoringStringGrid->ColCount) - 2;
  for(int m = 0; m < MonitoringStringGrid->ColCount; m++)
  {
    MonitoringStringGrid->ColWidths[m] = CellWidth;
  }

  Sensor1Image->Canvas->Font->Color = clWhite;
  Sensor1Image->Canvas->Font->Size = 10;
  Sensor1Image->Canvas->Pen->Width = 1;
  Sensor1Image->Canvas->Pen->Style = psSolid;
  Sensor1Image->Canvas->Pen->Color = clRed;
  Sensor1Image->Canvas->Brush->Style = bsClear;
  Sensor1Image->Picture->Bitmap->Width = Sensor1Image->Width;
  Sensor1Image->Picture->Bitmap->Height = Sensor1Image->Height;
  Sensor1Image->Canvas->Brush->Color = clBlack;
  Sensor1Image->Canvas->Brush->Style = bsSolid;

  Sensor2Image->Canvas->Font->Color = clWhite;
  Sensor2Image->Canvas->Font->Size = 10;
  Sensor2Image->Canvas->Pen->Width = 1;
  Sensor2Image->Canvas->Pen->Style = psSolid;
  Sensor2Image->Canvas->Pen->Color = clLime;
  Sensor2Image->Canvas->Brush->Style = bsClear;
  Sensor2Image->Picture->Bitmap->Width = Sensor2Image->Width;
  Sensor2Image->Picture->Bitmap->Height = Sensor2Image->Height;
  Sensor2Image->Canvas->Brush->Color = clBlack;
  Sensor2Image->Canvas->Brush->Style = bsSolid;

  Sensor3Image->Canvas->Font->Color = clWhite;
  Sensor3Image->Canvas->Font->Size = 10;
  Sensor3Image->Canvas->Pen->Width = 1;
  Sensor3Image->Canvas->Pen->Style = psSolid;
  Sensor3Image->Canvas->Pen->Color = clYellow;
  Sensor3Image->Canvas->Brush->Style = bsClear;
  Sensor3Image->Picture->Bitmap->Width = Sensor3Image->Width;
  Sensor3Image->Picture->Bitmap->Height = Sensor3Image->Height;
  Sensor3Image->Canvas->Brush->Color = clBlack;
  Sensor3Image->Canvas->Brush->Style = bsSolid;

  TotalSensorImage->Canvas->Font->Color = clWhite;
  TotalSensorImage->Canvas->Font->Size = 10;
  TotalSensorImage->Canvas->Pen->Width = 1;
  TotalSensorImage->Canvas->Pen->Style = psSolid;
  TotalSensorImage->Canvas->Pen->Color = clBlue;
  TotalSensorImage->Canvas->Brush->Style = bsClear;
  TotalSensorImage->Picture->Bitmap->Width = TotalSensorImage->Width;
  TotalSensorImage->Picture->Bitmap->Height = TotalSensorImage->Height;
  TotalSensorImage->Canvas->Brush->Color = clBlack;
  TotalSensorImage->Canvas->Brush->Style = bsSolid;

  EjectImage->Canvas->Font->Color = clWhite;
  EjectImage->Canvas->Font->Size = 10;
  EjectImage->Canvas->Pen->Width = 1;
  EjectImage->Canvas->Pen->Style = psSolid;
  EjectImage->Canvas->Pen->Color = clRed;
  EjectImage->Canvas->Brush->Style = bsClear;
  EjectImage->Picture->Bitmap->Width = EjectImage->Width;
  EjectImage->Picture->Bitmap->Height = EjectImage->Height;
  EjectImage->Canvas->Brush->Color = clBlack;
  EjectImage->Canvas->Brush->Style = bsSolid;

  Sensor1Image->Canvas->FillRect(Rect(0, 0, Sensor1Image->Picture->Bitmap->Width, Sensor1Image->Picture->Bitmap->Height));
  Sensor2Image->Canvas->FillRect(Rect(0, 0, Sensor2Image->Picture->Bitmap->Width, Sensor2Image->Picture->Bitmap->Height));
  Sensor3Image->Canvas->FillRect(Rect(0, 0, Sensor3Image->Picture->Bitmap->Width, Sensor3Image->Picture->Bitmap->Height));
  TotalSensorImage->Canvas->FillRect(Rect(0, 0, TotalSensorImage->Picture->Bitmap->Width, TotalSensorImage->Picture->Bitmap->Height));
  EjectImage->Canvas->FillRect(Rect(0, 0, EjectImage->Picture->Bitmap->Width, EjectImage->Picture->Bitmap->Height));

  ScrollImage->Picture->Bitmap->Width = ScrollImage->Width;
	ScrollImage->Picture->Bitmap->Height = ScrollImage->Height;
	ScrollImage->Picture->Bitmap->PixelFormat = pf24bit;
	for (int y = 0; y < ScrollImage->Height; y++)
	{
		byte *pBitmap = (byte *)ScrollImage->Picture->Bitmap->ScanLine[y];
		byte colorB = 0xFF - abs(y - ScrollImage->Height / 2) * 0x4F / (ScrollImage->Height / 2);
		byte colorG = 0x7F - abs(y - ScrollImage->Height / 2) * 0x1F / (ScrollImage->Height / 2);
		byte colorR = 0x7F - abs(y - ScrollImage->Height / 2) * 0x1F / (ScrollImage->Height / 2);
		if (y % 10 == 0)
		{
			colorB = colorG = colorR = 0;
		}

		for (int x = 0; x < ScrollImage->Width; x++)
		{
			pBitmap[x * 3] = colorB;
			pBitmap[x * 3 + 1] = colorG;
			pBitmap[x * 3 + 2] = colorR;
		}
	}

  ChartScale = 4;

  CurrentIntervalALabel->Visible = false;
  CurrentIntervalBLabel->Visible = false;
  CurrentDefectDelayLabel->Visible = false;
  CurrentUninsDelayLabel->Visible = false;
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::MonitoringStringGridClick(
      TObject *Sender)
{   
  if(bExecutedFindEvent)
  {
    ErrorReasonLabel->Visible = true;
  }
  else
  {
    ErrorReasonLabel->Visible = false;
  }
  
  int SelectedTabletNumber;
  int SelectRow = MonitoringStringGrid->Row;

  if(SelectRow > 0 && !MonitoringStringGrid->Cells[0][SelectRow].IsEmpty())
  {
    if(bExecutedFindEvent)
    {
      if(SelectRow != ShiftRowIndex)
      {
        bExecutedFindEvent = false;
        ErrorReasonLabel->Visible = false;
      }
    }
    
	  Sensor1Image->Canvas->FillRect(Rect(0, 0, Sensor1Image->Picture->Bitmap->Width, Sensor1Image->Picture->Bitmap->Height));
    Sensor2Image->Canvas->FillRect(Rect(0, 0, Sensor2Image->Picture->Bitmap->Width, Sensor2Image->Picture->Bitmap->Height));
    Sensor3Image->Canvas->FillRect(Rect(0, 0, Sensor3Image->Picture->Bitmap->Width, Sensor3Image->Picture->Bitmap->Height));
    TotalSensorImage->Canvas->FillRect(Rect(0, 0, TotalSensorImage->Picture->Bitmap->Width, TotalSensorImage->Picture->Bitmap->Height));
    EjectImage->Canvas->FillRect(Rect(0, 0, EjectImage->Picture->Bitmap->Width, EjectImage->Picture->Bitmap->Height));

    SelectedTabletNumber = StrToInt(MonitoringStringGrid->Cells[0][SelectRow]);

    vector<THCBDisk2TabletUnit>::iterator it;

    bool searchingSW = false;
    int nextTabletNumber;
    unsigned int offset;

    THCBDisk2TabletUnit tempData;

    memset(S1WriteMask, 0, SENSOR_CHART_WIDTH);
    memset(S2WriteMask, 0, SENSOR_CHART_WIDTH);
    memset(S3WriteMask, 0, SENSOR_CHART_WIDTH);
  
    for (it = HCBTabletUnitList.begin(); it < HCBTabletUnitList.end(); it++)
    {
      memcpy(&tempData, it, sizeof(THCBDisk2TabletUnit));
      if(tempData.TabletNumber == SelectedTabletNumber)
      {
        int Sensor1StartTime = tempData.Sensor1Time / ChartScale;
        int Sensor2StartTime = tempData.Sensor2Time / ChartScale;
        int Sensor3StartTime = tempData.Sensor3Time / ChartScale;

        int Sensor1Length = tempData.Sensor1Length / ChartScale;
        int Sensor2Length = tempData.Sensor2Length / ChartScale;
        int Sensor3Length = tempData.Sensor3Length / ChartScale;

        int start, end;

        offset = Sensor1StartTime - 30;

        // sensor1
        start = Sensor1StartTime - offset;
        end = start + Sensor1Length;

        if(start >= 0 && start < SENSOR_CHART_WIDTH)
        {
          S1WriteMask[start] = 1;
        }

        Sensor1Image->Canvas->TextOutW(start + 5, Sensor1Image->Picture->Bitmap->Height - 20, IntToStr(tempData.TabletNumber)); 
        Sensor1Image->Canvas->Pen->Style = psSolid;
        Sensor1Image->Canvas->MoveTo(start, Sensor1Image->Picture->Bitmap->Height);
        Sensor1Image->Canvas->LineTo(start, 10);

        Sensor1Image->Canvas->MoveTo(start, 10);
        Sensor1Image->Canvas->LineTo(end, 10);

        Sensor1Image->Canvas->MoveTo(end, 10);
        Sensor1Image->Canvas->LineTo(end, Sensor1Image->Picture->Bitmap->Height);

        TotalSensorImage->Canvas->Pen->Color = clRed;

        TotalSensorImage->Canvas->MoveTo(start, TotalSensorImage->Picture->Bitmap->Height);
        TotalSensorImage->Canvas->LineTo(start, 10);

        TotalSensorImage->Canvas->MoveTo(start, 10);
        TotalSensorImage->Canvas->LineTo(end, 10);

        TotalSensorImage->Canvas->MoveTo(end, 10);
        TotalSensorImage->Canvas->LineTo(end, TotalSensorImage->Picture->Bitmap->Height);

        // sensor2
        start = Sensor2StartTime - offset - ConvHCBSetupData.IntervalA / ChartScale;
        end = start + Sensor2Length;

        if(start >= 0 && start < SENSOR_CHART_WIDTH)
        {
          S2WriteMask[start] = 1;
        }

        Sensor2Image->Canvas->TextOutW(start + 5, Sensor2Image->Picture->Bitmap->Height - 20, IntToStr(tempData.TabletNumber));
        Sensor2Image->Canvas->Pen->Style = psSolid;
        Sensor2Image->Canvas->MoveTo(start, Sensor2Image->Picture->Bitmap->Height);
        Sensor2Image->Canvas->LineTo(start, 10);

        Sensor2Image->Canvas->MoveTo(start, 10);
        Sensor2Image->Canvas->LineTo(end, 10);

        Sensor2Image->Canvas->MoveTo(end, 10);
        Sensor2Image->Canvas->LineTo(end, Sensor2Image->Picture->Bitmap->Height);

        // sensor2 - modified
        if(ConvHCBSetupData.IntervalA != ConvNewHCBSetupData.IntervalA)
        {
          start = Sensor2StartTime - offset - ConvNewHCBSetupData.IntervalA / ChartScale;
          end = start + Sensor2Length;

          Sensor2Image->Canvas->Pen->Style = psDot;
          Sensor2Image->Canvas->MoveTo(start, Sensor2Image->Picture->Bitmap->Height);
          Sensor2Image->Canvas->LineTo(start, 15);

          Sensor2Image->Canvas->MoveTo(start, 15);
          Sensor2Image->Canvas->LineTo(end, 15);

          Sensor2Image->Canvas->MoveTo(end, 15);
          Sensor2Image->Canvas->LineTo(end, Sensor2Image->Picture->Bitmap->Height);
        }

        TotalSensorImage->Canvas->Pen->Color = clLime;

        TotalSensorImage->Canvas->MoveTo(start, TotalSensorImage->Picture->Bitmap->Height);
        TotalSensorImage->Canvas->LineTo(start, 10);

        TotalSensorImage->Canvas->MoveTo(start, 10);
        TotalSensorImage->Canvas->LineTo(end, 10);

        TotalSensorImage->Canvas->MoveTo(end, 10);
        TotalSensorImage->Canvas->LineTo(end, TotalSensorImage->Picture->Bitmap->Height);

        // sensor3
        start = Sensor3StartTime - offset - (ConvHCBSetupData.IntervalB / ChartScale + ConvHCBSetupData.IntervalA / ChartScale);
        end = start + Sensor3Length;

        if(start >= 0 && start < SENSOR_CHART_WIDTH)
        {
          S3WriteMask[start] = 1;
        }

        Sensor3Image->Canvas->TextOutW(start + 5, Sensor3Image->Picture->Bitmap->Height - 20, IntToStr(tempData.TabletNumber));
        Sensor3Image->Canvas->Pen->Style = psSolid;
        Sensor3Image->Canvas->MoveTo(start, Sensor3Image->Picture->Bitmap->Height);
        Sensor3Image->Canvas->LineTo(start, 10);

        Sensor3Image->Canvas->MoveTo(start, 10);
        Sensor3Image->Canvas->LineTo(end, 10);

        Sensor3Image->Canvas->MoveTo(end, 10);
        Sensor3Image->Canvas->LineTo(end, Sensor3Image->Picture->Bitmap->Height);

        // sensor3 - modified
        if(ConvHCBSetupData.IntervalA != ConvNewHCBSetupData.IntervalA || ConvHCBSetupData.IntervalB != ConvNewHCBSetupData.IntervalB)
        {
          start = Sensor3StartTime - offset - (ConvNewHCBSetupData.IntervalB / ChartScale + ConvNewHCBSetupData.IntervalA / ChartScale);
          end = start + Sensor3Length;

          Sensor3Image->Canvas->Pen->Style = psDot;
          Sensor3Image->Canvas->MoveTo(start, Sensor3Image->Picture->Bitmap->Height);
          Sensor3Image->Canvas->LineTo(start, 15);

          Sensor3Image->Canvas->MoveTo(start, 15);
          Sensor3Image->Canvas->LineTo(end, 15);

          Sensor3Image->Canvas->MoveTo(end, 15);
          Sensor3Image->Canvas->LineTo(end, Sensor3Image->Picture->Bitmap->Height);
        }

        TotalSensorImage->Canvas->Pen->Color = clYellow;

        TotalSensorImage->Canvas->MoveTo(start, TotalSensorImage->Picture->Bitmap->Height);
        TotalSensorImage->Canvas->LineTo(start, 10);

        TotalSensorImage->Canvas->MoveTo(start, 10);
        TotalSensorImage->Canvas->LineTo(end, 10);

        TotalSensorImage->Canvas->MoveTo(end, 10);
        TotalSensorImage->Canvas->LineTo(end, TotalSensorImage->Picture->Bitmap->Height);

        if(tempData.Ejection == TABLET_EJECTION_UNINSPECT || tempData.Ejection == TABLET_EJECTION_DEFECT)
        {
          int EjectTime;
          if(tempData.Ejection == TABLET_EJECTION_UNINSPECT)
          {
            EjectTime = tempData.UnInsEjectorTime / ChartScale;
            start = EjectTime - ConvHCBSetupData.EjectorInfo.UnInsEjectorDelay / ChartScale - offset - ConvHCBSetupData.IntervalA / ChartScale;
            end = start + tempData.UnInsEjectorLength / ChartScale;

            EjectImage->Canvas->Pen->Style = psSolid;
            EjectImage->Canvas->Pen->Color = clYellow;
            EjectImage->Canvas->TextOutW(start + 5, EjectImage->Picture->Bitmap->Height - 20, "U");

            EjectImage->Canvas->MoveTo(start, EjectImage->Picture->Bitmap->Height);
            EjectImage->Canvas->LineTo(start, 10);

            EjectImage->Canvas->MoveTo(start, 10);
            EjectImage->Canvas->LineTo(end, 10);

            EjectImage->Canvas->MoveTo(end, 10);
            EjectImage->Canvas->LineTo(end, EjectImage->Picture->Bitmap->Height);

            if(ConvHCBSetupData.IntervalA != ConvNewHCBSetupData.IntervalA)
            {
              EjectTime = tempData.UnInsEjectorTime / ChartScale;
              start = EjectTime - ConvHCBSetupData.EjectorInfo.UnInsEjectorDelay / ChartScale - offset - ConvNewHCBSetupData.IntervalA / ChartScale;
              end = start + tempData.UnInsEjectorLength / ChartScale;

              EjectImage->Canvas->Pen->Style = psDot;
              EjectImage->Canvas->Pen->Color = clYellow;

              EjectImage->Canvas->MoveTo(start, EjectImage->Picture->Bitmap->Height);
              EjectImage->Canvas->LineTo(start, 15);

              EjectImage->Canvas->MoveTo(start, 15);
              EjectImage->Canvas->LineTo(end, 15);

              EjectImage->Canvas->MoveTo(end, 15);
              EjectImage->Canvas->LineTo(end, EjectImage->Picture->Bitmap->Height);
            }
          }
          else
          {
            EjectTime = tempData.DefectEjectorTime / ChartScale;
            start = EjectTime - ConvHCBSetupData.EjectorInfo.DefectEjectorDelay / ChartScale - offset - ConvHCBSetupData.IntervalA / ChartScale;
            end = start + tempData.DefectEjectorLength / ChartScale;

            EjectImage->Canvas->Pen->Style = psSolid;
            EjectImage->Canvas->Pen->Color = clRed;
            EjectImage->Canvas->TextOutW(start + 5, EjectImage->Picture->Bitmap->Height - 20, "D");

            EjectImage->Canvas->MoveTo(start, EjectImage->Picture->Bitmap->Height);
            EjectImage->Canvas->LineTo(start, 10);

            EjectImage->Canvas->MoveTo(start, 10);
            EjectImage->Canvas->LineTo(end, 10);

            EjectImage->Canvas->MoveTo(end, 10);
            EjectImage->Canvas->LineTo(end, EjectImage->Picture->Bitmap->Height);

            if(ConvHCBSetupData.IntervalA != ConvNewHCBSetupData.IntervalA)
            {
              EjectTime = tempData.DefectEjectorTime / ChartScale;
              start = EjectTime - ConvHCBSetupData.EjectorInfo.DefectEjectorDelay / ChartScale - offset - ConvNewHCBSetupData.IntervalA / ChartScale;
              end = start + tempData.DefectEjectorLength / ChartScale;

              EjectImage->Canvas->Pen->Style = psDot;
              EjectImage->Canvas->Pen->Color = clRed;

              EjectImage->Canvas->MoveTo(start, EjectImage->Picture->Bitmap->Height);
              EjectImage->Canvas->LineTo(start, 15);

              EjectImage->Canvas->MoveTo(start, 15);
              EjectImage->Canvas->LineTo(end, 15);

              EjectImage->Canvas->MoveTo(end, 15);
              EjectImage->Canvas->LineTo(end, EjectImage->Picture->Bitmap->Height);
            }
          }
        }

        Sensor1Image->Refresh();
        Sensor2Image->Refresh();
        Sensor3Image->Refresh();
        TotalSensorImage->Refresh();
        EjectImage->Refresh();
        
        nextTabletNumber = SelectedTabletNumber + 1;
        searchingSW = true;
      }
      else if(searchingSW)
      {
        if(tempData.TabletNumber == nextTabletNumber)
        {
          int Sensor1StartTime = tempData.Sensor1Time / ChartScale;
          int Sensor2StartTime = tempData.Sensor2Time / ChartScale;
          int Sensor3StartTime = tempData.Sensor3Time / ChartScale;

          int Sensor1Length = tempData.Sensor1Length / ChartScale;
          int Sensor2Length = tempData.Sensor2Length / ChartScale;
          int Sensor3Length = tempData.Sensor3Length / ChartScale;

          int start, end;
          int outofChartCount = 0;

          // sensor1
          start = Sensor1StartTime - offset;
          end = start + Sensor1Length;

          if(!(start < Sensor1Image->Picture->Bitmap->Width && end < Sensor1Image->Picture->Bitmap->Width && start > 0 && end > 0))
          {
            outofChartCount++;
          }

          if(start >= 0 && start < SENSOR_CHART_WIDTH)
          {
            if(!S1WriteMask[start])
            {
              Sensor1Image->Canvas->TextOutW(start + 5, Sensor1Image->Picture->Bitmap->Height - 20, IntToStr(tempData.TabletNumber));
            }
          }

          Sensor1Image->Canvas->Pen->Style = psSolid;
          Sensor1Image->Canvas->MoveTo(start, Sensor1Image->Picture->Bitmap->Height);
          Sensor1Image->Canvas->LineTo(start, 10);

          Sensor1Image->Canvas->MoveTo(start, 10);
          Sensor1Image->Canvas->LineTo(end, 10);

          Sensor1Image->Canvas->MoveTo(end, 10);
          Sensor1Image->Canvas->LineTo(end, Sensor1Image->Picture->Bitmap->Height);

          if(start >= 0 && start < SENSOR_CHART_WIDTH)
          {
            S1WriteMask[start] = 1;
          }

          TotalSensorImage->Canvas->Pen->Color = clRed;

          TotalSensorImage->Canvas->MoveTo(start, TotalSensorImage->Picture->Bitmap->Height);
          TotalSensorImage->Canvas->LineTo(start, 10);

          TotalSensorImage->Canvas->MoveTo(start, 10);
          TotalSensorImage->Canvas->LineTo(end, 10);

          TotalSensorImage->Canvas->MoveTo(end, 10);
          TotalSensorImage->Canvas->LineTo(end, TotalSensorImage->Picture->Bitmap->Height);

          // sensor2
          start = Sensor2StartTime - offset - ConvHCBSetupData.IntervalA / ChartScale;
          end = start + Sensor2Length;

          if(!(start < Sensor2Image->Picture->Bitmap->Width && end < Sensor2Image->Picture->Bitmap->Width && start > 0 && end > 0))
          {
            outofChartCount++;
          }

          if(start >= 0 && start < SENSOR_CHART_WIDTH)
          {
            if(!S2WriteMask[start])
            {
              Sensor2Image->Canvas->TextOutW(start + 5, Sensor2Image->Picture->Bitmap->Height - 20, IntToStr(tempData.TabletNumber));
            }
          }

          Sensor2Image->Canvas->Pen->Style = psSolid;
          Sensor2Image->Canvas->MoveTo(start, Sensor2Image->Picture->Bitmap->Height);
          Sensor2Image->Canvas->LineTo(start, 10);

          Sensor2Image->Canvas->MoveTo(start, 10);
          Sensor2Image->Canvas->LineTo(end, 10);

          Sensor2Image->Canvas->MoveTo(end, 10);
          Sensor2Image->Canvas->LineTo(end, Sensor2Image->Picture->Bitmap->Height);

          if(start >= 0 && start < SENSOR_CHART_WIDTH)
          {
            S2WriteMask[start] = 1;
          }

          // sensor2 - modified
          if(ConvHCBSetupData.IntervalA != ConvNewHCBSetupData.IntervalA)
          {
            start = Sensor2StartTime - offset - ConvNewHCBSetupData.IntervalA / ChartScale;
            end = start + Sensor2Length;

            Sensor2Image->Canvas->Pen->Style = psDot;
            Sensor2Image->Canvas->MoveTo(start, Sensor2Image->Picture->Bitmap->Height);
            Sensor2Image->Canvas->LineTo(start, 15);

            Sensor2Image->Canvas->MoveTo(start, 15);
            Sensor2Image->Canvas->LineTo(end, 15);

            Sensor2Image->Canvas->MoveTo(end, 15);
            Sensor2Image->Canvas->LineTo(end, Sensor2Image->Picture->Bitmap->Height);
          }

          TotalSensorImage->Canvas->Pen->Color = clLime;

          TotalSensorImage->Canvas->MoveTo(start, TotalSensorImage->Picture->Bitmap->Height);
          TotalSensorImage->Canvas->LineTo(start, 10);

          TotalSensorImage->Canvas->MoveTo(start, 10);
          TotalSensorImage->Canvas->LineTo(end, 10);

          TotalSensorImage->Canvas->MoveTo(end, 10);
          TotalSensorImage->Canvas->LineTo(end, TotalSensorImage->Picture->Bitmap->Height);

          // sensor3
          start = Sensor3StartTime - offset - (ConvHCBSetupData.IntervalB / ChartScale + ConvHCBSetupData.IntervalA / ChartScale);
          end = start + Sensor3Length;

          if(!(start < Sensor2Image->Picture->Bitmap->Width && end < Sensor2Image->Picture->Bitmap->Width && start > 0 && end > 0))
          {
            outofChartCount++;
          }

          if(start >= 0 && start < SENSOR_CHART_WIDTH)
          {
            if(!S3WriteMask[start])
            {
              Sensor3Image->Canvas->TextOutW(start + 5, Sensor3Image->Picture->Bitmap->Height - 20, IntToStr(tempData.TabletNumber));
            }
          }

          Sensor3Image->Canvas->Pen->Style = psSolid;
          Sensor3Image->Canvas->MoveTo(start, Sensor3Image->Picture->Bitmap->Height);
          Sensor3Image->Canvas->LineTo(start, 10);

          Sensor3Image->Canvas->MoveTo(start, 10);
          Sensor3Image->Canvas->LineTo(end, 10);

          Sensor3Image->Canvas->MoveTo(end, 10);
          Sensor3Image->Canvas->LineTo(end, Sensor3Image->Picture->Bitmap->Height);

          if(start >= 0 && start < SENSOR_CHART_WIDTH)
          {
            S3WriteMask[start] = 1;
          }

          // sensor3 - modified
          if(ConvHCBSetupData.IntervalA != ConvNewHCBSetupData.IntervalA || ConvHCBSetupData.IntervalB != ConvNewHCBSetupData.IntervalB)
          {
            start = Sensor3StartTime - offset - (ConvNewHCBSetupData.IntervalB / ChartScale + ConvNewHCBSetupData.IntervalA / ChartScale);
            end = start + Sensor3Length;

            Sensor3Image->Canvas->Pen->Style = psDot;
            Sensor3Image->Canvas->MoveTo(start, Sensor3Image->Picture->Bitmap->Height);
            Sensor3Image->Canvas->LineTo(start, 15);

            Sensor3Image->Canvas->MoveTo(start, 15);
            Sensor3Image->Canvas->LineTo(end, 15);

            Sensor3Image->Canvas->MoveTo(end, 15);
            Sensor3Image->Canvas->LineTo(end, Sensor3Image->Picture->Bitmap->Height);
          }

          TotalSensorImage->Canvas->Pen->Color = clYellow;

          TotalSensorImage->Canvas->MoveTo(start, TotalSensorImage->Picture->Bitmap->Height);
          TotalSensorImage->Canvas->LineTo(start, 10);

          TotalSensorImage->Canvas->MoveTo(start, 10);
          TotalSensorImage->Canvas->LineTo(end, 10);

          TotalSensorImage->Canvas->MoveTo(end, 10);
          TotalSensorImage->Canvas->LineTo(end, TotalSensorImage->Picture->Bitmap->Height);

          if(tempData.Ejection == TABLET_EJECTION_UNINSPECT || tempData.Ejection == TABLET_EJECTION_DEFECT)
          {
            int EjectTime;
            if(tempData.Ejection == TABLET_EJECTION_UNINSPECT)
            {
              EjectTime = tempData.UnInsEjectorTime / ChartScale;
              start = EjectTime - ConvHCBSetupData.EjectorInfo.UnInsEjectorDelay / ChartScale - offset - ConvHCBSetupData.IntervalA / ChartScale;
              end = start + tempData.UnInsEjectorLength / ChartScale;

              EjectImage->Canvas->Pen->Style = psSolid;
              EjectImage->Canvas->Pen->Color = clYellow;
              EjectImage->Canvas->TextOutW(start + 5, EjectImage->Picture->Bitmap->Height - 20, "U");

              EjectImage->Canvas->MoveTo(start, EjectImage->Picture->Bitmap->Height);
              EjectImage->Canvas->LineTo(start, 10);

              EjectImage->Canvas->MoveTo(start, 10);
              EjectImage->Canvas->LineTo(end, 10);

              EjectImage->Canvas->MoveTo(end, 10);
              EjectImage->Canvas->LineTo(end, EjectImage->Picture->Bitmap->Height);

              if(ConvHCBSetupData.IntervalA != ConvNewHCBSetupData.IntervalA)
              {
                EjectTime = tempData.UnInsEjectorTime / ChartScale;
                start = EjectTime - ConvHCBSetupData.EjectorInfo.UnInsEjectorDelay / ChartScale - offset - ConvNewHCBSetupData.IntervalA / ChartScale;
                end = start + tempData.UnInsEjectorLength / ChartScale;

                EjectImage->Canvas->Pen->Style = psDot;
                EjectImage->Canvas->Pen->Color = clYellow;

                EjectImage->Canvas->MoveTo(start, EjectImage->Picture->Bitmap->Height);
                EjectImage->Canvas->LineTo(start, 15);

                EjectImage->Canvas->MoveTo(start, 15);
                EjectImage->Canvas->LineTo(end, 15);

                EjectImage->Canvas->MoveTo(end, 15);
                EjectImage->Canvas->LineTo(end, EjectImage->Picture->Bitmap->Height);
              }
            }
            else
            {
              EjectTime = tempData.DefectEjectorTime / ChartScale;
              start = EjectTime - ConvHCBSetupData.EjectorInfo.DefectEjectorDelay / ChartScale - offset - ConvHCBSetupData.IntervalA / ChartScale;
              end = start + tempData.DefectEjectorLength / ChartScale;

              EjectImage->Canvas->Pen->Style = psSolid;
              EjectImage->Canvas->Pen->Color = clRed;
              EjectImage->Canvas->TextOutW(start + 5, EjectImage->Picture->Bitmap->Height - 20, "D");

              EjectImage->Canvas->MoveTo(start, EjectImage->Picture->Bitmap->Height);
              EjectImage->Canvas->LineTo(start, 10);

              EjectImage->Canvas->MoveTo(start, 10);
              EjectImage->Canvas->LineTo(end, 10);

              EjectImage->Canvas->MoveTo(end, 10);
              EjectImage->Canvas->LineTo(end, EjectImage->Picture->Bitmap->Height);

              if(ConvHCBSetupData.IntervalA != ConvNewHCBSetupData.IntervalA)
              {
                EjectTime = tempData.DefectEjectorTime / ChartScale;
                start = EjectTime - ConvHCBSetupData.EjectorInfo.DefectEjectorDelay / ChartScale - offset - ConvNewHCBSetupData.IntervalA / ChartScale;
                end = start + tempData.DefectEjectorLength / ChartScale;

                EjectImage->Canvas->Pen->Style = psDot;
                EjectImage->Canvas->Pen->Color = clRed;

                EjectImage->Canvas->MoveTo(start, EjectImage->Picture->Bitmap->Height);
                EjectImage->Canvas->LineTo(start, 15);

                EjectImage->Canvas->MoveTo(start, 15);
                EjectImage->Canvas->LineTo(end, 15);

                EjectImage->Canvas->MoveTo(end, 15);
                EjectImage->Canvas->LineTo(end, EjectImage->Picture->Bitmap->Height);
              }
            }
          }

          Sensor1Image->Refresh();
          Sensor2Image->Refresh();
          Sensor3Image->Refresh();
          TotalSensorImage->Refresh();
          EjectImage->Refresh();
        
          nextTabletNumber = nextTabletNumber + 1;

          if(outofChartCount >= 3)
          {
            // out of chart
            break;
          }
        }
        else
        {
          // last tablet
          break;
        }
      }
    }
  }
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::ApplyDiskSpeed()
{
	ConvHCBSetupData.DiskSpeed = HCBSetupData.DiskSpeed;
	ConvHCBSetupData.BaseSpeed = HCBSetupData.BaseSpeed;

	ConvHCBSetupData.IntervalA = HCBSetupData.IntervalA	* ConvHCBSetupData.DiskSpeed / ConvHCBSetupData.BaseSpeed;
	ConvHCBSetupData.IntervalB = HCBSetupData.IntervalB	* ConvHCBSetupData.DiskSpeed / ConvHCBSetupData.BaseSpeed;

	ConvHCBSetupData.EjectorInfo.DefectEjectorDelay = (HCBSetupData.EjectorInfo.DefectEjectorDelay * 20) * ConvHCBSetupData.DiskSpeed / ConvHCBSetupData.BaseSpeed;
	ConvHCBSetupData.EjectorInfo.UnInsEjectorDelay = (HCBSetupData.EjectorInfo.UnInsEjectorDelay * 20) * ConvHCBSetupData.DiskSpeed / ConvHCBSetupData.BaseSpeed;
	ConvHCBSetupData.EjectorInfo.GoodEjectorDelay = (HCBSetupData.EjectorInfo.GoodEjectorDelay * 20) * ConvHCBSetupData.DiskSpeed / ConvHCBSetupData.BaseSpeed;

	ConvNewHCBSetupData.IntervalA = NewHCBSetupData.IntervalA	* ConvHCBSetupData.DiskSpeed / ConvHCBSetupData.BaseSpeed;
	ConvNewHCBSetupData.IntervalB = NewHCBSetupData.IntervalB	* ConvHCBSetupData.DiskSpeed / ConvHCBSetupData.BaseSpeed;

	ConvNewHCBSetupData.EjectorInfo.DefectEjectorDelay = (NewHCBSetupData.EjectorInfo.DefectEjectorDelay * 20) * ConvHCBSetupData.DiskSpeed / ConvHCBSetupData.BaseSpeed;
	ConvNewHCBSetupData.EjectorInfo.UnInsEjectorDelay = (NewHCBSetupData.EjectorInfo.UnInsEjectorDelay * 20) * ConvHCBSetupData.DiskSpeed / ConvHCBSetupData.BaseSpeed;
}
//---------------------------------------------------------------------------
void __fastcall THCBMonitoringForm::upImageClick(TObject *Sender)
{
  bExecutedFindEvent = false;
  
  if (MonitoringStringGrid->Row - 1 > 0)
		MonitoringStringGrid->Row = MonitoringStringGrid->Row - 1;
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::downImageClick(TObject *Sender)
{
  bExecutedFindEvent = false;
  
  if (MonitoringStringGrid->Row + 1 < MonitoringStringGrid->RowCount)
		MonitoringStringGrid->Row = MonitoringStringGrid->Row + 1;
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::ScrollImageMouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
  if (!IsScrollImageMouseDown)
	{
		ScrollImageMouseDownPos.x = X;
		ScrollImageMouseDownPos.y = Y;
		ScrollImageMouseMovePos.x = X;
		ScrollImageMouseMovePos.y = Y;
		IsScrollImageMouseDown = true;
    StringGridMouseDownPos = MonitoringStringGrid->Row;
		LastScrollTime = GetTickCount();
	}
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::ScrollImageMouseMove(TObject *Sender,
      TShiftState Shift, int X, int Y)
{  
  bExecutedFindEvent = false;
  
	if (Y < 0 || Y >= ScrollImage->Height) return;
	if (IsScrollImageMouseDown)
	{
		ScrollImageMouseMovePos.x = X;
		ScrollImageMouseMovePos.y = Y;
		int scrollCount = (Y - ScrollImageMouseDownPos.y) / 10;
		int newRow = StringGridMouseDownPos + scrollCount;
		if (newRow < 1) newRow = 1;
		else if (newRow >= MonitoringStringGrid->RowCount) newRow = MonitoringStringGrid->RowCount - 1;
		MonitoringStringGrid->Row = newRow;
		if (scrollCount != 0)
		{
			for (int y = 0; y < ScrollImage->Height; y++)
			{
				byte *pBitmap = (byte *)ScrollImage->Picture->Bitmap->ScanLine[y];
				byte colorB = 0xFF - abs(y - ScrollImage->Height / 2 - scrollCount * 10) * 0x4F / (ScrollImage->Height / 2);
				byte colorG = 0x7F - abs(y - ScrollImage->Height / 2 - scrollCount * 10) * 0x1F / (ScrollImage->Height / 2);
				byte colorR = 0x7F - abs(y - ScrollImage->Height / 2 - scrollCount * 10) * 0x1F / (ScrollImage->Height / 2);
				if (y % 10 == 0)
				{
					colorB = colorG = colorR = 0;
				}

				for (int x = 0; x < ScrollImage->Width; x++)
				{
					pBitmap[x * 3] = colorB;
					pBitmap[x * 3 + 1] = colorG;
					pBitmap[x * 3 + 2] = colorR;
				}
			}

			ScrollImage->Repaint();
			LastScrollTime = GetTickCount();
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::ScrollImageMouseUp(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
  IsScrollImageMouseDown = false;

	for (int y = 0; y < ScrollImage->Height; y++)
	{
		byte *pBitmap = (byte *)ScrollImage->Picture->Bitmap->ScanLine[y];
		byte colorB = 0xFF - abs(y - ScrollImage->Height / 2) * 0x4F / (ScrollImage->Height / 2);
		byte colorG = 0x7F - abs(y - ScrollImage->Height / 2) * 0x1F / (ScrollImage->Height / 2);
		byte colorR = 0x7F - abs(y - ScrollImage->Height / 2) * 0x1F / (ScrollImage->Height / 2);

		if (y % 10 == 0)
		{
			colorB = colorG = colorR = 0;
		}

		for (int x = 0; x < ScrollImage->Width; x++)
		{
			pBitmap[x * 3] = colorB;
			pBitmap[x * 3 + 1] = colorG;
			pBitmap[x * 3 + 2] = colorR;
		}
	}
	ScrollImage->Repaint();
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::ScrollTimerTimer(TObject *Sender)
{
  if (IsScrollImageMouseDown)
	{
		if (GetTickCount() - LastScrollTime > 500)
		{
			if (ScrollImageMouseDownPos.y < ScrollImage->Height / 2)
			{
				if (MonitoringStringGrid->Row > 1)
				{
					MonitoringStringGrid->Row--;
				}
			}
			else
			{
				if (MonitoringStringGrid->Row < MonitoringStringGrid->RowCount - 1)
				{
					MonitoringStringGrid->Row++;
				}
			}

			ScrollImageMouseDownPos.x = ScrollImageMouseMovePos.x;
			ScrollImageMouseDownPos.y = ScrollImageMouseMovePos.y;
			StringGridMouseDownPos = MonitoringStringGrid->Row;
			LastScrollTime = GetTickCount();

			for (int y = 0; y < ScrollImage->Height; y++)
			{
				byte *pBitmap = (byte *)ScrollImage->Picture->Bitmap->ScanLine[y];
				byte colorB = 0xFF - abs(y - ScrollImage->Height / 2) * 0x4F / (ScrollImage->Height / 2);
				byte colorG = 0x7F - abs(y - ScrollImage->Height / 2) * 0x1F / (ScrollImage->Height / 2);
				byte colorR = 0x7F - abs(y - ScrollImage->Height / 2) * 0x1F / (ScrollImage->Height / 2);

				if (y % 10 == 0)
				{
					colorB = colorG = colorR = 0;
				}

				for (int x = 0; x < ScrollImage->Width; x++)
				{
					pBitmap[x * 3] = colorB;
					pBitmap[x * 3 + 1] = colorG;
					pBitmap[x * 3 + 2] = colorR;
				}
			}

			int radius = 40;

			for (int y = ScrollImageMouseDownPos.y - radius; y < ScrollImageMouseDownPos.y + radius; y++)
			{
				if (y < 0 || y >= ScrollImage->Height) continue;
				byte *pBitmap = (byte *)ScrollImage->Picture->Bitmap->ScanLine[y];
				for (int x = ScrollImageMouseDownPos.x - radius; x < ScrollImageMouseDownPos.x + radius; x++)
				{
					if (x < 0 || x >= ScrollImage->Width) continue;
					if (radius * radius > (y - ScrollImageMouseDownPos.y) * (y - ScrollImageMouseDownPos.y) + (x - ScrollImageMouseDownPos.x) * (x - ScrollImageMouseDownPos.x))
					{
						pBitmap[x * 3] = pBitmap[x * 3] - sqrt(radius * radius - (y - ScrollImageMouseDownPos.y) * (y - ScrollImageMouseDownPos.y) - (x - ScrollImageMouseDownPos.x) * (x - ScrollImageMouseDownPos.x)) * pBitmap[x * 3] / radius / 2;
						pBitmap[x * 3 + 1] = pBitmap[x * 3 + 1] - sqrt(radius * radius - (y - ScrollImageMouseDownPos.y) * (y - ScrollImageMouseDownPos.y) - (x - ScrollImageMouseDownPos.x) * (x - ScrollImageMouseDownPos.x)) * pBitmap[x * 3 + 1] / radius / 2;
						pBitmap[x * 3 + 2] = pBitmap[x * 3 + 2] - sqrt(radius * radius - (y - ScrollImageMouseDownPos.y) * (y - ScrollImageMouseDownPos.y) - (x - ScrollImageMouseDownPos.x) * (x - ScrollImageMouseDownPos.x)) * pBitmap[x * 3 + 2] / radius / 2;
					}
				}
			}
			ScrollImage->Repaint();
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::ChartScaleOptionBtn1Click(
      TObject *Sender)
{
  TSpeedButton *tempBtn = (TSpeedButton*) Sender;

  if(tempBtn->Tag == 0)
  {
    ChartScale = 1;
  }
  else if(tempBtn->Tag == 1)
  {
    ChartScale = 2;
  }
  else if(tempBtn->Tag == 2)
  {
    ChartScale = 4;
  }
  else if(tempBtn->Tag == 3)
  {
    ChartScale = 8;
  }
  else if(tempBtn->Tag == 4)
  {
    ChartScale = 16;
  }
  else if(tempBtn->Tag == 5)
  {
    ChartScale = 20;
  }

  // event trigger
  int currentRow = MonitoringStringGrid->Row;
  MonitoringStringGrid->Row = MonitoringStringGrid->RowCount - 1;
  MonitoringStringGrid->Row = currentRow;
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::NewIntervalAEditClick(TObject *Sender)
{
  TTntEdit *theEdit = (TTntEdit *) Sender;

  if(theEdit->Text == WideString("None"))
  {
    return;
  }

	KeyboardForm->Text = theEdit->Text;
  if (KeyboardForm->ShowKeypad() == mrOk)
  {
    try
    {
      int nVal = StrToInt(KeyboardForm->Text); // for value checking (float, space, etc)
      theEdit->Text = IntToStr(nVal);

      NewHCBSetupData.IntervalA = StrToInt(NewIntervalAEdit->Text);
      NewHCBSetupData.IntervalB = StrToInt(NewIntervalBEdit->Text);
      NewHCBSetupData.EjectorInfo.DefectEjectorDelay = StrToInt(NewDefectSolDelayEdit->Text);
      NewHCBSetupData.EjectorInfo.UnInsEjectorDelay = StrToInt(NewUninsSolDelayEdit->Text);

      ApplyDiskSpeed();

      // event trigger
      int currentRow = MonitoringStringGrid->Row;
      MonitoringStringGrid->Row = MonitoringStringGrid->RowCount - 1;
      MonitoringStringGrid->Row = currentRow;
    }
    catch(...)
    {
      ShowMessage("The input value is incorrect.");
    }
  }
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::NewIntervalAEditKeyPress(
      TObject *Sender, char &Key)
{
  Key = NULL;  
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::SaveDataButtonClick(TObject *Sender)
{
  bool errorSW = false;
  if(NewIntervalAEdit->Text == WideString("None"))
  {
    errorSW = true;
  }
  else if(NewIntervalBEdit->Text == WideString("None"))
  {
    errorSW = true;
  }
  else if(NewDefectSolDelayEdit->Text == WideString("None"))
  {
    errorSW = true;
  }
  else if(NewUninsSolDelayEdit->Text == WideString("None"))
  {
    errorSW = true;
  }

  if(!errorSW)
  {
    if (MessageDlgFA("The data is saved.(Product Data / Machine Setup Data) Would you like to proceed?", mtConfirmation, TMsgDlgButtons() << mbOK << mbCancel) == mrOk)
    {
      // 제품정보 선택을 통해 현재 활성화된 데이터를 우선 저장 (변경사항에 대한 데이터 유실 방지)
      AnsiString fileName = GetProductDataFileName(ProductData.ProductCode);
      WriteProductData(fileName, ProductData);

      // 모니터링 UI에서 선택된 제품정보 데이터 처리
      AnsiString productFileName = GetProductDataFileName(ProductName);
      if(FileExists(productFileName))
      {
        ReadProductData(productFileName, tempProductData, MachineParams, MachineSetupData);

        tempProductData.StudiedSensorIntervalA = StrToInt(NewIntervalAEdit->Text);
        tempProductData.StudiedSensorIntervalB = StrToInt(NewIntervalBEdit->Text);

        WriteProductData(productFileName, tempProductData);

        if(ProductData.ProductCode == ProductName)
        {
          // 현재 제품정보입력으로부터 선택된 제품과 모니터링 UI에서 불러온 제품정보가 동일한 경우)
          WideString CurrentLOTName = ProductData.LOTName;
          tempProductData.LOTName = CurrentLOTName;
          CopyProductData(ProductData, tempProductData);
        }

        CurrentIntervalALabel->Caption = "(" + IntToStr(tempProductData.StudiedSensorIntervalA) + ")";
        CurrentIntervalBLabel->Caption = "(" + IntToStr(tempProductData.StudiedSensorIntervalB) + ")";
        // completed product data
      }
      else
      {
        CurrentIntervalALabel->Caption = "(Not exist)";
        CurrentIntervalBLabel->Caption = "(Not exist)";
      }

      MachineSetupData.EjectorInfo.DefectEjectorDelay = StrToInt(NewDefectSolDelayEdit->Text);
      MachineSetupData.EjectorInfo.UnInsEjectorDelay = StrToInt(NewUninsSolDelayEdit->Text);

      WriteMachineSetupData(ProgramPath.Env + "\\SystemInfor.ini", MachineSetupData);
      Comm_Request(COMM_HCB, CMD_MACHINE_PARAM_SETUP, &MachineSetupData, sizeof(TMachineSetupData));

      CurrentDefectDelayLabel->Caption = "(" + IntToStr(MachineSetupData.EjectorInfo.DefectEjectorDelay) + ")";
      CurrentUninsDelayLabel->Caption = "(" + IntToStr(MachineSetupData.EjectorInfo.UnInsEjectorDelay) + ")";

      ShowMessage("Completed.");
    }
  }
  else
  {
    ShowMessage("The input value is incorrect.");
  }
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::AnalysisTabletList()
{
  ProgressPanel->Visible = true;
  this->Enabled = false;

  int expectedMaxTabletCount = dataFileCount * HCB_MONITORING_DATA_COUNT;
  ProgressBar->Min = 0;
  ProgressBar->Max = expectedMaxTabletCount;
  ProgressBar->Position = 0;

  int Count[5];
  memset(Count, 0, sizeof(int) * 5);

  for(int fileIndex = 1; fileIndex <= dataFileCount; fileIndex++)
  {
    AnsiString Filename = DataPath + "\\Result" + IntToStr(fileIndex) + ".hmf";

    TFileStream *pFileStream = NULL;
    if(FileExists(Filename))
    {
      pFileStream = new TFileStream(Filename, fmOpenRead);

      THCBDisk2TabletUnit tempData;

      while(1)
      {
        pFileStream->Read(&tempData, sizeof(THCBDisk2TabletUnit));

        bool bError = false;
        if (tempData.InspectionResult & TABLET_RESULT_SPB_MASK)
        {
          int spbUnInsResult = (tempData.InspectionResult & ~TABLET_RESULT_SPB_MASK);
          switch (spbUnInsResult)
          {
            case SPB_TABLET_RESULT_NONE:
              Count[COUNT_TAG_UNINS]++;
              break;
            case SPB_TABLET_RESULT_GOOD:
              Count[COUNT_TAG_GOOD]++;
              break;
            case SPB_TABLET_RESULT_PROCESSING:
              Count[COUNT_TAG_UNINS]++;
              break;
            case SPB_TABLET_RESULT_DEFECT:
              Count[COUNT_TAG_DEFECT]++;
              break;
            case SPB_TABLET_RESULT_UNINS_IMAGE_BUFFER_FULL:
              Count[COUNT_TAG_UNINS]++;
              break;
            case SPB_TABLET_RESULT_UNINS_TABLET_NUMBER_UNDEFINED:
              Count[COUNT_TAG_UNINS]++;
              break;
            case SPB_TABLET_RESULT_UNINS_WRONG_TABLET_NUMBER:
              Count[COUNT_TAG_UNINS]++;
              break;
            case SPB_TABLET_RESULT_UNINS_CAPTURE_TIMEOUT:
              Count[COUNT_TAG_UNINS]++;
              break;
            case SPB_TABLET_RESULT_UNINS_CAPTURE_NOT_READY:
              Count[COUNT_TAG_UNINS]++;
              break;
            case SPB_TABLET_RESULT_UNINS_PROCESSING_TIMEOUT:
              Count[COUNT_TAG_UNINS]++;
              break;
            case SPB_TABLET_RESULT_UNINS_PROCESSING_ERROR:
              Count[COUNT_TAG_UNINS]++;
              break;
            case SPB_TABLET_RESULT_UNINS_CPB_FULL:
              Count[COUNT_TAG_UNINS]++;
              break;
            case SPB_TABLET_RESULT_UNINS_CLOSED_TABLET:
              Count[COUNT_TAG_UNINS]++;
              break;
            case SPB_TABLET_RESULT_UNINS_TABLET_POSITION:
              Count[COUNT_TAG_UNINS]++;
              break;
            case SPB_TABLET_RESULT_UNINS_BRIGHTNESS_DROPPED:
              Count[COUNT_TAG_UNINS]++;
              break;
            case SPB_TABLET_RESULT_UNINS_BRIGHTNESS_CHASE:
              Count[COUNT_TAG_UNINS]++;
              break;
            default:
              Count[COUNT_TAG_UNINS]++;
              break;
          }
        }
        else
        {
          switch(tempData.InspectionResult)
          {
            case TABLET_RESULT_NONE:
              Count[COUNT_TAG_ELSE]++;
              bError = true;
              break;
            case TABLET_RESULT_GOOD:
              Count[COUNT_TAG_GOOD]++;
              break;
            case TABLET_RESULT_DEFECT:
              Count[COUNT_TAG_DEFECT]++;
              break;
            case TABLET_RESULT_DEFECT_UNPRINT:
              if(MachineSetupData.LasercomplexerInfo.Laser_complexer_Enable)
              {
                // LIMA 장비인 경우 미인쇄 불량 개수를 전체 수량에서 제외
                Count[COUNT_TAG_TOTAL]--;
              }
              else
              {
                Count[COUNT_TAG_DEFECT]++;
              }
              
              break;
            case TABLET_RESULT_DEFECT_SPB_PROCESSING_NOT_COMPLETE:
              Count[COUNT_TAG_DEFECT]++;
              break;
            case TABLET_RESULT_UNINS_SPB_TIMEOUT:
              Count[COUNT_TAG_UNINS]++;
              break;
            case TABLET_RESULT_UNINS_SPB_PROCESSING_NOT_COMPLETE:
              Count[COUNT_TAG_UNINS]++;
              break;
            case TABLET_RESULT_INSERTED:
              Count[COUNT_TAG_UNINS]++;
              break;
            case TABLET_RESULT_DISAPPEARED:
              Count[COUNT_TAG_UNINS]++;
              break;
            case TABLET_RESULT_CLOSED_UNINS:
              Count[COUNT_TAG_UNINS]++;
              break;
            case TABLET_RESULT_CLOSED_DEFECT:
              Count[COUNT_TAG_DEFECT]++;
              break;
            case TABLET_RESULT_SENSOR_1_MISFEEDING:
              Count[COUNT_TAG_UNINS]++;
              break;
            case TABLET_RESULT_SENSOR_2_MISFEEDING:
              Count[COUNT_TAG_UNINS]++;
              break;
            case TABLET_RESULT_MULTI_TABLET_SENSOR_1:
              Count[COUNT_TAG_UNINS]++;
              break;
            case TABLET_RESULT_MULTI_TABLET_SENSOR_2:
              Count[COUNT_TAG_UNINS]++;
              break;
            case TABLET_RESULT_UNINTENDED_UNINSPECT:
              Count[COUNT_TAG_UNINS]++;
              break;
            case TABLET_RESULT_DEFECT_FR_MISMATCH:
              Count[COUNT_TAG_DEFECT]++;
              break;
            default:
              Count[COUNT_TAG_ELSE]++;
              bError = true;
              break;
          }
        }

        Count[COUNT_TAG_TOTAL]++;

        if(!bError)
        {
          int spbUnInsResult = (tempData.InspectionResult & ~TABLET_RESULT_SPB_MASK);

          int ExpectedMaxLength;
          int ExpectedMinLength;

          int ExpectedS1MinTime;
          int ExpectedS1MaxTime;

          int ExpectedS2MinTime;
          int ExpectedS2MaxTime;

          int AjustSpeedIntervalLimit = SENSOR_INTERVAL_LIMIT	* HCBSetupData.DiskSpeed / HCBSetupData.BaseSpeed;

          ExpectedMaxLength = tempData.Sensor3Length * 150 / 100; // 1.5배
          ExpectedMinLength = tempData.Sensor3Length * 50 / 100; // 0.5배

          ExpectedS2MinTime = tempData.Sensor3Time - (ConvHCBSetupData.IntervalB + AjustSpeedIntervalLimit);
          ExpectedS2MaxTime = tempData.Sensor3Time - (ConvHCBSetupData.IntervalB - AjustSpeedIntervalLimit);

          ExpectedS1MinTime = tempData.Sensor2Time - (ConvHCBSetupData.IntervalA + AjustSpeedIntervalLimit);
          ExpectedS1MaxTime = tempData.Sensor2Time - (ConvHCBSetupData.IntervalA - AjustSpeedIntervalLimit);

          if(tempData.InspectionResult != TABLET_RESULT_NONE)
          {
            if(tempData.Sensor3Length)
            {
              // sensor 3에 인식된 경우
              if(tempData.Ejection == TABLET_EJECTION_UNINSPECT || tempData.Ejection == TABLET_EJECTION_DEFECT)
              {
                // Eject가 실행되었는데 S3에 인식된 경우
                Count[COUNT_TAG_ELSE]++;
              }
              else
              {
                // Eject가 실행되지 않은 경우
                // 검사 결과값 확인

                if ((tempData.InspectionResult & TABLET_RESULT_SPB_MASK) && (spbUnInsResult != SPB_TABLET_RESULT_GOOD))
                {
                  // 검사 결과가 양품이 아닌데 Eject 설정이 되지 않아 S3에 인식된 경우
                  Count[COUNT_TAG_ELSE]++;
                }
                else if(!(tempData.InspectionResult & TABLET_RESULT_SPB_MASK) && (tempData.InspectionResult != TABLET_RESULT_GOOD))
                {
                  // 검사 결과가 양품이 아닌데 Eject 설정이 되지 않아 S3에 인식된 경우
                  Count[COUNT_TAG_ELSE]++;
                }
                else
                {
                  // 양품인 경우
                  // S1, S2 상태가 정상인지 확인

                  // length & time check
                  if(tempData.Sensor1Length > ExpectedMaxLength || tempData.Sensor1Length < ExpectedMinLength)
                  {
                    Count[COUNT_TAG_ELSE]++;
                  }
                  else if(tempData.Sensor2Length > ExpectedMaxLength || tempData.Sensor2Length < ExpectedMinLength)
                  {
                    Count[COUNT_TAG_ELSE]++;
                  }
                  else if(tempData.Sensor2Time < ExpectedS2MinTime || tempData.Sensor2Time > ExpectedS2MaxTime)
                  {
                    Count[COUNT_TAG_ELSE]++;
                  }
                  else if(tempData.Sensor1Time < ExpectedS1MinTime || tempData.Sensor1Time > ExpectedS1MaxTime)
                  {
                    // 위 if 문에 적용이 되지 않았다면, S2 time이 정상이라는 가정
                    Count[COUNT_TAG_ELSE]++;
                  }
                }
              }
            }
            else
            {
               if(tempData.Ejection == TABLET_EJECTION_NONE)
               {
                  Count[COUNT_TAG_ELSE]++;
               }
              // sensor 3에 인식되지 않은 경우
/*
              if ((tempData.InspectionResult & TABLET_RESULT_SPB_MASK) && (spbUnInsResult == SPB_TABLET_RESULT_GOOD))
              {
                // 검사 결과가 양품인데 S3에 인식되지 않은 경우
                Count[COUNT_TAG_ELSE]++;
              }
              else if(!(tempData.InspectionResult & TABLET_RESULT_SPB_MASK) && (tempData.InspectionResult == TABLET_RESULT_GOOD))
              {
                // 검사 결과가 양품인데 S3에 인식되지 않은 경우
                Count[COUNT_TAG_ELSE]++;
              }
*/              
            }
          }
        }

        Application->ProcessMessages();
        ProgressBar->Position++;

        if(pFileStream->Position >= pFileStream->Size)
        {
          break;
        }
      }

      delete pFileStream;
    }
  }

  AnalysisCountInfo1->Caption = IntToStr(Count[0]);
  AnalysisCountInfo2->Caption = IntToStr(Count[1]);
  AnalysisCountInfo3->Caption = IntToStr(Count[2]);
  AnalysisCountInfo4->Caption = IntToStr(Count[3]);
  AnalysisCountInfo5->Caption = IntToStr(Count[4]);

  this->Enabled = true;
  ProgressPanel->Visible = false;
}
//---------------------------------------------------------------------------
void __fastcall THCBMonitoringForm::FindErrorBtnClick(TObject *Sender)
{
  ShiftRowIndex = MonitoringStringGrid->Row;

  int SelectedTabletNumber;
  int SelectRow;

  if(bExecutedFindEvent)
  {
    // continuous event
    SelectRow = MonitoringStringGrid->Row + 1;
  }
  else
  {
    // new event
    SelectRow = MonitoringStringGrid->Row;
  }

  bExecutedFindEvent = true;

  bool searchingSW = false;
  bool FindSW = false;

  int FindTabletNumber;
  AnsiString ErrorReason = "";

  if(SelectRow < MonitoringStringGrid->RowCount)
  {
    if(SelectRow > 0 && !MonitoringStringGrid->Cells[0][SelectRow].IsEmpty())
    {
      SelectedTabletNumber = StrToInt(MonitoringStringGrid->Cells[0][SelectRow]);

      vector<THCBDisk2TabletUnit>::iterator it;
      THCBDisk2TabletUnit tempData;
  
      for (it = HCBTabletUnitList.begin(); it < HCBTabletUnitList.end(); it++)
      {
        memcpy(&tempData, it, sizeof(THCBDisk2TabletUnit));
        if(tempData.TabletNumber == SelectedTabletNumber || searchingSW)
        {
          searchingSW = true;

          bool bError = false;
          if (tempData.InspectionResult & TABLET_RESULT_SPB_MASK)
          {
            // continue
          }
          else
          {
            switch(tempData.InspectionResult)
            {
              case TABLET_RESULT_NONE:
                bError = true;
                ErrorReason = "Result None";
                break;

              case TABLET_RESULT_GOOD:
              case TABLET_RESULT_DEFECT:
              case TABLET_RESULT_DEFECT_UNPRINT:
              case TABLET_RESULT_DEFECT_SPB_PROCESSING_NOT_COMPLETE:
              case TABLET_RESULT_UNINS_SPB_TIMEOUT:
              case TABLET_RESULT_UNINS_SPB_PROCESSING_NOT_COMPLETE:
              case TABLET_RESULT_INSERTED:
              case TABLET_RESULT_DISAPPEARED:
              case TABLET_RESULT_CLOSED_UNINS:
              case TABLET_RESULT_CLOSED_DEFECT:
              case TABLET_RESULT_SENSOR_1_MISFEEDING:
              case TABLET_RESULT_SENSOR_2_MISFEEDING:
              case TABLET_RESULT_MULTI_TABLET_SENSOR_1:
              case TABLET_RESULT_MULTI_TABLET_SENSOR_2:
              case TABLET_RESULT_UNINTENDED_UNINSPECT:
              case TABLET_RESULT_DEFECT_FR_MISMATCH:
                // continue
                break;

              default:
                bError = true;
                ErrorReason = "Result None";
                break;
            }
          }

          if(!bError)
          {
            int spbUnInsResult = (tempData.InspectionResult & ~TABLET_RESULT_SPB_MASK);

            int ExpectedMaxLength;
            int ExpectedMinLength;

            int ExpectedS1MinTime;
            int ExpectedS1MaxTime;

            int ExpectedS2MinTime;
            int ExpectedS2MaxTime;

            int AjustSpeedIntervalLimit = SENSOR_INTERVAL_LIMIT	* HCBSetupData.DiskSpeed / HCBSetupData.BaseSpeed;

            ExpectedMaxLength = tempData.Sensor3Length * 150 / 100; // 1.5배
            ExpectedMinLength = tempData.Sensor3Length * 50 / 100; // 0.5배

            ExpectedS2MinTime = tempData.Sensor3Time - (ConvHCBSetupData.IntervalB + AjustSpeedIntervalLimit);
            ExpectedS2MaxTime = tempData.Sensor3Time - (ConvHCBSetupData.IntervalB - AjustSpeedIntervalLimit);

            ExpectedS1MinTime = tempData.Sensor2Time - (ConvHCBSetupData.IntervalA + AjustSpeedIntervalLimit);
            ExpectedS1MaxTime = tempData.Sensor2Time - (ConvHCBSetupData.IntervalA - AjustSpeedIntervalLimit);

            if(tempData.InspectionResult != TABLET_RESULT_NONE)
            {
              if(tempData.Sensor3Length)
              {
                // sensor 3에 인식된 경우
                if(tempData.Ejection == TABLET_EJECTION_UNINSPECT || tempData.Ejection == TABLET_EJECTION_DEFECT)
                {
                  // Eject가 실행되었는데 S3에 인식된 경우
                  bError = true;
                  ErrorReason = "Required Ejt Chk";
                }
                else
                {
                  // Eject가 실행되지 않은 경우
                  // 검사 결과값 확인

                  if ((tempData.InspectionResult & TABLET_RESULT_SPB_MASK) && (spbUnInsResult != SPB_TABLET_RESULT_GOOD))
                  {
                    // 검사 결과가 양품이 아닌데 Eject 설정이 되지 않아 S3에 인식된 경우
                    bError = true;
                    ErrorReason = "Ejt State Err";
                  }
                  else if(!(tempData.InspectionResult & TABLET_RESULT_SPB_MASK) && (tempData.InspectionResult != TABLET_RESULT_GOOD))
                  {
                    // 검사 결과가 양품이 아닌데 Eject 설정이 되지 않아 S3에 인식된 경우
                    bError = true;
                    ErrorReason = "Ejt State Err";
                  }
                  else
                  {
                    // 양품인 경우
                    // S1, S2 상태가 정상인지 확인

                    // length & time check
                    if(tempData.Sensor1Length > ExpectedMaxLength || tempData.Sensor1Length < ExpectedMinLength)
                    {
                      bError = true;
                      ErrorReason = "Required S1 Chk(L)";
                    }
                    else if(tempData.Sensor2Length > ExpectedMaxLength || tempData.Sensor2Length < ExpectedMinLength)
                    {
                      bError = true;
                      ErrorReason = "Required S2 Chk(L)";
                    }
                    else if(tempData.Sensor2Time < ExpectedS2MinTime || tempData.Sensor2Time > ExpectedS2MaxTime)
                    {
                      bError = true;
                      ErrorReason = "Required S2 Chk(Dly)";
                    }
                    else if(tempData.Sensor1Time < ExpectedS1MinTime || tempData.Sensor1Time > ExpectedS1MaxTime)
                    {
                      // 위 if 문에 적용이 되지 않았다면, S2 time이 정상이라는 가정
                      bError = true;
                      ErrorReason = "Required S1 Chk(Dly)";
                    }
                  }
                }
              }
              else
              {
			if(tempData.Ejection == TABLET_EJECTION_NONE)
			{
			      bError = true;
			      ErrorReason = "Expected Over Blow";			
			}
                // sensor 3에 인식되지 않은 경우
/*
                if ((tempData.InspectionResult & TABLET_RESULT_SPB_MASK) && (spbUnInsResult == SPB_TABLET_RESULT_GOOD))
                {
                  // 검사 결과가 양품인데 S3에 인식되지 않은 경우
                  bError = true;
                  ErrorReason = "Expected Over Blow";
                }
                else if(!(tempData.InspectionResult & TABLET_RESULT_SPB_MASK) && (tempData.InspectionResult == TABLET_RESULT_GOOD))
                {
                  // 검사 결과가 양품인데 S3에 인식되지 않은 경우
                  bError = true;
                  ErrorReason = "Expected Over Blow";
                }
*/                
              }
            }
          }

          if(bError)
          {
            FindSW = true;
            FindTabletNumber = tempData.TabletNumber;
            break;
          }
        }
      }
    }
  }

  if(FindSW)
  {
    for(int listIndex = MonitoringStringGrid->FixedRows; listIndex < MonitoringStringGrid->RowCount; ++listIndex)
    {
      if(listIndex > 0 && !MonitoringStringGrid->Cells[0][listIndex].IsEmpty())
      {
        int currentTabletNumber = StrToInt(MonitoringStringGrid->Cells[0][listIndex]);

        if(currentTabletNumber == FindTabletNumber)
        {
          ShiftRowIndex = listIndex;
          MonitoringStringGrid->Row = ShiftRowIndex;
          break;
        }
      }
    }

    ErrorReasonLabel->Caption = ErrorReason;
  }
  else
  {
    ErrorReasonLabel->Caption = "Not exist (on page)";
  }
}
//---------------------------------------------------------------------------

void __fastcall THCBMonitoringForm::LoadData(AnsiString RootPath)
{
  bool bError = false;
  
  AnsiString DataFileName;
  DataFileName = RootPath + "\\data.ini";

  if(FileExists(DataFileName))
  {
    TIniFile *iniFile = new TIniFile(DataFileName);

    if(iniFile)
    {
      double InspectionStartTime, InspectionEndTime;
      ProductName = iniFile->ReadString("Data", "Product Name", "");
      LOTName = iniFile->ReadString("Data", "LOT Name", "");
      InspectionStartTime = iniFile->ReadFloat("Data", "Inspection Start Time", 0);
      InspectionEndTime = iniFile->ReadFloat("Data", "Inspection End Time", 0);
      dataFileCount = iniFile->ReadInteger("Data", "Count", -1);

      if(ProductName == "" ||
          LOTName == "" ||
          InspectionStartTime == 0 ||
          InspectionEndTime == 0 ||
          dataFileCount == -1)
      {
        bError = true;
      }
      else
      {
        ProductNameLabel->Caption = ProductName;
        LOTNameLabel->Caption = LOTName;

        AnsiString TimeLabel;
        DateTimeToString(TimeLabel, "yy/mm/dd  HH:mm:ss", InspectionStartTime);
        InspectionStartTimeLabel->Caption = TimeLabel;

        DateTimeToString(TimeLabel, "yy/mm/dd  HH:mm:ss", InspectionEndTime);
        InspectionEndTimeLabel->Caption = TimeLabel;

        dataFileCount = dataFileCount + 1;

        HCBSetupData.DiskSpeed = iniFile->ReadInteger("Data", "Disk Speed", 0);
        HCBSetupData.BaseSpeed = iniFile->ReadInteger("Data", "Base Speed", 0);
        HCBSetupData.IntervalA = iniFile->ReadInteger("Data", "Interval A", 0);
        HCBSetupData.IntervalB = iniFile->ReadInteger("Data", "Interval B", 0);

        HCBSetupData.EjectorInfo.DefectEjectorDelay = iniFile->ReadInteger("Data", "Defect Ejector Delay", 20);
        HCBSetupData.EjectorInfo.UnInsEjectorDelay = iniFile->ReadInteger("Data", "UnIns Ejector Delay", 20);
        HCBSetupData.EjectorInfo.GoodEjectorDelay = iniFile->ReadInteger("Data", "Good Ejector Delay", 20);
        HCBSetupData.EjectorInfo.DefectEjectorDelay = iniFile->ReadInteger("Data", "Defect Ejector Length", 1);
        HCBSetupData.EjectorInfo.UnInsEjectorDelay = iniFile->ReadInteger("Data", "UnIns Ejector Length", 1);
        HCBSetupData.EjectorInfo.GoodEjectorDelay = iniFile->ReadInteger("Data", "Good Ejector Length", 1);

        DiskSpeedLabel->Caption = IntToStr(HCBSetupData.BaseSpeed * 100 / HCBSetupData.DiskSpeed) + "%";
        IntervalLabel->Caption = IntToStr(HCBSetupData.IntervalA) + " / " + IntToStr(HCBSetupData.IntervalB);

        NewHCBSetupData.IntervalA = HCBSetupData.IntervalA;
        NewHCBSetupData.IntervalB = HCBSetupData.IntervalB;
        NewHCBSetupData.EjectorInfo.DefectEjectorDelay = HCBSetupData.EjectorInfo.DefectEjectorDelay;
        NewHCBSetupData.EjectorInfo.UnInsEjectorDelay = HCBSetupData.EjectorInfo.UnInsEjectorDelay;

        NewIntervalAEdit->Text = IntToStr(HCBSetupData.IntervalA);
        NewIntervalBEdit->Text = IntToStr(HCBSetupData.IntervalB);
        NewDefectSolDelayEdit->Text = IntToStr(HCBSetupData.EjectorInfo.DefectEjectorDelay);
        NewUninsSolDelayEdit->Text = IntToStr(HCBSetupData.EjectorInfo.UnInsEjectorDelay);

        CurrentIntervalALabel->Visible = true;
        CurrentIntervalBLabel->Visible = true;
        CurrentDefectDelayLabel->Visible = true;
        CurrentUninsDelayLabel->Visible = true;
  
        AnsiString productFileName = GetProductDataFileName(ProductName);

        if(FileExists(productFileName))
        {
          ReadProductData(productFileName, tempProductData, MachineParams, MachineSetupData);

          CurrentIntervalALabel->Caption = "(" + IntToStr(tempProductData.StudiedSensorIntervalA) + ")";
          CurrentIntervalBLabel->Caption = "(" + IntToStr(tempProductData.StudiedSensorIntervalB) + ")";
        }
        else
        {
          CurrentIntervalALabel->Caption = "(Not exist)";
          CurrentIntervalBLabel->Caption = "(Not exist)";
        }

        CurrentDefectDelayLabel->Caption = "(" + IntToStr(MachineSetupData.EjectorInfo.DefectEjectorDelay) + ")";
        CurrentUninsDelayLabel->Caption = "(" + IntToStr(MachineSetupData.EjectorInfo.UnInsEjectorDelay) + ")";

        int Count[5]; 
        Count[0] = iniFile->ReadInteger("Data", "Total Tablet Count", 0);
        Count[1] = iniFile->ReadInteger("Data", "Good Tablet Count", 0);
        Count[2] = iniFile->ReadInteger("Data", "Defect Tablet Count", 0);
        Count[3] = iniFile->ReadInteger("Data", "Uninspection Tablet Count", 0);
        Count[4] = iniFile->ReadInteger("Data", "Couunter Sensor Count", 0);

        RealCountInfo1->Caption = IntToStr(Count[0]);
        RealCountInfo2->Caption = IntToStr(Count[1]);
        RealCountInfo3->Caption = IntToStr(Count[2]);
        RealCountInfo4->Caption = IntToStr(Count[3]);
        RealCountInfo5->Caption = IntToStr(Count[4]);
      }

      delete iniFile;
    }
    else
    {
      bError = true;
    }
  }
  else
  {
    bError = true;
  }

  if(bError)
  {
    ShowMessage("Data does not exist.");
  }
  else
  {
    DataPath = RootPath;
    PageControl->Enabled = true;
    ApplyDiskSpeed();
      
    AnalysisTabletList();
    RefreshDataChart(true);

    // event trigger
    int currentRow = MonitoringStringGrid->Row;
    MonitoringStringGrid->Row = MonitoringStringGrid->RowCount - 1;
    MonitoringStringGrid->Row = currentRow;
  }
}
//---------------------------------------------------------------------------
void __fastcall THCBMonitoringForm::FormActivate(TObject *Sender)
{
  this->Refresh();
  
  if(bRecentFileLoad)
  {
    LoadData(RecentFilePath);
  }
}
//---------------------------------------------------------------------------

