-------------------------------------------------------------------------------
--
--  This file is part of AdaBrowse.
--
-- <STRONG>Copyright (c) 2002 by Thomas Wolf.</STRONG>
-- <BLOCKQUOTE>
--    AdaBrowse 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, or (at your option) any
--    later version. AdaBrowse is distributed in the hope that it will be
--    useful, but <EM>without any warranty</EM>; without even the implied
--    warranty of <EM>merchantability or fitness for a particular purpose.</EM>
--    See the GNU General Public License for  more details. You should have
--    received a copy of the GNU General Public License with this distribution,
--    see file "<A HREF="GPL.txt">GPL.txt</A>". If not, write to the Free
--    Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
--    USA.
-- </BLOCKQUOTE>
--
-- <DL><DT><STRONG>
-- Author:</STRONG><DD>
--   Thomas Wolf  (TW)
--   <ADDRESS><A HREF="mailto:twolf@acm.org">twolf@acm.org</A></ADDRESS></DL>
--
-- <DL><DT><STRONG>
-- Purpose:</STRONG><DD>
--   Filters for formatted output of comments.</DL>
--
-- <!--
-- Revision History
--
--   04-JUN-2002   TW  Initial version.
--   24-JUN-2002   TW  Changed the pipe filter from a dyadic operator to
--                     a flat, multi-operand operator. For some unknown reason
--                     GNAT had severe problems with finalizing pipe filters
--                     using the recursive dyadic operator implementation: it
--                     somehow took ages. (Note: it may have well been some
--                     programming error of my part, such as may not having
--                     gotten the tree links right. But I don't know, for I
--                     didn't check this; I just rewrote it. Anyway:) With the
--                     new structure, there can be at most one pipe filter,
--                     and it'll be at top level, and finalizing it works like
--                     a charm and is fast.
--   01-JUL-2002   TW  Renamed the "None" filter to "Entities", and added the
--                     "Unknown" filter.
-- -->
-------------------------------------------------------------------------------

pragma License (GPL);

with Ada.Unchecked_Deallocation;
with Ada.Finalization;

with Util.Text;

package AD.Filters is

   pragma Elaborate_Body;

   ----------------------------------------------------------------------------
   --  Root filter class

   type Filter     is abstract tagged limited null record;
   type Filter_Ref is access all Filter'Class;

   procedure Transform
     (Self : access Filter;
      Text : in out Util.Text.Unbounded_String)
      is abstract;

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

   Parse_Error : exception;
   --  May be raised by @Parse@ if the program is invalid.

   function Parse
     (Program : in String)
     return Filter_Ref;
   --  raises @Parse_Error@ if @Program@ has an illegal syntax. Otherwise
   --  returns a filter implementing the given program.

   ----------------------------------------------------------------------------
   --  Simple filters that do not involve HTML parsing.

   type Filter_Pipe is new Filter with private;

   procedure Add_Operand
     (Self    : access Filter_Pipe;
      Operand : in     Filter_Ref);

   procedure Transform
     (Self : access Filter_Pipe;
      Text : in out Util.Text.Unbounded_String);

   type Filter_Entities is new Filter with null record;

   procedure Transform
     (Self : access Filter_Entities;
      Text : in out Util.Text.Unbounded_String);

   type Filter_Enclose is new Filter with private;

   procedure Init
     (Self          : access Filter_Enclose;
      Before, After : in     String);

   procedure Transform
     (Self : access Filter_Enclose;
      Text : in out Util.Text.Unbounded_String);

   type Filter_Pre is new Filter with null record;

   procedure Transform
     (Self : access Filter_Pre;
      Text : in out Util.Text.Unbounded_String);

   type Filter_Swallow is new Filter with null record;

   procedure Transform
     (Self : access Filter_Swallow;
      Text : in out Util.Text.Unbounded_String);

   type Filter_Linefeeds is (LF_Only, CR_And_LF, CR_Only, Default_LF);

   type Filter_Execute (Linefeed : Filter_Linefeeds) is
     new Filter with private;

   procedure Init
     (Self : access Filter_Execute;
      Cmd  : in     String);

   procedure Transform
     (Self : access Filter_Execute;
      Text : in out Util.Text.Unbounded_String);

   ----------------------------------------------------------------------------
   --  Filters that need to parse the HTML. First tag-modifying filters:

   type Filter_Expand is new Filter with null record;

   Recursive_Expansion : exception;

   procedure Transform
     (Self : access Filter_Expand;
      Text : in out Util.Text.Unbounded_String);

   type Filter_Strip is new Filter with null record;

   procedure Transform
     (Self : access Filter_Strip;
      Text : in out Util.Text.Unbounded_String);

   type Filter_Unknown (Std_Only : Boolean) is new Filter with null record;

   procedure Transform
     (Self : access Filter_Unknown;
      Text : in out Util.Text.Unbounded_String);

   ----------------------------------------------------------------------------
   --  And now content-modifying filters:

   type Filter_Plain is new Filter with null record;

   procedure Transform
     (Self : access Filter_Plain;
      Text : in out Util.Text.Unbounded_String);

   type Filter_Para is new Filter with null record;

   procedure Transform
     (Self : access Filter_Para;
      Text : in out Util.Text.Unbounded_String);

   type Filter_Lines is new Filter with null record;

   procedure Transform
     (Self : access Filter_Lines;
      Text : in out Util.Text.Unbounded_String);

   type Filter_Shortcut is new Filter with null record;

   procedure Transform
     (Self : access Filter_Shortcut;
      Text : in out Util.Text.Unbounded_String);

   type Filter_HR (Strip : Boolean) is
     new Filter with null record;

   procedure Transform
     (Self : access Filter_HR;
      Text : in out Util.Text.Unbounded_String);

   type Filter_Standard is new Filter with null record;

   procedure Transform
     (Self : access Filter_Standard;
      Text : in out Util.Text.Unbounded_String);
   --  Same as Expand | Strip | HR | Para | Shortcut | Plain

   procedure Free is
      new Ada.Unchecked_Deallocation (Filter'Class, Filter_Ref);

private

   type Filter_Enclose is new Filter with
      record
         Before, After : Util.Text.Unbounded_String;
      end record;

   type Filter_Execute (Linefeed : Filter_Linefeeds) is
     new Filter with
      record
         Cmd : Util.Text.Unbounded_String;
      end record;

   type Filter_Killer (Parent : access Filter_Pipe'Class) is
     new Ada.Finalization.Limited_Controlled with null record;

   procedure Finalize (Self : in out Filter_Killer);

   type Operand_Table is array (Positive range <>) of Filter_Ref;
   type Operand_Ptr   is access all Operand_Table;

   type Filter_Pipe is new Filter with
      record
         Killer   : Filter_Killer (Filter_Pipe'Access);
         Operands : Operand_Ptr;
      end record;

   --  Note: I use a controlled component to avoid that all filters become
   --  controlled types. I fear that making type 'Filter' (limited) controlled
   --  may encur too large an overhead for the standard filter.

end AD.Filters;


