unit BlockAsyncForm;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, BlockToAsyncBuf, PrimeRangeThread;

const
  MaxCount = 20;

type
  TBlockAsyncFrm = class(TForm)
    Label1: TLabel;
    StartRangeEdit: TEdit;
    Label2: TLabel;
    EndRangeEdit: TEdit;
    SubmitBtn: TButton;
    ResultsMemo: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure SubmitBtnClick(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    FItemsInTransit: integer;
    FBuf: TBlockToAsyncBuf;
    FWorkerThread: TPrimeRangeThread;
    procedure BufRead(Sender: TObject);
    procedure BufWrite(Sender: TObject);
  public
    { Public declarations }
  end;

var
  BlockAsyncFrm: TBlockAsyncFrm;

implementation

{$R *.DFM}

procedure TBlockAsyncFrm.FormCreate(Sender: TObject);
begin
  FWorkerThread := TPrimeRangeThread.Create(true);
  FBuf := TBlockToAsyncBuf.Create(Self);
  with FBuf do
  begin
    { Note that these changes will take effect before
      events from this component could possibly occur }
    OnRead := BufRead;
    OnWrite := BufWrite;
  end;
  SetThreadPriority(FWorkerThread.Handle, THREAD_PRIORITY_BELOW_NORMAL);
  with FWorkerThread do
  begin
    Buf := FBuf;
    Resume;
  end;
end;

procedure TBlockAsyncFrm.SubmitBtnClick(Sender: TObject);

var
  Request: PRangeRequestType;
  Temp: integer;

begin
  New(Request);
  try
    Request.Low := StrToInt(StartRangeEdit.Text);
    Request.High := StrToInt(EndRangeEdit.Text);
    if Request.Low > Request.High then
    begin
      Temp := Request.Low;
      Request.Low := Request.High;
      Request.High := Temp;
    end;
    if FBuf.AsyncWrite(Request) then
    begin
      Request := nil;
      SubmitBtn.Enabled := false;
      Inc(FItemsInTransit);
    end;
  finally
    if Assigned(Request) then Dispose(Request);
  end;
end;

procedure TBlockAsyncFrm.BufWrite(Sender: TObject);
begin
  { Buffer has indicated that there is space for us to write }
  SubmitBtn.Enabled := true;
end;

procedure TBlockAsyncFrm.BufRead(Sender: TObject);

var
  Reply: TStringList;

begin
  { We have received a notification that we may read. }
  Reply := TStringList(FBuf.AsyncRead);
  if Assigned(Reply) then
  begin
    Dec(FItemsInTransit);
    ResultsMemo.Lines.BeginUpdate;
    ResultsMemo.Lines.AddStrings(Reply);
    while ResultsMemo.Lines.Count > MaxCount do
      ResultsMemo.Lines.Delete(0);
    ResultsMemo.Lines.EndUpdate;
  end;
end;

procedure TBlockAsyncFrm.FormCloseQuery(Sender: TObject;
  var CanClose: Boolean);
begin
  CanClose := true;
  if FItemsInTransit > 0 then
    if MessageDlg('Some requests in transit, close anyway?', mtWarning,
      mbOKCancel, 0) <> mrOK then
      CanClose := false;
end;

procedure TBlockAsyncFrm.FormDestroy(Sender: TObject);
begin
  FWorkerThread.Terminate;
  FBuf.ResetState;
  FWorkerThread.WaitFor;
  FBuf.Free;
  FWorkerThread.Free;
end;

end.