-- This file is  free  software, which  comes  along  with  SmartEiffel. This
-- software  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. You can modify it as you want, provided
-- this header is kept unaltered, and a notification of the changes is added.
-- You  are  allowed  to  redistribute  it and sell it, alone or as a part of
-- another product.
--       Copyright (C) 1994-2002 LORIA - INRIA - U.H.P. Nancy 1 - FRANCE
--          Dominique COLNET and Suzanne COLLIN - SmartEiffel@loria.fr
--                       http://SmartEiffel.loria.fr
--
deferred class COLLECTION2[E]
   --
   -- Abstract definition of a 2 dimensional collection of elements
   -- of type E.
   --
   -- The SmartEiffel standard library (SmartEiffel/lib/base) provides two
   -- implementations of COLLECTION2[E]: ARRAY2[E] and FIXED_ARRAY2[E].
   -- All implementations have exactly the same behavior. Switching
   -- from one implementation to another only change the memory used
   -- and the execution time.
   --

inherit
   SAFE_EQUAL[E]
      undefine copy, is_equal
      redefine fill_tagged_out_memory
      end

feature -- Indexing:

   lower1, lower2: INTEGER is
         -- Lower index bounds.
      deferred
      end

   frozen line_minimum: INTEGER is
         -- Equivalent of `lower1'.
      do
         Result := lower1
      end

   frozen column_minimum: INTEGER is
         -- Equivalent of `lower2'.
      do
         Result := lower2
      end

   upper1, upper2: INTEGER is
         -- Upper index bounds.
      deferred
      end

   frozen line_maximum: INTEGER is
         -- Equivalent of `upper1'.
      do
         Result := upper1
      end

   frozen column_maximum: INTEGER is
         -- Equivalent of `upper2'.
      do
         Result := upper2
      end

feature -- Reading:

   item(line, column: INTEGER): E is
      require
         valid_index(line,column)
      deferred
      end

