{-------------------------------------------------------------------------
 Module:    OSM Tile Manager

 Comment:   Shared helper class that manages OSM tile infrastructure
            (stores, downloader, property setters) for both TGlobe4 and
            TGlobe5.  Eliminates duplicated property-setter code in
            Globe4.pas and Globe5.pas.

 Classes:   TGOSMTileManager
-------------------------------------------------------------------------}
{$IFDEF FPC}{$MODE DELPHI}{$ENDIF}
{$WEAKPACKAGEUNIT ON}
unit uCICOSMTileManager;

interface

uses
  SysUtils, Classes, uCICOSMTileCommon, uCICOSMTileStore, uCICTileDownloader;

type
  TGOSMTileManager = class
  private
    FOSMTileStore    : TGOSMTileCache;
    FLocalTileStore  : TGOSMTileCache;
    FOSMTileDownloader: TGTileFetcher;

    FSurfaceTileDirectory    : string;
    FSurfaceTileMaxZoom      : Integer;
    FSurfaceTileURLTemplate  : string;
    FSurfaceTileUserAgent    : string;
    FSurfaceTileDownloadEnabled: Boolean;
    FSurfaceTileDownloadDir  : string;
    FSurfaceTileLocalEnabled : Boolean;

    FOnChanged: TNotifyEvent;

    procedure SetSurfaceTileDirectory(const Value: string);
    procedure SetSurfaceTileMaxZoom(Value: Integer);
    procedure SetSurfaceTileURLTemplate(const Value: string);
    procedure SetSurfaceTileUserAgent(const Value: string);
    procedure SetSurfaceTileDownloadEnabled(Value: Boolean);
    procedure SetSurfaceTileDownloadDir(const Value: string);
    procedure SetSurfaceTileLocalEnabled(Value: Boolean);
    procedure UpdateDownloadPaths;
    procedure DoChanged;
  public
    constructor Create;
    destructor Destroy; override;

    function HasOSMTiles: Boolean;
    function HasLocalTiles: Boolean;

    // Called by component to forward downloader completion back to DoChanged
    procedure DoTileDownloaded(Sender: TObject);

    property OSMTileStore    : TGOSMTileCache read FOSMTileStore;
    property LocalTileStore  : TGOSMTileCache read FLocalTileStore;
    property OSMTileDownloader: TGTileFetcher read FOSMTileDownloader;

    property OnChanged: TNotifyEvent read FOnChanged write FOnChanged;

    property SurfaceTileDirectory: string
      read FSurfaceTileDirectory write SetSurfaceTileDirectory;
    property SurfaceTileMaxZoom: Integer
      read FSurfaceTileMaxZoom write SetSurfaceTileMaxZoom;
    property SurfaceTileURLTemplate: string
      read FSurfaceTileURLTemplate write SetSurfaceTileURLTemplate;
    property SurfaceTileUserAgent: string
      read FSurfaceTileUserAgent write SetSurfaceTileUserAgent;
    property SurfaceTileDownloadEnabled: Boolean
      read FSurfaceTileDownloadEnabled write SetSurfaceTileDownloadEnabled;
    property SurfaceTileDownloadDir: string
      read FSurfaceTileDownloadDir write SetSurfaceTileDownloadDir;
    property SurfaceTileLocalEnabled: Boolean
      read FSurfaceTileLocalEnabled write SetSurfaceTileLocalEnabled;
  end;

implementation

//==============================================================================
// TGOSMTileManager
//==============================================================================

constructor TGOSMTileManager.Create;
begin
  inherited Create;

  FOSMTileStore     := TGOSMTileCache.Create;
  FLocalTileStore   := TGOSMTileCache.Create;
  FOSMTileDownloader := TGTileFetcher.Create;

  FSurfaceTileMaxZoom      := OSM_DEFAULT_MAX_ZOOM;
  FSurfaceTileLocalEnabled := True;
  FSurfaceTileDownloadEnabled := False;
  FOSMTileDownloader.Enabled := False;

  // Set default URL template on both store and downloader so IsActive returns
  // true for the download store once a download dir is configured.
  FSurfaceTileURLTemplate := 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';
  FOSMTileStore.URLTemplate    := FSurfaceTileURLTemplate;
  FOSMTileDownloader.URLTemplate := FSurfaceTileURLTemplate;
end;

