File : src/aws-containers-tables.adb


------------------------------------------------------------------------------
--                              Ada Web Server                              --
--                                                                          --
--                         Copyright (C) 2000-2003                          --
--                                ACT-Europe                                --
--                                                                          --
--  Authors: Dmitriy Anisimkov - Pascal Obry                                --
--                                                                          --
--  This library is free software; you can redistribute it and/or modify    --
--  it under the terms of the GNU General Public License as published by    --
--  the Free Software Foundation; either version 2 of the License, or (at   --
--  your option) any later version.                                         --
--                                                                          --
--  This library 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       --
--  along with this library; if not, write to the Free Software Foundation, --
--  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.          --
--                                                                          --
--  As a special exception, if other files instantiate generics from this   --
--  unit, or you link this unit with other files to produce an executable,  --
--  this  unit  does not  by itself cause  the resulting executable to be   --
--  covered by the GNU General Public License. This exception does not      --
--  however invalidate any other reasons why the executable file  might be  --
--  covered by the  GNU Public License.                                     --
------------------------------------------------------------------------------

--  $Id: aws-containers-tables.adb,v 1.16 2003/10/18 12:48:46 obry Exp $

--  Parameters name/value are put into the GNAT.Dynamic_Tables.Table_Type
--  (Data field). The name as a key and the numeric index as a value is
--  placing to the AVL Tree for the fast find all Name/Value pairs with the
--  same name. Each value of the AVL Tree is a table of numeric indexes
--  in the Data field. The parameters must be accessible
--  through their string index by name and also using an numeric index in
--  the place order. So given a set of parameters (K1=V1, K2=V2...),
--  one must be able to ask for the value for K1 but also the name of the
--  second key or the value of the third key.
--
--  Each K/V pair is then inserted into the Data table for access by numeric
--  index. And its numeric index is placing to the AVL tree indexed by name.
--  The AVL Tree values is a tables of numeric indexes in the Data table.

with Ada.Characters.Handling;

