unit Bcl.Collections.Common;

{$I bcl.inc}

interface

uses
  Types,
  {$IFDEF ISDELPHI}
  Generics.Collections,
  {$ELSE}
  Bcl.Json.Common,
  JS,
  {$ENDIF}
  SysUtils;

type
  TStringMap = class
  private
    {$IFDEF PAS2JS}
    FMap: TJObject;
    {$ELSE}
    FDictionary: TObjectDictionary<string, TObject>;
    {$ENDIF}
    function GetItem(const Key: string): TObject;
    function GetKeys: TStringDynArray;
  public
    constructor Create(AOwnsObjects: Boolean = False); reintroduce;
    destructor Destroy; override;
    procedure Clear;
    procedure Add(const Key: string; const Value: TObject);
    procedure AddOrSetValue(const Key: string; const Value: TObject);
    function ContainsKey(const Key: string): Boolean;
    procedure Remove(const Key: string);
    property Items[const Key: string]: TObject read GetItem; default;
    property Keys: TStringDynArray read GetKeys;
  end;

implementation

{ TStringMap }

procedure TStringMap.Add(const Key: string; const Value: TObject);
begin
  {$IFDEF PAS2JS}
  FMap[Key] := Value;
  {$ELSE}
  FDictionary.Add(Key, Value);
  {$ENDIF}
end;

procedure TStringMap.AddOrSetValue(const Key: string; const Value: TObject);
begin
  {$IFDEF PAS2JS}
  FMap[Key] := Value;
  {$ELSE}
  FDictionary.AddOrSetValue(Key, Value);
  {$ENDIF}
end;

procedure TStringMap.Clear;
{$IFDEF PAS2JS}
var
  I: Integer;
begin
  for I := Length(Keys) - 1 downto 0 do
    Remove(Keys[I]);
end;
{$ELSE}
begin
  FDictionary.Clear;
end;
{$ENDIF}

function TStringMap.ContainsKey(const Key: string): Boolean;
begin
  {$IFDEF PAS2JS}
  Result := FMap.hasOwnProperty(Key);
  {$ELSE}
  Result := FDictionary.ContainsKey(Key);
  {$ENDIF}
end;

constructor TStringMap.Create(AOwnsObjects: Boolean);
{$IFDEF PAS2JS}
begin
  FMap := TJSObject.new;
end;
{$ELSE}
var
  Ownership: TDictionaryOwnerships;
begin
  Ownership := [];
  if AOwnsObjects then
    Ownership := [doOwnsValues];
  FDictionary := TObjectDictionary<string, TObject>.Create(Ownership);
end;
{$ENDIF}

destructor TStringMap.Destroy;
begin
  {$IFDEF PAS2JS}
  {$ELSE}
  FDictionary.Free;
  {$ENDIF}
  inherited;
end;

function TStringMap.GetItem(const Key: string): TObject;
begin
  {$IFDEF PAS2JS}
  Result := TObject(FMap[Key]);
  {$ELSE}
  Result := FDictionary[Key];
  {$ENDIF}
end;

function TStringMap.GetKeys: TStringDynArray;
{$IFDEF PAS2JS}
begin
  Result := TJSObject.Keys(FMap);
end;
{$ELSE}
var
  Key: string;
  I: Integer;
begin
  SetLength(Result, FDictionary.Keys.Count);
  I := 0;
  for Key in FDictionary.Keys do
  begin
    Result[I] := Key;
    Inc(I);
  end;
end;
{$ENDIF}

procedure TStringMap.Remove(const Key: string);
begin
  {$IFDEF PAS2JS}
  asm delete this.FMap[Key]; end;
  {$ELSE}
  FDictionary.Remove(Key);
  {$ENDIF}
end;

end.