destructor TGOSMTileManager.Destroy;
begin
  FreeAndNil(FOSMTileDownloader);
  FreeAndNil(FLocalTileStore);
  FreeAndNil(FOSMTileStore);
  inherited Destroy;
end;

//------------------------------------------------------------------------------

procedure TGOSMTileManager.DoChanged;
begin
  if Assigned(FOnChanged) then
    FOnChanged(Self);
end;

{$IFDEF FPC}{$PUSH}{$HINTS OFF}{$ENDIF}
procedure TGOSMTileManager.DoTileDownloaded(Sender: TObject);
begin
  DoChanged;
end;
{$IFDEF FPC}{$POP}{$ENDIF}

//------------------------------------------------------------------------------

function TGOSMTileManager.HasOSMTiles: Boolean;
begin
  Result := FSurfaceTileDownloadEnabled and FOSMTileStore.IsActive;
end;

function TGOSMTileManager.HasLocalTiles: Boolean;
begin
  Result := FSurfaceTileLocalEnabled and FLocalTileStore.IsActive;
end;

//------------------------------------------------------------------------------

procedure TGOSMTileManager.SetSurfaceTileDirectory(const Value: string);
begin
  if FSurfaceTileDirectory <> Value then
  begin
    FSurfaceTileDirectory := Value;
    FLocalTileStore.BaseDir := Value;
    FLocalTileStore.FlushCache;
    FOSMTileStore.BaseDir := '';   // download store must not search local dir
    FOSMTileDownloader.ClearPending;
    DoChanged;
  end;
end;

procedure TGOSMTileManager.SetSurfaceTileMaxZoom(Value: Integer);
begin
  if Value < 0  then Value := 0;
  if Value > 19 then Value := 19;
  if FSurfaceTileMaxZoom <> Value then
  begin
    FSurfaceTileMaxZoom := Value;
    FOSMTileStore.MaxZoom := Value;
    FOSMTileStore.FlushCache;
    FLocalTileStore.MaxZoom := Value;
    DoChanged;
  end;
end;

procedure TGOSMTileManager.SetSurfaceTileURLTemplate(const Value: string);
begin
  if FSurfaceTileURLTemplate <> Value then
  begin
    FSurfaceTileURLTemplate := Value;
    FOSMTileStore.URLTemplate     := Value;
    FOSMTileDownloader.URLTemplate := Value;
    FOSMTileDownloader.ClearBlacklist;
    UpdateDownloadPaths;
    DoChanged;
  end;
end;

procedure TGOSMTileManager.SetSurfaceTileUserAgent(const Value: string);
begin
  if FSurfaceTileUserAgent <> Value then
  begin
    FSurfaceTileUserAgent := Value;
    FOSMTileDownloader.UserAgent := Value;
  end;
end;

procedure TGOSMTileManager.SetSurfaceTileDownloadEnabled(Value: Boolean);
begin
  if FSurfaceTileDownloadEnabled <> Value then
  begin
    FSurfaceTileDownloadEnabled := Value;
    FOSMTileDownloader.Enabled := Value;
    if not Value then
      FOSMTileDownloader.ClearPending;
    DoChanged;
  end;
end;

procedure TGOSMTileManager.SetSurfaceTileDownloadDir(const Value: string);
begin
  if FSurfaceTileDownloadDir <> Value then
  begin
    FSurfaceTileDownloadDir := Value;
    UpdateDownloadPaths;
    DoChanged;
  end;
end;

procedure TGOSMTileManager.SetSurfaceTileLocalEnabled(Value: Boolean);
begin
  if FSurfaceTileLocalEnabled <> Value then
  begin
    FSurfaceTileLocalEnabled := Value;
    DoChanged;
  end;
end;

procedure TGOSMTileManager.UpdateDownloadPaths;
var
  EffectiveDir: string;
begin
  if FSurfaceTileDownloadDir <> '' then
  begin
    EffectiveDir := FSurfaceTileDownloadDir + PathDelim +
      URLTemplateToSubDir(FSurfaceTileURLTemplate);
    FOSMTileDownloader.BaseDir  := EffectiveDir;
    FOSMTileStore.DownloadDir   := EffectiveDir;
  end
  else
  begin
    FOSMTileDownloader.BaseDir := '';
    FOSMTileStore.DownloadDir  := '';
  end;
end;

end.