package body AWS.Containers.Tables is

   use Ada.Strings.Unbounded;

   procedure Get_Indexes
     (Table   : in     Table_Type;
      Name    : in     String;
      Indexes :    out Name_Index_Table;
      Found   :    out Boolean);
   pragma Inline (Get_Indexes);
   --  Returns all Name/Value indexes for the specified name.
   --  Found is set to False if Name was not found in Table and True otherwise.

   -----------
   -- Count --
   -----------

   function Count (Table : in Table_Type) return Natural is
   begin
      pragma Assert (Table.Index /= null);
      return Data_Table.Last (Table.Data);
   end Count;

   -----------
   -- Count --
   -----------

   function Count
     (Table : in Table_Type;
      Name  : in String)
      return Natural
   is
      Value : Name_Index_Table;
      Found : Boolean;
   begin
      pragma Assert (Table.Index /= null);

      Get_Indexes (Table, Name, Value, Found);

      if Found then
         return Natural (Name_Indexes.Last (Value));
      else
         return 0;
      end if;
   end Count;

   -----------
   -- Exist --
   -----------

   function Exist
     (Table : in Table_Type;
      Name  : in String)
      return Boolean is
   begin
      pragma Assert (Table.Index /= null);

      return Is_Present
        (Table.Index.all,
         Normalize_Name (Name, not Table.Case_Sensitive));
   end Exist;

   ---------
   -- Get --
   ---------

   function Get
     (Table : in Table_Type;
      Name  : in String;
      N     : in Positive := 1)
      return String
   is
      Value : Name_Index_Table;
      Found : Boolean;

   begin
      pragma Assert (Table.Index /= null);

      Get_Indexes (Table, Name, Value, Found);

      if Found and then Key_Positive (N) <= Name_Indexes.Last (Value) then
         return Table.Data.Table (Value.Table (Key_Positive (N))).Value;
      else
         return "";
      end if;
   end Get;

   function Get
     (Table : in Table_Type;
      N     : in Positive)
      return Element is
   begin
      pragma Assert (Table.Index /= null);

      if N <= Data_Table.Last (Table.Data) then
         return Table.Data.Table (N).all;
      else
         return Null_Element;
      end if;
   end Get;

   -----------------
   -- Get_Indexes --
   -----------------

   procedure Get_Indexes
     (Table   : in     Table_Type;
      Name    : in     String;
      Indexes :    out Name_Index_Table;
      Found   :    out Boolean) is
   begin
      Index_Table.Get_Value
        (Table => Index_Table.Table_Type (Table.Index.all),
         Key   => Normalize_Name (Name, not Table.Case_Sensitive),
         Value => Indexes,
         Found => Found);
   end Get_Indexes;

   --------------
   -- Get_Name --
   --------------

   function Get_Name
     (Table : in Table_Type;
      N     : in Positive := 1)
      return String is
   begin
      pragma Assert (Table.Index /= null);

      if N <= Data_Table.Last (Table.Data) then
         return Table.Data.Table (N).Name;
      else
         return "";
      end if;
   end Get_Name;

   ---------------
   -- Get_Names --
   ---------------

   function Get_Names
     (Table : in Table_Type;
      Sort  : in Boolean := False)
      return VString_Array
   is

      procedure Process
        (Key      : in     String;
         Value    : in     Name_Index_Table;
         Order    : in     Positive;
         Continue : in out Boolean);

      Result : VString_Array (1 .. Name_Count (Table));

      -------------
      -- Process --
      -------------

      procedure Process
        (Key      : in     String;
         Value    : in     Name_Index_Table;
         Order    : in     Positive;
         Continue : in out Boolean)
      is
         pragma Unreferenced (Value);
         pragma Unreferenced (Continue);
      begin
         Result (Order) := To_Unbounded_String (Key);
      end Process;

      -----------------------
      -- Disorder_Traverse --
      -----------------------

      procedure Disorder_Traverse is
         new Index_Table.Disorder_Traverse_G (Process);

      ------------------
      -- Traverse_Asc --
      ------------------

      procedure Traverse_Asc is
         new Index_Table.Traverse_Asc_G (Process);

   begin
      if Table.Index /= null then
         if Sort then
            Traverse_Asc (Index_Table.Table_Type (Table.Index.all));
         else
            Disorder_Traverse (Index_Table.Table_Type (Table.Index.all));
         end if;
      end if;

      return Result;
   end Get_Names;

   ---------------
   -- Get_Value --
   ---------------

   function Get_Value
     (Table : in Table_Type;
      N     : in Positive := 1)
      return String is
   begin
      pragma Assert (Table.Index /= null);

      if N <= Data_Table.Last (Table.Data) then
         return Table.Data.Table (N).Value;
      else
         return "";
      end if;
   end Get_Value;

   ----------------
   -- Get_Values --
   ----------------

   function Get_Values
     (Table : in Table_Type;
      Name  : in String)
      return VString_Array
   is
      Value : Name_Index_Table;
      Found : Boolean;
   begin
      pragma Assert (Table.Index /= null);

      Get_Indexes (Table, Name, Value, Found);

      if Found then
         declare
            Last   : Key_Positive := Name_Indexes.Last (Value);
            Result : VString_Array (1 .. Natural (Last));
         begin
            for I in Name_Indexes.First .. Last loop
               Result (Natural (I))
                  := To_Unbounded_String
                        (Table.Data.Table (Value.Table (I)).Value);
            end loop;
            return Result;
         end;
      else
         return (1 .. 0 => Null_Unbounded_String);
      end if;
   end Get_Values;

   ----------------
   -- Name_Count --
   ----------------

   function Name_Count (Table : in Table_Type) return Natural is
   begin
      if Table.Index = null then
         return 0;
      else
         return Size (Table.Index.all);
      end if;
   end Name_Count;

   --------------------
   -- Normalize_Name --
   --------------------

   function Normalize_Name
     (Name     : in String;
      To_Upper : in Boolean)
      return String is
   begin
      if To_Upper then
         return Ada.Characters.Handling.To_Upper (Name);
      else
         return Name;
      end if;
   end Normalize_Name;

end AWS.Containers.Tables;