unit singleinstance;

{
    This file is part of the Free Component Library (FCL)
    Copyright (c) 2015 by Ondrej Pokorny

    See the file COPYING.FPC, included in this distribution,
    for details about the copyright.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 **********************************************************************}

{$mode objfpc}
{$H+}

interface

uses
  SysUtils, Classes;

type

  TBaseSingleInstance = class;

  //siServer: No other instance is running. The server is started.
  //siClient: There is another instance running. This instance is used as client.
  //siNotResponding: There is another instance running but it doesn't respond.
  TSingleInstanceStart = (siServer, siClient, siNotResponding);
  TSingleInstanceParamsEvent = procedure(Sender: TBaseSingleInstance; Params: TStringList) of object;
  TBaseSingleInstance = class(TComponent)
  private
    FStartResult: TSingleInstanceStart;
    FTimeOutMessages: Integer;
    FTimeOutWaitForInstances: Integer;
    FOnServerReceivedParams: TSingleInstanceParamsEvent;
  Protected  
    function GetIsClient: Boolean; virtual; abstract;
    function GetIsServer: Boolean; virtual; abstract;
    function GetStartResult: TSingleInstanceStart; virtual;
    procedure DoServerReceivedParams(const aParamsDelimitedText: string);
    Procedure SetStartResult(AValue : TSingleInstanceStart); 
  public
    constructor Create(aOwner: TComponent); override;
    destructor Destroy; override;
  public
    //call Start when you want to start single instance checking
    function Start: TSingleInstanceStart; virtual; abstract;
    //stop single instance server or client
    procedure Stop; virtual; abstract;

    //check and handle pending messages on server
    procedure ServerCheckMessages; virtual; abstract;
    //post cmd parameters from client to server
    procedure ClientPostParams; virtual; abstract;
  public
    property TimeOutMessages: Integer read FTimeOutMessages write FTimeOutMessages;
    property TimeOutWaitForInstances: Integer read FTimeOutWaitForInstances write FTimeOutWaitForInstances;
    property OnServerReceivedParams: TSingleInstanceParamsEvent read FOnServerReceivedParams write FOnServerReceivedParams;
  public
    property StartResult: TSingleInstanceStart read GetStartResult;
    property IsServer: Boolean read GetIsServer;
    property IsClient: Boolean read GetIsClient;
  end;
  TBaseSingleInstanceClass = class of TBaseSingleInstance;

  ESingleInstance = class(Exception);

Var
  DefaultSingleInstanceClass : TBaseSingleInstanceClass = Nil;

implementation

{ TBaseSingleInstance }

constructor TBaseSingleInstance.Create(aOwner: TComponent);
begin
  inherited Create(aOwner);

  FTimeOutMessages := 1000;
  FTimeOutWaitForInstances := 100;
end;

destructor TBaseSingleInstance.Destroy;
begin
  Stop;

  inherited Destroy;
end;

procedure TBaseSingleInstance.DoServerReceivedParams(
  const aParamsDelimitedText: string);
var
  xSL: TStringList;
begin
  if not Assigned(FOnServerReceivedParams) then
    Exit;

  xSL := TStringList.Create;
  try
    xSL.DelimitedText := aParamsDelimitedText;
    FOnServerReceivedParams(Self, xSL);
  finally
    xSL.Free;
  end;
end;

function TBaseSingleInstance.GetStartResult: TSingleInstanceStart;
begin
  Result := FStartResult;
end;

Procedure TBaseSingleInstance.SetStartResult(AValue : TSingleInstanceStart);

begin
  FStartResult:=AValue;
end;   

end.

