note
	description:
		" EiffelVision utility used to retrieve an allocated WEL item. %
		% This class has been created in order to decrease the number of %
		% GDI object allocated."
	legal: "See notice at end of class."
	status: "See notice at end of class."
	date: "$Date:"
	revision: "$Revision:"

class
	EV_GDI_ALLOCATED_OBJECTS [G -> EV_GDI_OBJECT, H -> WEL_GDI_ANY]

inherit
	ANY
		redefine
			default_create
		end

create
	default_create

feature -- Initialization

	default_create
			-- Default initialization feature.
		local
			l_default: detachable G
		do
				-- Allocate space for `Max_allocated_objects' objects.
			create allocated_objects.make_filled (l_default, 1, Max_allocated_objects)
		end

feature {NONE} -- Implementation

	allocated_objects: ARRAY [detachable G]
			-- Sorted array (The most used item at the end of the array)
			-- of all objects located in `allocated_objects'.

	allocated_objects_number: INTEGER
			-- Current number of allocated pens.

	found_object_index: INTEGER
			-- Index of the last object found by `has_object'.

	cache_time: INTEGER
			-- Current time, used to compute for each object the date of the last access.

	successful_cache: INTEGER
			-- debugging purpose

	index_lightest_object: INTEGER
			-- Index of the lightest object.

	has_object (an_object: EV_GDI_OBJECT): BOOLEAN
			-- Is `an_object' in `allocated_objects'?
		local
			i: INTEGER
			object_hash_code: INTEGER
			curr_item: detachable G
			curr_item_value: INTEGER
			previous_item_value: INTEGER
			index_item_to_remove: INTEGER
			value_item_to_remove: INTEGER
		do
			found_object_index := 0

			from
				i := 1
				value_item_to_remove := 2147483646
				object_hash_code := an_object.hash_code
			until
				found_object_index /= 0 or else i > allocated_objects_number
			loop
				curr_item := allocated_objects.item(i)
				check curr_item /= Void then
					if (object_hash_code = curr_item.hash_code) and then
						an_object.is_equal (curr_item)
					then
						found_object_index := i
					else
							-- Can't find the object, so track the element to
							-- be deleted in case a new cell is required.
						curr_item_value := curr_item.value
						if curr_item_value < value_item_to_remove then
							value_item_to_remove := curr_item_value
							index_item_to_remove := i
						end

							-- Swap Current and Previous if they are not ordered.
						if (i > 1) and then (curr_item_value > previous_item_value) then
							swap_allocated_objects (i, i-1)
							if index_item_to_remove = i then
								index_item_to_remove := i - 1
							end
							if index_item_to_remove = i-1 then
								index_item_to_remove := i
							end
						end
					end
				end
					-- Prepare next iteration
				i := i + 1
				previous_item_value := curr_item_value
			end
			Result := (found_object_index /= 0)

			if not Result then
				-- We will delete an object, update the needed fields
				index_lightest_object := index_item_to_remove
			end
		end

	add_to_allocated_objects (new_object: G)
			-- Add `new_object' to the array of allocated objects.
		local
			index_new_item: INTEGER
			l_item: detachable G
		do
			check
				not (allocated_objects_number > Max_allocated_objects)
			end
			if allocated_objects_number = Max_allocated_objects then
				index_new_item := index_lightest_object
					-- Free the object that will be replaced...	
				l_item := allocated_objects.item (index_new_item)
				check l_item /= Void then
					l_item.delete
				end
			else
				allocated_objects_number := allocated_objects_number + 1
				index_new_item := allocated_objects_number
			end

				-- ..and we add it in our array.
			allocated_objects.put (new_object, index_new_item)

			debug("VISION2_WINDOWS_GDI")
				io.put_string ("created ")
			end
		end

	get_previously_allocated_object (real_object_index: INTEGER): H
			-- Retrieve the WEL object located in the array at index `real_object_index'.
		do
				-- Requested pen has been already allocated. We return the
				-- item found in our table.
			check attached allocated_objects.item (real_object_index) as real_object then
				real_object.update (cache_time)

				check attached {H} real_object.item as l_result then
					Result := l_result
					l_result.increment_reference
				end

				debug("VISION2_WINDOWS_GDI")
					successful_cache := successful_cache + 1
					io.put_string ("retrieved cached version ")
				end
			end
		end

	swap_allocated_objects (first_index, second_index: INTEGER)
			-- Swap objects at indexes `first_index' and `second_index'.
		require
			valid_first_index:
				first_index >= 1 and then
				first_index <= allocated_objects_number
			valid_second_index:
				second_index >= 1 and then
				second_index <= allocated_objects_number
		local
			first_object: detachable G
			second_object: detachable G
		do
			first_object := allocated_objects.item (first_index)
			second_object := allocated_objects.item (second_index)

			allocated_objects.put (first_object, second_index)
			allocated_objects.put (second_object, first_index)
		end

feature {NONE} -- Constants

	Max_allocated_objects: INTEGER = 32;
			-- Maximum number of allocated objects we keep.

note
	copyright:	"Copyright (c) 1984-2006, Eiffel Software and others"
	license:	"Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
	source: "[
			 Eiffel Software
			 356 Storke Road, Goleta, CA 93117 USA
			 Telephone 805-685-1006, Fax 805-685-6869
			 Website http://www.eiffel.com
			 Customer support http://support.eiffel.com
		]"




end -- class EV_GDI_ALLOCATED_OBJECTS