------------------------------------------------------------------------------
--                                                                          --
--                            GNATPP COMPONENTS                             --
--                                                                          --
--                         G N A T P P . S T A T E                          --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--                    Copyright (C) 2001-2009, AdaCore                      --
--                                                                          --
-- GNATPP is free software; you can redistribute it  and/or modify it under --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 2,  or (at your option) any later ver- --
-- sion.  GNATPP is  distributed in the  hope that it will  be  useful, but --
-- WITHOUT ANY WARRANTY; without even the implied warranty of  MERCHANTABI- --
-- LITY 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 GNAT; see file COPYING. If not, --
-- write to the Free Software Foundation,  51 Franklin Street, Fifth Floor, --
-- Boston, MA 02110-1301, USA.                                              --
--                                                                          --
-- GNATPP is maintained by AdaCore (http://www.adacore.com)                 --
--                                                                          --
------------------------------------------------------------------------------

with Asis.Clauses;         use Asis.Clauses;

with ASIS_UL.Misc;         use ASIS_UL.Misc;
with ASIS_UL.Output;       use ASIS_UL.Output;
with ASIS_UL.Source_Table; use ASIS_UL.Source_Table;

with GNATPP.Options;       use GNATPP.Options;
with GNATPP.Layout;        use GNATPP.Layout;
with GNATPP.Source_Line_Buffer;

package body GNATPP.State is

   Max_Logical_Depth : Natural := 1;
   Physical_Depth    : Natural := 0;

   Min_Space_In_Out_Line : constant Positive := 32;
   --  Minimal number of the position left in the output line after setting the
   --  indentation level.

   --------------------------
   -- Decrease_Indentation --
   --------------------------

   procedure Decrease_Indentation is
   begin
      Physical_Depth := Physical_Depth - 1;

      if Physical_Depth > Max_Logical_Depth then
         SLOC_Warning
           (Message => "too big nesting level - can not reformat correctly",
            SLOC    => Get_Current_SLOC);
         --  ???  better diagnosis needed!
      else
         Logical_Depth := Physical_Depth;
      end if;

   end Decrease_Indentation;

   ----------------------
   -- Get_Current_SLOC --
   ----------------------

   function Get_Current_SLOC return String is
   begin
      return Short_Source_Name (Get_Current_SF) & ':' &
             Image (Current_Line) & ':' &
             Image (GNATPP.Source_Line_Buffer.Line_Pos);
   end Get_Current_SLOC;

   -----------------------
   -- Get_Current_State --
   -----------------------

   procedure Get_Current_State is
   begin
      Current_State      := Traversal_Stack.Top;
   end Get_Current_State;

   --------------------------
   -- Increase_Indentation --
   --------------------------

   procedure Increase_Indentation is
   begin
      Physical_Depth := Physical_Depth + 1;

      if Physical_Depth = Max_Logical_Depth then
         Error ("nesting level again allows proper reformatting");
         --  ???  better diagnosis needed!
         --  ??? Error or Warning?
      elsif Physical_Depth < Max_Logical_Depth then
         Logical_Depth := Physical_Depth;
      end if;

   end Increase_Indentation;

   ----------------
   -- Initialize --
   ----------------

   procedure Initialize is
   begin
      Before_CU                    := False;
      In_Context_Clause            := False;
      In_Unit                      := False;
      Behind_Unit                  := False;
      Prev_Element_Kind            := Not_An_Element;
      Prev_Element                 := Nil_Element;
      Last_KW                      := Not_A_KW;
      Last_Dlm                     := Not_A_Dlm;
      Unary_Adding_Op_Just_Printed := False;
      Saved_Last_KW                := Not_A_KW;
      Saved_Last_Dlm               := Not_A_Dlm;
      Is_First_Parameter_Spec      := False;
      Par_Specs_On_Separate_Lines  := False;
      The_Very_First_Line          := True;
      Current_Out_Line             := 1;
      Last_If_Path_Start           := 0;
      Last_Loop_Start              := 0;
      Last_Type_Start              := 0;
      Logical_Depth                := 0;
      Out_File_Exists              := False;

      Physical_Depth               := 0;
   end Initialize;

   -----------------------
   -- Set_Current_State --
   -----------------------

   procedure Set_Current_State (The_Element : Asis.Element) is
   begin
      Current_State.The_Element := The_Element;
      Current_State.The_Span    := Element_Span (The_Element);

      Current_State.Layout      := Nil_Layout_Info;
   end Set_Current_State;

   ---------------------------
   -- Set_Max_Nesting_Level --
   ---------------------------

   procedure Set_Max_Nesting_Level is
   begin
      Max_Logical_Depth := 1;

      while Max_Line_Length - Max_Logical_Depth * PP_Indentation >=
            Min_Space_In_Out_Line
      loop
         Max_Logical_Depth := Max_Logical_Depth + 1;
      end loop;

      Max_Logical_Depth :=  Max_Logical_Depth - 1;

   end Set_Max_Nesting_Level;

   ----------------------
   -- Set_Prev_Element --
   ----------------------

   procedure Set_Prev_Element (The_Element : Asis.Element) is
   begin

      case Flat_Element_Kind (The_Element) is
         when A_With_Clause =>

            declare
               Unit_Names : constant Asis.Element_List :=
                 Clause_Names (The_Element);
            begin

               if Unit_Names'Length > 1 then
                  Prev_Element := Nil_Element;
               else
                  Prev_Element := Unit_Names (Unit_Names'First);
               end if;

            end;

         when others =>
            Prev_Element := Nil_Element;
      end case;

   end Set_Prev_Element;

end GNATPP.State;