feature -- Writing:

   put(element: like item; line, column: INTEGER) is
      require
         valid_index(line,column)
      deferred
      ensure
         item(line,column) = element
      end

   force(element: like item; line, column: INTEGER) is
         -- Put `element' at position (`line',`column'). Collection is
         -- resized first when (`line',`column') is not inside current
         -- bounds. New bounds are initialized with default values.
      require
         line >= 0
         column >= 0
      deferred
      ensure
         item(line,column) = element
         count >= old count
      end

feature -- Index validity:

   frozen valid_line, valid_index1(line: INTEGER): BOOLEAN is
      do
         Result := lower1 <= line and then line <= upper1
      ensure
         Result = (lower1 <= line and line <= upper1)
      end

   frozen valid_column, valid_index2(column: INTEGER): BOOLEAN is
      do
         Result := lower2 <= column and then column <= upper2
      ensure
         Result = (lower2 <= column and column <= upper2)
      end

   frozen valid_index(line, column: INTEGER): BOOLEAN is
      do
         Result := ((lower1 <= line) and then (line <= upper1)
                    and then
                    (lower2 <= column) and then (column <= upper2))
      ensure
         Result = (valid_line(line) and valid_column(column))
      end

feature -- Counting:

   count1: INTEGER is
         -- Size of the first dimension.
      deferred
      ensure
         Result = upper1 - lower1 + 1
      end

   frozen line_count: INTEGER is
         -- Equivalent of `count1'.
      do
         Result := count1
      end

   count2: INTEGER is
         -- Size of the second dimension.
      deferred
      ensure
         Result = upper2 - lower2 + 1
      end

   frozen column_count: INTEGER is
      do
         Result := count2
      end

   count: INTEGER is
         -- Total number of elements.
      deferred
      ensure
         Result = line_count * column_count
      end

feature

   swap(line1, column1, line2, column2: INTEGER) is
         -- Swap the element at index (`line1',`column1') with the
         -- the element at index (`line2',`column2').
      require
         valid_index(line1,column1)
         valid_index(line2,column2)
      deferred
      ensure
         item(line1,column1) = old item(line2,column2)
         item(line2,column2) = old item(line1,column1)
         count = old count
      end

   set_all_with(v: like item) is
         -- Set all item with value `v'.
      deferred
      ensure
         count = old count
      end

   frozen clear_all is
         -- Set all items to default values.
      local
         value: like item
      do
         set_all_with(value)
      ensure
         count = old count
      end

feature -- Creating or initializing:

   from_collection2(model: COLLECTION2[like item]) is
         --  Uses `model' to initialize Current.
      require
         model /= Void
      deferred
      ensure
         count1 = model.count1
         count2 = model.count2
      end

   from_model(model: COLLECTION[COLLECTION[E]]) is
         -- The `model' is used to fill line by line Current.
         -- Assume all sub-collections of `model' have the same
         -- number of lines.
      require
         model /= Void
      deferred
      ensure
         count1 = model.count
         count2 > 0 implies count2 = model.first.count
      end

feature -- Looking and comparison:

   all_default: BOOLEAN is
         -- Do all items have their type's default value?
      deferred
      end

   same_as(other: COLLECTION2[E]): BOOLEAN is
         -- Unlike `is_equal', this feature can be used to compare
         -- distinct implementation of COLLECTION2.
      require
         other /= Void
      deferred
      ensure
         Result implies standard_same_as(other)
      end

feature -- Printing:

   frozen fill_tagged_out_memory is
      local
         line, column: INTEGER
         v: like item
      do
         tagged_out_memory.append(once "lower1: ")
         lower1.append_in(tagged_out_memory)
         tagged_out_memory.append(once " upper1: ")
         upper1.append_in(tagged_out_memory)
         tagged_out_memory.append(once " lower2: ")
         lower2.append_in(tagged_out_memory)
         tagged_out_memory.append(once " upper2: ")
         upper2.append_in(tagged_out_memory)
         tagged_out_memory.append(once " [%N")
         from
            line := lower1
         until
            line > upper1
               or else
            tagged_out_memory.count > 4096
         loop
            tagged_out_memory.append(once "line ")
            line.append_in(tagged_out_memory)
            tagged_out_memory.append(once "%T: ")
            from
               column := lower2
            until
               column > upper2
            loop
               v := item(line,column)
               if v = Void then
                  tagged_out_memory.append(once "Void")
               else
                  v.out_in_tagged_out_memory
               end
               tagged_out_memory.extend(' ')
               column := column + 1
            end
            tagged_out_memory.extend('%N')
            line := line + 1
         end
         if valid_line(line) then
            tagged_out_memory.append(once "......%N")
         end
      end

feature -- Miscellaneous features:

   occurrences(elt: E): INTEGER is
         -- Number of occurrences using `equal'.
         -- See also `fast_occurrences' to chose the apropriate one.
      deferred
      ensure
         Result >= 0
      end

   fast_occurrences(elt: E): INTEGER is
         -- Number of occurrences using `='.
         -- See also `occurrences' to chose the apropriate one.
      deferred
      ensure
         Result >= 0
      end

   has(x: like item): BOOLEAN is
         -- Search if a element x is in the array using `equal'.
         -- See also `fast_has' to chose the apropriate one.
      deferred
      end

   fast_has(x: like item): BOOLEAN is
         --  Search if a element x is in the array using `='.
      deferred
      end

   replace_all(old_value, new_value: like item) is
         -- Replace all occurences of the element `old_value' by `new_value'
         -- using `equal' for comparison.
         -- See also `fast_replace_all' to choose the apropriate one.
      deferred
      ensure
         count = old count
         occurrences(old_value) = 0
      end

   fast_replace_all(old_value, new_value: like item) is
         -- Replace all occurences of the element `old_value' by `new_value'
         -- using operator `=' for comparison.
         -- See also `replace_all' to choose the apropriate one.
      deferred
      ensure
         count = old count
         fast_occurrences(old_value) = 0
      end

   sub_collection2(line_min, line_max,
                   column_min, column_max: INTEGER): like Current is
         -- Create a new object using selected area of `Current'.
      require
         valid_index(line_min,column_min)
         valid_index(line_max,column_max)
      deferred
      ensure
         Result /= Void
      end

   set_area(element: like item
            line_min, line_max, column_min, column_max: INTEGER) is
         -- Set all the elements of the selected area rectangle with `element'.
      require
         valid_index(line_min,column_min)
         valid_index(line_max,column_max)
      local
         line, column : INTEGER
      do
         from
            line := line_min
         until
            line > line_max
         loop
            from
               column := column_min
            until
               column > column_max
            loop
               put(element,line,column)
               column := column + 1
            end
            line := line + 1
         end
      ensure
         count = old count
      end

feature {COLLECTION2} -- For `same_as' implementation:

   frozen standard_same_as(other: COLLECTION2[E]): BOOLEAN is
      require
         generating_type /= other.generating_type
      local
         line, column: INTEGER
      do
         if lower1 /= other.lower1 then
         elseif upper1 /= other.upper1 then
         elseif lower2 /= other.lower2 then
         elseif upper2 /= other.upper2 then
         else
            from
               Result := true
               line := upper1
            until
               not Result or else line < lower1
            loop
               from
                  column := upper2
               until
                  not Result or else column < lower2
               loop
                  Result := safe_equal(item(line,column),
				       other.item(line,column))
                  column := column - 1
               end
               line := line - 1
            end
         end
      end

   same_as_array2(other: ARRAY2[E]): BOOLEAN is
      require
         other /= Void
      deferred
      end

   same_as_fixed_array2(other: FIXED_ARRAY2[E]): BOOLEAN is
      require
         other /= Void
      deferred
      end

end -- COLLECTION2[E]