unit ASFormatters;

{ **************************************************************************** }
{ Rejbrand AlgoSim Kernel number formatters                                    }
{ Copyright © 2017–2025 Andreas Rejbrand                                       }
{ https://english.rejbrand.se/                                                 }
{ **************************************************************************** }

{$WARN SYMBOL_PLATFORM OFF}
{$WARN DUPLICATE_CTOR_DTOR OFF}

interface

uses
  SysUtils, ASObjects, ASNum;

function TryGetFormatter(AStyle: TFormatStyle; out AFormatter: TASRFormatter): Boolean;

implementation

uses
  Windows, Math, StrUtils, DateUtils, ASMidi, RomanNumerals;

var
  Formatters: array[TFormatStyle] of TASRFormatter;

function TryGetFormatter(AStyle: TFormatStyle; out AFormatter: TASRFormatter): Boolean;
begin
  AFormatter := Formatters[AStyle];
  Result := Assigned(AFormatter);
end;

function FormatMonth(const AOptions: TFormatOptions; const Val: TASR): string;
var
  ZBMonthIndex: Integer;
begin
  if IsInteger(Val) then
  begin
    ZBMonthIndex := (Round(Val) - 1) mod 12;
    Result := GetLocaleStr(LOCALE_USER_DEFAULT, LOCALE_SMONTHNAME1 + ZBMonthIndex,
      Round(Val).ToString);
  end
  else
    Result := RealToStr(Val, AOptions)
end;

function FormatDay(const AOptions: TFormatOptions; const Val: TASR): string;
var
  ZBDayIndex: Integer;
begin
  if IsInteger(Val) then
  begin
    ZBDayIndex := (Round(Val) - 1) mod 7;
    Result := GetLocaleStr(LOCALE_USER_DEFAULT, LOCALE_SDAYNAME1 + ZBDayIndex,
      Round(Val).ToString);
  end
  else
    Result := RealToStr(Val, AOptions)
end;

function FormatMIDIInstrument(const AOptions: TFormatOptions; const Val: TASR): string;
begin
  if IsInteger(Val) and InRange(Round(Val), Ord(Low(TMIDIInstrument)), Ord(High(TMIDIInstrument))) then
    Result := MIDI_INSTRUMENT_NAMES[TMIDIInstrument(Round(Val))]
  else
    Result := RealToStr(Val, AOptions)
end;

function FormatRomanNumeral(const AOptions: TFormatOptions; const Val: TASR): string;
begin
  if IsInteger(Val) then
  begin
    if Val >= 0 then
      Result := IntToRoman(Round(Val))
    else
      Result := MINUS_SIGN + IntToRoman(-Round(Val))
  end
  else
    Result := RealToStr(Val, AOptions);
end;

initialization
  Formatters[fsMonth] := FormatMonth;
  Formatters[fsDayOfWeek] := FormatDay;
  Formatters[fsMidiInstrument] := FormatMIDIInstrument;
  Formatters[fsRoman] := FormatRomanNumeral;

end.
