-------------------------------------------------------------------------------
-- (C) Altran Praxis Limited
-------------------------------------------------------------------------------
--
-- The SPARK toolset is free software; you can redistribute it and/or modify it
-- under terms of the GNU General Public License as published by the Free
-- Software Foundation; either version 3, or (at your option) any later
-- version. The SPARK toolset is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-- Public License for more details. You should have received a copy of the GNU
-- General Public License distributed with the SPARK toolset; see file
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
-- the license.
--
--=============================================================================

with SPARK_Ada_Integer_Text_IO;

package body Sparklalr_Common is

   procedure Put_File_Output (Std_Out : in     Boolean;
                              File    : in out SPARK.Ada.Text_IO.File_Type;
                              Item    : in     String) is
   begin
      if Std_Out then
         SPARK.Ada.Text_IO.Put_Output (Item => Item);
      else
         SPARK.Ada.Text_IO.Put_File (File => File,
                                     Item => Item);
      end if;
   end Put_File_Output;

   procedure Put_Character_File_Output (Std_Out : in     Boolean;
                                        File    : in out SPARK.Ada.Text_IO.File_Type;
                                        Item    : in     Character) is
   begin
      if Std_Out then
         SPARK.Ada.Text_IO.Put_Character_Output (Item => Item);
      else
         SPARK.Ada.Text_IO.Put_Character_File (File => File,
                                               Item => Item);
      end if;
   end Put_Character_File_Output;

   procedure Put_Line_File_Output (Std_Out : in     Boolean;
                                   File    : in out SPARK.Ada.Text_IO.File_Type;
                                   Item    : in     String) is
   begin
      if Std_Out then
         SPARK.Ada.Text_IO.Put_Line_Output (Item => Item);
      else
         SPARK.Ada.Text_IO.Put_Line_File (File => File,
                                          Item => Item);
      end if;
   end Put_Line_File_Output;

   procedure Put_Integer_File_Output
     (Std_Out : in     Boolean;
      File    : in out SPARK.Ada.Text_IO.File_Type;
      Item    : in     Integer;
      Width   : in     SPARK.Ada.Text_IO.Field)
   is
   begin
      if Std_Out then
         SPARK_Ada_Integer_Text_IO.Put_Output (Item  => Item,
                                               Width => Width,
                                               Base  => 10);
      else
         SPARK_Ada_Integer_Text_IO.Put_File (File  => File,
                                             Item  => Item,
                                             Width => Width,
                                             Base  => 10);
      end if;
   end Put_Integer_File_Output;

   procedure New_Line_File_Output (Std_Out : in     Boolean;
                                   File    : in out SPARK.Ada.Text_IO.File_Type) is
   begin
      if Std_Out then
         SPARK.Ada.Text_IO.New_Line_Output (Spacing => 1);
      else
         SPARK.Ada.Text_IO.New_Line_File (File    => File,
                                          Spacing => 1);
      end if;
   end New_Line_File_Output;

   procedure Put_N_Chars
     (Std_Out : in     Boolean;
      F       : in out SPARK.Ada.Text_IO.File_Type;
      C       : in     Character;
      N       : in     Natural)
   is
   begin
      for I in Integer range 1 .. N loop
         Put_Character_File_Output (Std_Out => Std_Out,
                                    File    => F,
                                    Item    => C);
      end loop;
   end Put_N_Chars;

   procedure Print
     (Std_Out : in     Boolean;
      F       : in out SPARK.Ada.Text_IO.File_Type;
      String1 : in     String;
      Posn    : in out Integer;
      Tab     : in     Integer;
      Comm    : in     Boolean)
   is
      I : Integer;
   begin
      I := String1'Length;
      while String1 (I) = ' ' loop
         I := I - 1;
      end loop;
      if (Posn + I) > (Page_Width - 2) then
         New_Line_File_Output (Std_Out => Std_Out,
                               File    => F);
         if Comm then
            Put_File_Output (Std_Out => Std_Out,
                             File    => F,
                             Item    => "--");
            Put_N_Chars (Std_Out => Std_Out,
                         F       => F,
                         C       => ' ',
                         N       => Tab - 2);
         else
            Put_N_Chars (Std_Out => Std_Out,
                         F       => F,
                         C       => ' ',
                         N       => Tab);
         end if;
         Posn := I + Tab;
      else
         Posn := Posn + I;
      end if;
      for J in Integer range 1 .. I loop
         Put_Character_File_Output (Std_Out => Std_Out,
                                    File    => F,
                                    Item    => String1 (J));
      end loop;
   end Print;

   procedure Print2
     (F       : in out SPARK.Ada.Text_IO.File_Type;
      String1 : in     String;
      String2 : in     String;
      Posn    : in out Integer;
      Tab     : in     Integer;
      Comm    : in     Boolean)
   is
      I, J : Integer;
   begin
      I := String1'Length;
      while String1 (I) = ' ' loop
         I := I - 1;
      end loop;
      J := String2'Length;
      while String2 (J) = ' ' loop
         J := J - 1;
      end loop;
      if ((Posn + I) + J) > (Page_Width - 2) then
         SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                          Spacing => 1);
         if Comm then
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => "--");
            Put_N_Chars (Std_Out => False,
                         F       => F,
                         C       => ' ',
                         N       => Tab - 2);
         else
            Put_N_Chars (Std_Out => False,
                         F       => F,
                         C       => ' ',
                         N       => Tab);
         end if;
         Posn := (I + J) + Tab;
      else
         Posn := (Posn + I) + J;
      end if;
      for K in Integer range 1 .. I loop
         SPARK.Ada.Text_IO.Put_Character_File (File => F,
                                               Item => String1 (K));
      end loop;
      for K in Integer range 1 .. J loop
         SPARK.Ada.Text_IO.Put_Character_File (File => F,
                                               Item => String2 (K));
      end loop;
   end Print2;

   function Code (Sr : in Action_Type;
                  C  : in Integer) return Integer
   -- ENCODES PARSING ACTION INTO INTEGER REPRESENTATION
   is
      Result_Code : Integer;
   begin
      if Sr = Reduce then
         Result_Code := C;
      else
         if Sr = Shift then
            Result_Code := Prod_Lim + C;
         else
            Result_Code := 0;
         end if;
      end if;
      return Result_Code;
   end Code;

   function Decode (C : in Integer) return Integer is
      Result_Decode : Integer;
   begin
      if C > Prod_Lim then
         Result_Decode := C - Prod_Lim;
      else
         Result_Decode := C;
      end if;
      return Result_Decode;
   end Decode;

end Sparklalr_Common;
