//---------------------------------------------------------------------------
#include <fmx.h>
#pragma hdrstop

#include "Main.h"
#include "Settings.h"
#include "System.IOUtils.hpp"
#include "FMX.DialogService.hpp"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "Winsoft.Android.Camera"
#pragma link "Winsoft.FireMonkey.Obr"
#pragma resource "*.fmx"
TFormMain *FormMain;
//---------------------------------------------------------------------------
__fastcall TFormMain::TFormMain(TComponent* Owner)
  : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::ACameraDataReady(TObject *Sender)
{
  if (TInterlocked::BitTestAndSet(Scanning, 0))
  {
    ACamera->ReleaseData(); // already scanning so nothing to do with data
    return;
  }

  TThread::CreateAnonymousThread(
    [this]()
    {
      try
      {
        try
        {
          ACamera->DataToRgba(&RgbaData[0], ACamera->PreviewRotation, ACamera->PreviewHorizMirror);
        }
        __finally
        {
          ACamera->ReleaseData();
        }

        try
        {
          int Width, Height;
          if (ACamera->PreviewRotation == ro0 || ACamera->PreviewRotation == ro180)
          {
            Width = RgbaDataWidth;
            Height = RgbaDataHeight;
          }
          else
          {
            Width = RgbaDataHeight;
            Height = RgbaDataWidth;
          }

          ACamera->UpdateBitmap(ScanBitmap, &RgbaData[0], Width, Height);

          FObr->Picture = ScanBitmap;
          try
          {
            FObr->Scan();
            if (FObr->BarcodeCount > 0)
            {
              TObrSymbol *Barcode = FObr->Barcode[0];
              String Text = Barcode->SymbologyName + Barcode->SymbologyAddonName + " " + Barcode->OrientationName + " " + Barcode->DataUtf8;

              // execute UI code in main thread
              TThread::Queue(NULL,
                [this, Text]()
                {
                  if (LabelBarcode->Text != Text)
                  {
                    LabelBarcode->Text = Text;
                    ACamera->PlayMediaActionSound(msStartVideoRecording);
                  }
                });
            }
          }
          __finally
          {
            FObr->Picture = NULL;
          }
        }
        catch (Exception &ex)
        {
          String text = ex.Message;
          // execute UI code in main thread
          TThread::Queue(NULL,
            [this, text]()
            {
              LabelBarcode->Text = text;
            });
        }
      }
      __finally
      {
        TInterlocked::BitTestAndClear(Scanning, 0);
      }
    })->Start();
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::ButtonSettingsClick(TObject *Sender)
{
  if (!ACamera->PermissionGranted)
    ACamera->RequestPermission();
  else
  {
    ACamera->Active = true;
    Stop();
    FormSettings->Show();
    ButtonStartStop->Enabled = true;
  }
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::Start()
{
  RgbaDataWidth = ACamera->PreviewSize.Width;
  RgbaDataHeight = ACamera->PreviewSize.Height;
  RgbaData.Length = RgbaDataWidth * RgbaDataHeight;

  LabelBarcode->Text = "";
  ACamera->Start();
  ButtonTakePicture->Enabled = true;
  ButtonStartStop->Text = "Stop";
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::Stop()
{
  ACamera->Stop();
  ButtonTakePicture->Enabled = false;
  ButtonStartStop->Text = "Start";
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::ButtonStartStopClick(TObject *Sender)
{
  if (ACamera->Capturing)
    Stop();
  else
    Start();
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::ButtonTakePictureClick(TObject *Sender)
{
  ACamera->TakePicture();
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::ACameraPictureTaken(TObject *Sender, System::DynamicArray<System::Byte> Data)
{
  TFile::WriteAllBytes(System::Ioutils::TPath::Combine(System::Ioutils::TPath::GetPublicPath(), "picture_" + FormatDateTime("yyyymmdd_hhnnss", Now()) + ".jpeg"), Data);
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::FormCreate(TObject *Sender)
{
  ScanBitmap = new TBitmap();

  ACamera->OnPictureTaken = ACameraPictureTaken;
  ACamera->OnDisplayRationale = ACameraDisplayRationale;
  if (TPlatformServices::Current->SupportsPlatformService(__uuidof(IFMXApplicationEventService)))
  {
    FMXApplicationEventService = TPlatformServices::Current->GetPlatformService(__uuidof(IFMXApplicationEventService));
    if (FMXApplicationEventService)
      FMXApplicationEventService->SetApplicationEventHandler(HandleAppEvent);
  }

  ACamera->LoadMediaActionSound(msStartVideoRecording);
  FObr->Active = true;
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::ACameraPermission(TObject *Sender)
{
  if (ACamera->PermissionGranted)
    ButtonSettingsClick(this);
  else
    ShowMessage("Cannot access the camera because the required permission has not been granted");
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::ACameraDisplayRationale(TObject *Sender, const _di_TProc APostRationaleProc)
{
  // Show an explanation to the user *asynchronously* - don't block this thread waiting for the user's response!
  // After the user sees the explanation, invoke the post-rationale routine to request the permissions
  TDialogService::ShowMessage("The application needs to access the camera in order to work",
    [APostRationaleProc](const TModalResult AResult)
    {
      APostRationaleProc->Invoke();
    });
}
//---------------------------------------------------------------------------
bool __fastcall TFormMain::HandleAppEvent(TApplicationEvent AAppEvent, TObject *AContext)
{
  if (ACamera->PermissionGranted)
    switch (AAppEvent)
    {
      case TApplicationEvent::EnteredBackground:
      {
        Paused = ACamera->Capturing;
        Stop();
        ACamera->Active = false;
        break;
      }

      case TApplicationEvent::WillBecomeForeground:
      {
        ACamera->Active = true;
        FormSettings->ApplySettings();
        if (Paused)
        {
          Paused = false;
          Start();
        }
        break;
      }

      default:
        break;
    }

  return true;
}
//---------------------------------------------------------------------------