unit uNameNumbers;

interface

function NameInteger(AValue: Integer): string;
function NameCurrency(AValue: Currency): string;

implementation

uses SysUtils;

type
  TclNumbers = array[0..9] of string;
  TclMagnitudes = array[0..4] of string;

const
  UNITS: TclNumbers =
    ((''),
     ('um'),
     ('dois'),
     ('três'),
     ('quatro'),
     ('cinco'),
     ('seis'),
     ('sete'),
     ('oito'),
     ('nove'));

  TEENS: TclNumbers =
    (('dez'),
     ('onze'),
     ('doze'),
     ('treze'),
     ('catorze'),
     ('quinze'),
     ('dezesseis'),
     ('dezessete'),
     ('dezoito'),
     ('dezenove'));

  TENS: TclNumbers =
    ((''),
     ('dez'),
     ('vinte'),
     ('trinta'),
     ('quarenta'),
     ('cinquenta'),
     ('sessenta'),
     ('setenta'),
     ('oitenta'),
     ('noventa'));

  HUNDREDS: TclNumbers =
    ((''),
     ('cento'),
     ('duzentos'),
     ('trezentos'),
     ('quatrocentos'),
     ('quinhentos'),
     ('seiscentos'),
     ('setecentos'),
     ('oitocentos'),
     ('novecentos'));

  MAGNITUDE_SG: TclMagnitudes =
    ((' '),
     (' mil'),
     (' milhão'),
     (' bilhão'),
     (' trilhão'));

  MAGNITUDE_PL: TclMagnitudes =
    ((' '),
     (' mil'),
     (' milhões'),
     (' bilhões'),
     (' trilhões'));

function HundredToString(Value: Integer): string;
begin
  Result := '';
  if (Value < 0) or (Value > 999) then Exit;
{ 100 }
  if (Value = 100) then
  begin
    Result := 'cem';
    Exit;
  end;
  Result := HUNDREDS[Value div 100];
  Value := Value mod 100;
  if (Value > 0) and
     (Result <> '') then
    Result := Result + ' e ';

{ X10..X19 }
  if (Value >= 10) and (Value < 20) then
  begin
    Result := Result +
              TEENS[Value mod 10];
    Exit;
  end
  else
{ X20..X99 e X00..X09 }
  begin
    Result := Result +
              TENS[Value div 10];
    if ((Value div 10) > 0) and
       ((Value mod 10) > 0) then
      Result := Result + ' e ';
    Result := Result + UNITS[Value mod 10];
  end;
end;

function NameInteger(AValue: Integer): string;

  function GetSuffix(Order, Number: Integer): string;
  begin
    if (Number = 1) then
      Result := MAGNITUDE_SG[Order]
    else
      Result := MAGNITUDE_PL[Order];
  end;

var
  iGroup,
  iValue,
  iNumber,
  iLastGroup: Integer;
begin
  iGroup := 0;
  Result := '';
  iValue := AValue;
  iLastGroup := 0;
  while (iValue > 0) do
    if ((iValue mod 1000) = 0) then
    begin
      inc(iLastGroup);
      iValue := iValue div 1000;
    end
    else
      Break;
  while (AValue > 0) do
  begin
    iNumber := AValue mod 1000;
    AValue := AValue div 1000;
    Result := HundredToString(iNumber) +
              GetSuffix(iGroup, iNumber) +
              Result;
    if (AValue > 0) and
       (iGroup = iLastGroup) and
       ((iNumber mod 100 = 0) or
         ((iNumber > 0) and (iNumber <= 99))) then
      Result := ' e ' + Result
    else
      Result := ' ' + Result;
    inc(iGroup);
  end;
  if (Result = '') then
    Result := 'zero'
  else
    Result := Trim(Result);
end;

{$U+}
// sem a diretiva acima, erros para centavos ocorriam
// esporadicamente
function NameCurrency(AValue: Currency): string;
var
  i, c: Integer;
  si, sc: string;
begin
  i := Trunc(AValue);
  c := Round(Frac(AValue)*100);
  if (i > 0) then
  begin
    si := NameInteger(i);
    if i = 1 then
      si := si + ' real'
    else
      si := si + ' reais';
  end;
  if (c > 0) then
  begin
    sc := NameInteger(c);
    if c = 1 then
      sc := sc + ' centavo'
    else
      sc := sc + ' centavos';
  end;
  if (si <> '') and (sc <> '') then
    Result := si + ' e ' + sc
  else
    Result := si + sc;
end;
{$U-}

end.