with Asis;
with Asis.Errors;
with Asis.Exceptions;
with Asis.Implementation;
with Asis.Ada_Environments;
with Asis.Compilation_Units;
with Asis.Elements;
with Asis.Iterator;
with Asis.Declarations;
with Asis.Definitions;
with Asis.Expressions;

with Ada.Wide_Text_Io; use Ada.Wide_Text_Io;
with Ada.Text_Io; use Ada.Text_Io;
with Ada.Characters.Handling; use Ada.Characters.Handling;
with Ada.Command_Line; use Ada.Command_Line;
with Gnat.Current_Exception;

procedure Dump_Types is

   type Natural_Record is record

      N : Natural;

   end record;

   type Foo is record

      First : Integer;

      Second : Natural_Record;

      Third : Float;

   end record;

   My_Context                 : Asis.Context;

begin

   Asis.Implementation.Initialize;
   Asis.Ada_Environments.Associate (My_Context, "");
   Asis.Ada_Environments.Open (My_Context);

   Ada.Text_Io.Put_Line ("****************************************************************");
   Ada.Text_Io.Put_Line ("****************************************************************");
   Ada.Text_Io.Put_Line ("****************************************************************");

   declare
      My_Unit_Lists  : Asis.Compilation_Unit_List := Asis.Compilation_Units.Compilation_Unit_Bodies (My_Context);
   begin
      for I in My_Unit_Lists'Range loop
         Ada.Text_Io.Put (Integer'Image (I));
         Ada.Text_Io.Set_Col (8);
         Ada.Wide_Text_Io.Put (Asis.Compilation_Units.Unit_Full_Name (My_Unit_Lists (I)));
         Ada.Text_Io.New_Line;

         declare
            My_Element   : Asis.Element := Asis.Elements.Unit_Declaration (My_Unit_Lists (I));
         begin
            Ada.Text_Io.Put_Line (Asis.Element_Kinds'Image (Asis.Elements.Element_Kind (My_Element)));
            Ada.Text_Io.Put_Line (Asis.Declaration_Kinds'Image (Asis.Elements.Declaration_Kind (My_Element)));
            declare
               My_Declarations : Asis.Declarative_Item_List := Asis.Declarations.Body_Declarative_Items (My_Element);
            begin
               if Asis."=" (My_Declarations, Asis.Nil_Element_List) then
                  Ada.Text_Io.Put_Line ("no visible declarations");
               else
                  Ada.Text_Io.Put_Line ("VISIBLE DECLARATIONS");
                  Ada.Text_Io.Put_Line ("my_declarations'last = " & Integer'Image (My_Declarations'Last));
                  for I in My_Declarations'Range loop
                     declare
                        Decl_Kind : Asis.Declaration_Kinds := Asis.Elements.Declaration_Kind (My_Declarations (I));
                     begin
                        if not Asis."="(Asis.Not_A_Declaration, Decl_Kind) then
                           declare
                              Name_List : Asis.Defining_Name_List := Asis.Declarations.Names (My_Declarations (I));
                              Name_String : String := Ada.Characters.Handling.To_Lower (Ada.Characters.Handling.To_String (Asis.Declarations.Defining_Name_Image (Name_List (1))));
                           begin
                              case Asis.Elements.Declaration_Kind (My_Declarations (I)) is
                                 when Asis.An_Ordinary_Type_Declaration =>
                                    declare
                                       Type_Defn : Asis.Type_Definition := Asis.Declarations.Type_Declaration_View (My_Declarations (I));
                                       Type_Kind : Asis.Type_Kinds := Asis.Elements.Type_Kind (Type_Defn);
                                       begin
                                          Ada.Text_Io.Put_Line ("name_string for element # = " & Integer'Image (I) & " is " & Name_String);
                                          Ada.Text_Io.Put_Line (Asis.Declaration_Kinds'Image (Asis.Elements.Declaration_Kind (My_Declarations (I))));
                                          Ada.Text_Io.Put_Line ("type_defn = " & Asis.Definition_Kinds'Image (Asis.Elements.Definition_Kind (Type_Defn)));
                                          Ada.Text_Io.Put_Line ("type_kind = " & Asis.Type_Kinds'Image (Type_Kind));
                                          case Type_Kind is
                                             when Asis.A_Record_Type_Definition =>
                                                declare
                                                   Record_Definition : Asis.Definition := Asis.Definitions.Record_Definition (Type_Defn);
                                                   Components : Asis.Record_Component_List := Asis.Definitions.Record_Components (Record_Definition);
                                                begin
                                                   Ada.Text_Io.Put_Line ("components'last = " & Integer'Image (Components'Last));
                                                   Ada.Text_Io.Put_Line ("**************** debugging type definition ****************");
                                                     Ada.Text_Io.Put_Line (Ada.Characters.Handling.To_String (Asis.Elements.Debug_Image (Type_Defn)));
                                                   Ada.Text_Io.Put_Line ("**************** debugging record definition ****************");
                                                   Ada.Text_Io.Put_Line (Ada.Characters.Handling.To_String (Asis.Elements.Debug_Image (Record_Definition)));
                                                   for Comps in Components'Range loop
                                                      Ada.Text_Io.Put_Line (Integer'Image (Comps) & " : element_kind : " &
                                                                            Asis.Element_Kinds'Image (Asis.Elements.Element_Kind (Components (Comps))));
                                                      Ada.Text_Io.Put_Line ("**** declaration_kind = " & Asis.Declaration_Kinds'Image (Asis.Elements.Declaration_Kind (Components (Comps))));
                                                      Ada.Text_Io.Put_Line ("**** definition_kind = " & Asis.Definition_Kinds'Image (Asis.Elements.Definition_Kind (Components (Comps))));
                                                      Ada.Text_Io.Put_Line ("**************** debugging component definition ****************");
                                                      Ada.Text_Io.Put_Line (Ada.Characters.Handling.To_String (Asis.Elements.Debug_Image (Components (Comps))));
                                                      case Asis.Elements.Element_Kind (Components (Comps)) is
                                                         when Asis.A_Declaration =>
                                                            declare
                                                               ODV : Asis.Definition := Asis.Declarations.Object_Declaration_View (Components (Comps));
                                                            begin
                                                               Ada.Text_Io.Put_Line ("ODV element_kind : " &
                                                                                     Asis.Element_Kinds'Image (Asis.Elements.Element_Kind (Components (Comps))));
                                                               Ada.Text_Io.Put_Line ("ODV decl_kind = " &
                                                                                     Asis.Declaration_Kinds'Image (Asis.Elements.Declaration_Kind (ODV)));
                                                               Ada.Text_Io.Put_Line ("ODV def_kind = " &
                                                                                     Asis.Definition_Kinds'Image (Asis.Elements.Definition_Kind (ODV)));
                                                               Ada.Text_Io.Put_Line (Ada.Characters.Handling.To_String (Asis.Elements.Debug_Image (Odv)));
                                                               --
                                                               -- this fails, but only because the def_kind of
                                                               -- ODV is NOT_A_DEFINITION...
                                                               --
                                                               declare
                                                                  Subtype_Mark : Asis.Expression := Asis.Definitions.Subtype_Mark (ODV);
                                                               begin
                                                                  Ada.Text_Io.Put_Line ("subtype_mark worked!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                                                                  Ada.Text_Io.Put_Line (Ada.Characters.Handling.To_String (Asis.Elements.Debug_Image (Subtype_Mark)));
                                                               end;
                                                            exception
                                                               when others =>
                                                                  Ada.Text_Io.Put_Line ("subtype_mark declaration failed");
                                                                  Ada.Text_Io.Put_Line (Gnat.Current_Exception.Exception_Information);
                                                            end;
                                                         when others =>
                                                            null;
                                                      end case;
                                                   end loop;
                                                end;
                                             when others =>
                                                null;
                                          end case;
                                       end;
                                 when others =>
                                    null;
                              end case;
                           end;
                        end if;
                     end;
                  end loop;
               end if;
            end;
         end;
      end loop;
   end;

   Asis.Ada_Environments.Close (My_Context);
   Asis.Ada_Environments.Dissociate (My_Context);
   Asis.Implementation.Finalize;

exception
   when others =>
      Ada.Text_Io.Put_Line ("ASIS Application failed");
end Dump_Types;
