unit uMapFilters;

interface

uses
  System.SysUtils, System.StrUtils,
  JS, Web,
  VCL.TMSFNCLeaflet, VCL.TMSFNCMaps, VCL.TMSFNCMapsCommonTypes;

type
  TMapFilters = class
  private
    FMap: TTMSFNCLeaflet;
    FShowUnits: Boolean;
    FShowComplaints: Boolean;
    FShowLocation: Boolean;


    function GetCheckBoxChecked(const elementId: string; defaultValue: Boolean): Boolean;
    procedure SetCheckBoxChecked(const elementId: string; checked: Boolean);
    procedure SetText(const elementId: string; const value: string);

    procedure ReadUi;
    procedure ResetUi;
    procedure UpdateSummary;
    procedure ApplyToMap;

    procedure HandleDocClick(e: TJSMouseEvent);
    procedure HandleDocChange(e: TJSEvent);
  public
    constructor Create(AMap: TTMSFNCLeaflet);
    procedure Init;
    procedure Apply;
    procedure Reset;
  end;

implementation

{ TMapFilters }

constructor TMapFilters.Create(AMap: TTMSFNCLeaflet);
begin
  inherited Create;
  FMap := AMap;

  FShowUnits := True;
  FShowComplaints := True;
  FShowLocation := False;
end;

procedure TMapFilters.Init;
begin
  Document.addEventListener('click', @HandleDocClick);
  Document.addEventListener('change', @HandleDocChange);

  ResetUi;
  ReadUi;
  UpdateSummary;
  ApplyToMap;
end;

procedure TMapFilters.Apply;
begin
  ReadUi;
  UpdateSummary;
  ApplyToMap;
end;

procedure TMapFilters.Reset;
begin
  ResetUi;
  ReadUi;
  UpdateSummary;
  ApplyToMap;
end;

procedure TMapFilters.HandleDocClick(e: TJSMouseEvent);
var
  el: TJSElement;
  id: string;
begin
  el := TJSElement(e.target);
  if el = nil then
    Exit;

  // Note: This supports clicking inner icons/spans by walking up to a parent with an id
  asm
    while (el && !el.id) { el = el.parentElement; }
  end;


  if (el <> nil) and (el is TJSHtmlElement) then
  begin
    id := string(TJSHtmlElement(el).id);

    if id = 'map_filters_apply' then
    begin
      e.preventDefault;
      e.stopPropagation;
      Apply;
      Exit;
    end;

    if id = 'map_filters_reset' then
    begin
      e.preventDefault;
      e.stopPropagation;
      Reset;
      Exit;
    end;
  end;
end;

procedure TMapFilters.HandleDocChange(e: TJSEvent);
begin
  //Note: Summary text changes when toggles change
  ReadUi;
  UpdateSummary;
end;

procedure TMapFilters.ReadUi;
begin
  FShowUnits := GetCheckBoxChecked('map_filter_units', True);
  FShowComplaints := GetCheckBoxChecked('map_filter_complaints', True);
  FShowLocation := GetCheckBoxChecked('map_filter_location', False);
end;

procedure TMapFilters.ResetUi;
begin
  SetCheckBoxChecked('map_filter_units', True);
  SetCheckBoxChecked('map_filter_complaints', True);
  SetCheckBoxChecked('map_filter_location', False);
end;

procedure TMapFilters.UpdateSummary;
var
  summaryText: string;
begin
  summaryText := '';

  if FShowUnits then
    summaryText := 'Units';

  if FShowComplaints then
  begin
    if summaryText <> '' then
      summaryText := summaryText + ', ';
    summaryText := summaryText + 'Complaints';
  end;

  if FShowLocation then
  begin
    if summaryText <> '' then
      summaryText := summaryText + ', ';
    summaryText := summaryText + 'Location';
  end;

  if summaryText = '' then
    summaryText := 'None';

  SetText('map_filters_summary', summaryText);
end;

procedure TMapFilters.ApplyToMap;
var
  i: Integer;
  m: TTMSFNCMapsMarker;
  ds: string;
  showMarker: Boolean;
begin
  if FMap = nil then
    Exit;

  FMap.BeginUpdate;
  try
    for i := 0 to FMap.Markers.Count - 1 do
    begin
      m := FMap.Markers[i];
      ds := Trim(string(m.DataString));

      // Note: Map form sets:
      // - units: m.DataString := 'unit'
      // - complaints: m.DataString := 'complaint'
      showMarker := True;

      if SameText(ds, 'unit') then
        showMarker := FShowUnits
      else if StartsText('complaint', LowerCase(ds)) then
        showMarker := FShowComplaints
      else if SameText(ds, 'device') then
        showMarker := FShowLocation;

      // Note: TTMSFNCMapsMarker supports visibility toggling
      m.Visible := showMarker;
    end;
  finally
    FMap.EndUpdate;
  end;
end;

function TMapFilters.GetCheckBoxChecked(const elementId: string; defaultValue: Boolean): Boolean;
var
  el: TJSElement;
begin
  Result := defaultValue;

  el := Document.getElementById(elementId);
  if (el <> nil) and (el is TJSHtmlInputElement) then
    Result := TJSHtmlInputElement(el).checked;
end;

procedure TMapFilters.SetCheckBoxChecked(const elementId: string; checked: Boolean);
var
  el: TJSElement;
begin
  el := Document.getElementById(elementId);
  if (el <> nil) and (el is TJSHtmlInputElement) then
    TJSHtmlInputElement(el).checked := checked;
end;

procedure TMapFilters.SetText(const elementId: string; const value: string);
var
  el: TJSElement;
begin
  el := Document.getElementById(elementId);
  if (el <> nil) and (el is TJSHtmlElement) then
    TJSHtmlElement(el).innerText := value;
end;

end.

