-----------------------------------------------------------------------
--                               G P S                               --
--                                                                   --
--                    Copyright (C) 2008-2009, AdaCore               --
--                                                                   --
-- GPS 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 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 --
-- General Public License for more details. You should have received --
-- a copy of the GNU General Public License along with this program; --
-- if not,  write to the  Free Software Foundation, Inc.,  59 Temple --
-- Place - Suite 330, Boston, MA 02111-1307, USA.                    --
-----------------------------------------------------------------------

with Diffing;
with GNAT.Strings; use GNAT.Strings;

package body String_Diff is

   type Iter is record
      S : String_Access;
      I : Natural;
   end record;

   Null_Object : constant Character := ASCII.NUL;

   function Length (C : String_Access) return Natural;
   function First (C : String_Access) return Iter;
   function Last (C : String_Access) return Iter;
   function Get (I : Iter) return Character;
   function Next (I : Iter) return Iter;
   function Prev (I : Iter) return Iter;
   function At_End (I : Iter) return Boolean;
   --  See documentation in Diffing

   ------------
   -- Length --
   ------------

   function Length (C : String_Access) return Natural is
   begin
      return C'Length;
   end Length;

   -----------
   -- First --
   -----------

   function First (C : String_Access) return Iter is
   begin
      return (S => C, I => C'First);
   end First;

   ----------
   -- Last --
   ----------

   function Last (C : String_Access) return Iter is
   begin
      return (S => C, I => C'Last);
   end Last;

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

   function Get (I : Iter) return Character is
   begin
      return I.S (I.I);
   end Get;

   ----------
   -- Next --
   ----------

   function Next (I : Iter) return Iter is
   begin
      return (S => I.S, I => I.I + 1);
   end Next;

   ----------
   -- Prev --
   ----------

   function Prev (I : Iter) return Iter is
   begin
      return (S => I.S, I => I.I - 1);
   end Prev;

   ------------
   -- At_End --
   ------------

   function At_End (I : Iter) return Boolean is
   begin
      return I.I >= I.S'Last;
   end At_End;

   package String_Access_Diff is new Diffing
     (Object      => Character,
      Container   => String_Access,
      Iterator    => Iter,
      Null_Object => Null_Object,
      "="         => "=",
      Length      => Length,
      Last        => Last,
      First       => First,
      Get         => Get,
      Next        => Next,
      Prev        => Prev,
      At_End      => At_End);

   ----------
   -- Diff --
   ----------

   procedure Diff
     (Old_String : String;
      New_String : String;
      Callback   : Diff_Callback)
   is
      Ol : String_Access := new String'(Old_String);
      Ne : String_Access := new String'(New_String);

      procedure Wrapper
        (Old_Obj, New_Obj : Character;
         State : String_Access_Diff.Diff_State);
      --  Callback passed to the diff function

      -------------
      -- Wrapper --
      -------------

      procedure Wrapper
        (Old_Obj, New_Obj : Character;
         State : String_Access_Diff.Diff_State) is
      begin
         Callback (Old_Obj, New_Obj,
                   Diff_State'Val (String_Access_Diff.Diff_State'Pos (State)));
      end Wrapper;

   begin
      String_Access_Diff.Diff (Ol, Ne, Wrapper'Unrestricted_Access);
      GNAT.Strings.Free (Ol);
      GNAT.Strings.Free (Ne);
   end Diff;

end String_Diff;
