// CC 20260323 Form thread — creates and runs the MapWindow form on its own
// thread with its own Win32 message loop, independent of HC's thread.
unit uFormThread;

{$mode objfpc}{$H+}

interface

uses
  Classes, Windows, SysUtils, Forms,
  uThreadComm;

type
  TFormThread = class(TThread)
  private
    FReadyEvent: THandle;
    FCaption: string;
    FDLLVERN: Integer;
    FDLLVERINTN: Integer;
  protected
    procedure Execute; override;
  public
    constructor Create(const aCaption: string; aDLLVERN, aDLLVERINT: Integer);
    destructor Destroy; override;
    function WaitReady(timeoutMs: DWORD): Boolean;
  end;

implementation

uses
  mainform;

type
  // CC 20260924 access class for TApplication's protected async call queue
  TApplicationAccess = class(TApplication);

constructor TFormThread.Create(const aCaption: string; aDLLVERN, aDLLVERINT: Integer);
begin
  FCaption := aCaption;
  FDLLVERN := aDLLVERN;
  FDLLVERINTN := aDLLVERINT;
  FReadyEvent := CreateEvent(nil, True, False, nil);  // manual-reset, initially non-signaled
  FreeOnTerminate := False;
  inherited Create(False);  // start immediately
end;

destructor TFormThread.Destroy;
begin
  CloseHandle(FReadyEvent);
  inherited;
end;

procedure TFormThread.Execute;
var
  msg: TMsg;
begin
  // CC 20260323 Initialize LCL on this thread — registers window classes,
  // creates Application handle. Safe because HC never calls LCL.
  Application.Initialize;

  // Create the form on this thread — all LCL interaction stays here
  mainform.frmMain := TfrmMain.Create(nil);
  // NOTE: do NOT set ParentWindow — form floats as independent window
  mainform.frmMain.Caption := FCaption;
  // CC 20260922 rgVisibility now synced from gMapSettings in FormCreate (default Player)

  // Store handle for cross-thread PostMessage
  gFormHWND := mainform.frmMain.Handle;

  // Signal that the form is ready
  SetEvent(FReadyEvent);

  // CC 20260323 Run own message loop — completely independent of HC's thread
  while GetMessage(msg, 0, 0, 0) do
  begin
    TranslateMessage(msg);
    DispatchMessage(msg);
    // CC 20260924 LCL defers Release/caFree (and QueueAsyncCall) to Application's
    //  async queue, which only Application.Run/HandleMessage process. This loop
    //  replaces those, so run the queue here or forms never close or free.
    TApplicationAccess(Application).ProcessAsyncCallQueue;
  end;

  // Cleanup — form is being destroyed
  gFormHWND := 0;
  mainform.frmMain.Free;
  mainform.frmMain := nil;
end;

function TFormThread.WaitReady(timeoutMs: DWORD): Boolean;
begin
  Result := WaitForSingleObject(FReadyEvent, timeoutMs) = WAIT_OBJECT_0;
end;

end.
