indexing
	namespace: "candidate"
	cluster: "fso"
	description: "Represent a file system object."
	original_author: "Justin Finnerty"
	original_date: "July 2005"
	current_date: "$Date: 2005/09/28 13:38:19 $"
	current_author: "$Author: finnerty $"
	revision: "$Revision: 2.2 $"
	-- $Log: file_system_object.ge,v $
	-- Revision 2.2  2005/09/28 13:38:19  finnerty
	-- Updated to work with ISE
	--
	-- Revision 2.1  2005/09/05 02:34:07  finnerty
	-- Renamed *.e to *.ge for gepp
	--
	-- Revision 2.1  2005/09/02 08:10:26  finnerty
	-- Added features to better support DIRDUP_REPORT
	--
	-- Revision 2.0  2005/08/26 23:30:21  finnerty
	-- == alpha version ==
	--
	-- Revision 1.6  2005/08/24 23:24:48  finnerty
	-- Replaced FILE_TOOLS with FSO_PROP_FACTORY for testing file existance.
	--
	-- Revision 1.5  2005/08/21 11:54:26  finnerty
	-- Alpha 1 version
	--
	-- Revision 1.4  2005/08/12 07:00:33  finnerty
	-- Amended procedures for change to FSO_PROPERTIES factory. Removed
	-- 'delete' and 'move' procedures. Manipulation of the underlying
	-- file system will be handled elsewhere, probably in the
	-- SYNCHRONISED_DIRECTORY derived types.
	--
	-- Revision 1.3  2005/08/10 02:20:20  finnerty
	-- Provided support for POSIX... and EIFFEL... variants of FSO_PROPERTIES
	--
	-- Revision 1.2  2005/08/09 13:46:36  finnerty
	-- Changes for alpha test. Is now a concrete class with OS abstracted in FSO_PROPERTIES heirarchy.
	--
	-- Revision 1.1  2005/08/07 02:15:54  finnerty
	-- Base type for file system objects. FSOs represent a file/directory etc in a real file system.
	--
   --
class FILE_SYSTEM_OBJECT
	-- Represent a file system object.

inherit
	TREE_NODE
	FSO_PROP_FACTORY
		rename
			make_root as make_base
		redefine
			path
		end

creation {ANY}
	make_root, make_child
			
feature {NONE}
	-- Creation methods restricted as valid during creation only.
	make_root (a_filename: STRING) is
			-- Create the root node of a tree.
		require
			Name_required: a_filename /= Void and not a_filename.is_empty
			Sync_with_filesystem: test_path ( a_filename )
		do
			-- Do TREE_NODE creation
			make
			make_base (a_filename)
		ensure
			Sync_with_filesystem: exists
		end

	make_child (a_filename: STRING; a_parent: FILE_SYSTEM_OBJECT) is
			-- Create node and add to a parent.
		require
			Name_required: a_filename /= Void and not a_filename.is_empty
			Parent_required: a_parent /= Void
			Sync_with_filesystem: test_path_join ( a_parent.path, a_filename )
			-- Sync_with_filesystem: PATH( a_parent.path, a_name ) must
			-- represent a real file system object
		do
			-- Do TREE_NODE creation
			make
#ifdef SE
			m_name := a_filename.twin
#else
			!!m_name.make_from_string (a_filename)
#endif
			-- Add to parent
			put_parent(a_parent)
			reset_properties
		ensure			
			Has_properties: properties /= Void
			Sync_with_filesystem: exists
		end

feature {ANY}
	-- Queries
	frozen ancestor(a_parent: FILE_SYSTEM_OBJECT): INTEGER is
			-- Number of parent steps to `a_parent'
		require
			a_parent /= Void
		local
			l_cursor: like Current
		do
			from
				l_cursor := Current
				Result := 0
			variant
				l_cursor.depth
			until
				l_cursor = a_parent or else
				not l_cursor.has_parent
			loop
				l_cursor := l_cursor.parent
				Result := Result + 1
			end
			if l_cursor /= a_parent then
				Result := -1
			end
		ensure
			-- Result = -1 implies `a_parent' is not an ancestor
		end

	get_child_named (a_name: STRING): FILE_SYSTEM_OBJECT is
			-- Does one of the immediate child nodes have this name?
		do
			if has_children then
				from
					Result := first_child
				until
					Result = last_child or else
					Result.name.is_equal (a_name)
				loop
					Result := Result.next_sibling
				end
				if not Result.name.is_equal (a_name) then
					Result := Void
				end
			end
		end
	
	has_child_named (a_name: STRING): BOOLEAN is
			-- Does one of the immediate child nodes have this name?
		do
			Result := Void /= get_child_named (a_name)
		end
	
	path: STRING is
			-- Path of file system object including `name'
		local
			l_cursor: like Current
			l_left_end_of_path: STRING
		do
			-- Return the full path, including the current name, of this 
			-- object. There is not a corresponding method to get the path 
			-- of this object excluding the current name as this can be 
			-- obtained from `parent.full_path'
			from
				-- From the current position
				l_cursor := Current
				l_left_end_of_path := name
				Result := l_left_end_of_path
			until
				-- Loop until to root
				not l_cursor.has_parent
			loop
				Result := l_cursor.parent.name
				-- Add parent's name and path.
				to_file_path_with( Result, l_left_end_of_path )
				l_left_end_of_path := Result
				-- Step up the parent tree
				l_cursor := l_cursor.parent
			end
		ensure then
			-- Result has valid notation for real file system
		end

	unique_backup_name (a_parent: FILE_SYSTEM_OBJECT): STRING is
			-- Create a name for this FSO that is unique relative to our 
			-- current parent and `a_parent'.
		local
			l_counter, l_start_index: INTEGER
			l_done: BOOLEAN
			l_death: EXCEPTIONS
		do
			-- discover unique name
			from
				l_counter := 1
				Result := name + ".~~~"
#ifdef SE
				l_start_index := Result.upper - 1
#else
				l_start_index := Result.count - 1
#endif
				l_done := False
			until
				l_done or else
#ifdef SE
				not l_counter.fit_integer_16
#else
				l_counter > 32768
#endif
			loop
#ifdef SE
				Result.replace_substring (l_counter.to_string, l_start_index, Result.upper - 1)
#else
				Result.replace_substring (l_counter.out, l_start_index, Result.count - 1)
#endif
				if not parent.has_child_named (Result) then
					l_done := True
					if parent /= a_parent and then
						a_parent.has_child_named (Result) then
						l_done := False
					end
				end
				l_counter := l_counter + 1
			end
			if not l_done then
				-- issue warning
#ifdef SE
				std_output.put_string ("Sorry, could not find unique backup name for %
											  %file " + name + "(32000 names tried!!)")
				std_output.put_new_line
#else
#endif
				!!l_death
				l_death.die (1)
			end
		ensure
			Result_not_empty: Result /= Void and then not Result.is_empty
		end

end -- class FILE_SYSTEM_OBJECT
