with Ada.Command_Line, Strings, Globals;
use Globals;

pragma Elaborate_All (Ada.Command_Line,Strings,Globals);

package body Ints is

  function IMin(I1,I2,I3: Integer) return Integer is
  begin
    return IMin(IMin(I1,I2),I3);
  end IMin;

  function IMax(I1,I2,I3: Integer) return Integer is
  begin
    return IMax(IMin(I1,I2),I3);
  end IMax;

  function Sign(I: in Integer) return Integer is
  begin
    if I>0 then return 1; end if;
    if I<0 then return -1; end if;
    return 0;
  end Sign;

  function Choose(ChooseN0: Boolean; N0,N1: Integer) return Integer is
  begin
    if ChooseN0 then return N0; else return N1; end if;
  end Choose;

  function IntVal(B: Boolean) return Integer is
  begin
    if B then return 1; else return 0; end if;
  end IntVal;

  function Binomial(N,M: Positive) return Positive is
    K: constant Positive := IMax(M,N-M);
    B: Positive := 1;
  begin
    for J in 1 .. N-K loop
      B := (B*(K+J))/J;
    end loop;
    return B;
  end Binomial;

  function Convert(I: Integer) return Integer is
  begin
    return I;
  end Convert;

  function Sqr(I: Integer) return Integer is
  begin
    return I*I;
  end Sqr;

  function ISqrt(N: Positive) return Natural is
    --- integer part of Sqrt(N)
    MaxIter: constant Positive := 256;
    X: Integer := (N+1)/2;
    Y,Z: Integer;
  begin
    for I in 1 .. MaxIter loop
      Y := (X+N/X)/2;
      Z := (Y+N/Y)/2;
      if Z=X then return IMin(X,Y); end if;
      X := Z;
    end loop;
    raise Constraint_Error;
    return 0;
  end ISqrt;

  function GCD(N,D: Integer) return Integer is
    AN: Integer := abs(N);
    AD: Integer := abs(D);
    Tmp: Integer;
  begin
    while (AN /= 0) loop
      Tmp  := AN;
      AN := AD mod Tmp;
      AD := Tmp;
    end loop;
    if AD=0 then raise Constraint_Error; end if;
    return AD;
  end GCD;

  function LCM(M,N: Positive) return Integer is
  begin
    return M*(N/GCD(M,N));
  end LCM;

  ---------------------------------------------

  procedure Put(P: in File_Access; I: in Integer; Width: in Field := Int_IO.Default_Width) is
  begin
    if P=null then
      Int_IO.Put(I,Width);
    else
      Int_IO.Put(P.all,I,Width);
    end if;
  end Put;

  procedure Put(F: in File_Type; I: in Integer; Dummy: in Boolean := False) is
    use Strings;
    pragma Unreferenced(Dummy);
  begin
    Int_IO.Put(F,I,Width(I)+1);
    New_Line(F);
  end Put;

  procedure Get(F: in File_Type; I: in out Integer; Dummy: in Boolean := False) is
    pragma Unreferenced(Dummy);
  begin
    Int_IO.Get(F,I);
  end Get;

  function Read(FileName: in String) return Integer is
    I: Integer;
    F: File_Type;
  begin
    Open(F,In_File,FileName);
    Int_IO.Get(F,I);
    Close(F);
    return I;
  end Read;

  function Prompt(N: String) return Integer is
    I: Integer;
  begin
    Put(N);
    Int_IO.Get(I);
    return I;
  end Prompt;

  procedure Show1(N: in String; I: in Integer; NewLine: in Boolean := True) is
    use Strings;
    P: constant File_Access := Default_Output.all;
  begin
    Put(P,N);
    Put(P,I,Width(I)+1);
    if NewLine then New_Line(P); end if;
  end Show1;

  procedure Show2(N: in String; I1,I2: in Integer; NewLine: in Boolean := True) is
    use Strings;
    P: constant File_Access := Default_Output.all;
  begin
    Put(P,N);
    Put(P,I1,Width(I1)+1);
    Put(P,I2,Width(I2)+5);
    if NewLine then New_Line(P); end if;
  end Show2;

  function GetArg return Integer is
    use Ada.Command_Line;
    M,L: Integer;
  begin
    Int_IO.Get(Argument(ArgIndex),M,L);
    ArgIndex := ArgIndex+1;
    return M;
  end GetArg;

  function Put_Value(Ptr: Integer_Access; Val: Integer) return Boolean is
  begin
    if Ptr=null then return False; end if;
    Ptr.all := Val;
    return True;
  end Put_Value;

end Ints;
