--  Copyright (2008-2011) Cédric Coussinet (cedric.coussinet@nomoseed.net)
--
--  This program is free software: you can redistribute it and/or modify
--  it under the terms of the GNU Affero General Public License as published
--  by the Free Software Foundation, either version 3 of the License, or
--  (at your option) any later version.
--
--  This program 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 Affero General Public License for more details.

--  You should have received a copy of the GNU Affero General Public License
--  along with this program. If not, see <http://www.gnu.org/licenses/>

package body Basic_Sax.Stream_Parser is

   procedure Parse (Handler    : in out Reader'Class;
                    End_Marker : in String) is
      use Ada.Strings.Unbounded;
      S      : String (1 .. Size_String_Max);
      C      : Character;
      I      : Positive;
      Marker : Unbounded_String;
      Atts   : Attributes;
   begin
      Character'Read (Handler.Stream, C);
      loop
         if C = '<' then
            I := 1;
            loop
               Character'Read (Handler.Stream, C);
               exit when C = '>' or C = ' ';
               S (I) := C;
               I := Positive'Succ (I);
            end loop;
            if S (1) /= '/' and S (1) /= '?' and S (1 .. 2) /= "--" then
               Marker := To_Unbounded_String (S (1 .. I - 1));
               Atts.Size := 0;
               if C = ' ' then
                  loop
                     loop
                        Character'Read (Handler.Stream, C);
                        exit when C /= ' ';
                     end loop;
                     if C = '/' then
                        Character'Read (Handler.Stream, C);
                     end if;
                     exit when C = '>';
                     I := 1;
                     loop
                        exit when C = '=';
                        S (I) := C;
                        I := Positive'Succ (I);
                        Character'Read (Handler.Stream, C);
                     end loop;
                     Atts.Size := Natural'Succ (Atts.Size);
                     Atts.Tab (Atts.Size).Name := To_Unbounded_String (S (1 .. I - 1));
                     Character'Read (Handler.Stream, C);
                     I := 1;
                     loop
                        Character'Read (Handler.Stream, C);
                        exit when C = '"';
                        S (I) := C;
                        I := Positive'Succ (I);
                     end loop;
                     Atts.Tab (Atts.Size).Value := To_Unbounded_String (S (1 .. I - 1));
                  end loop;
               end if;
               Start_Element (Handler, To_String (Marker), Atts);
               Character'Read (Handler.Stream, C);
            elsif S (1) = '/' then
               End_Element (Handler, S (2 .. I - 1));
               if S (2 .. I - 1) = End_Marker then
                  exit;
               end if;
               Character'Read (Handler.Stream, C);
            elsif C = ' ' then
               Character'Read (Handler.Stream, C);
               while C /= '>' loop
                  Character'Read (Handler.Stream, C);
               end loop;
            end if;
         else
            I := 1;
            loop
               S (I) := C;
               I := Positive'Succ (I);
               Character'Read (Handler.Stream, C);
               exit when C = '<';
            end loop;
            Characters (Handler, S (1 .. I - 1));
         end if;
      end loop;
   end Parse;

   procedure Move_At (Handler      : in out Reader'Class;
                      Begin_Marker : in String) is
      use Ada.Strings.Unbounded;
      S      : String (1 .. Size_String_Max);
      C      : Character;
      I      : Positive;
      Marker : Unbounded_String;
   begin
      Character'Read (Handler.Stream, C);
      loop
         if C = '<' then
            I := 1;
            loop
               Character'Read (Handler.Stream, C);
               exit when C = '>' or C = ' ';
               S (I) := C;
               I := Positive'Succ (I);
            end loop;
            if S (1) /= '/' and S (1) /= '?' and S (1 .. 2) /= "--" then
               Marker := To_Unbounded_String (S (1 .. I - 1));
               if C = ' ' then
                  loop
                     I := 1;
                     loop
                        Character'Read (Handler.Stream, C);
                        exit when C = '=';
                        S (I) := C;
                        I := Positive'Succ (I);
                     end loop;
                     Character'Read (Handler.Stream, C);
                     I := 1;
                     loop
                        Character'Read (Handler.Stream, C);
                        exit when C = '"';
                        S (I) := C;
                        I := Positive'Succ (I);
                     end loop;
                     Character'Read (Handler.Stream, C);
                     if C = '/' then
                        Character'Read (Handler.Stream, C);
                     end if;
                     exit when C = '>';
                  end loop;
               end if;
               if To_String (Marker) = Begin_Marker then
                  exit;
               end if;
               Character'Read (Handler.Stream, C);
            elsif S (1) = '/' then
               Character'Read (Handler.Stream, C);
            elsif C = ' ' then
               Character'Read (Handler.Stream, C);
               while C /= '>' loop
                  Character'Read (Handler.Stream, C);
               end loop;
            end if;
         else
            I := 1;
            loop
               S (I) := C;
               I := Positive'Succ (I);
               Character'Read (Handler.Stream, C);
               exit when C = '<';
            end loop;
            Characters (Handler, S (1 .. I - 1));
         end if;
      end loop;
   end Move_At;

end Basic_Sax.Stream_Parser;
