indexing
	cluster: "demangler"
	namespace: "candidate"
	description: "Report errors in a `SYNCHRONISED_DIRECTORY' object."
	original_author: "Justin Finnerty"
	original_date: "July 2005"
	current_date: "$Date: 2005/10/31 07:19:34 $"
	current_author: "$Author: finnerty $"
	revision: "$Revision: 2.6 $"	
	-- $Log: sync_report.ge,v $
	-- Revision 2.6  2005/10/31 07:19:34  finnerty
	-- Added ability to create symlinks between directories as an alternative to merging. The major changes are in DIRDUP_REPORT with others adding/changing features as required.
	--
	-- Revision 2.5  2005/10/30 03:41:51  finnerty
	-- Split REPORT_VIEW into REPORT_CONTROL and REPORT_VIEW. Made changes to other classes as necessary
	--
	-- Revision 2.4  2005/10/28 04:17:27  finnerty
	-- Added 'is_editable' for REPORT_VIEW upgrade.
	--
	-- Revision 2.3  2005/09/30 06:49:12  finnerty
	-- Finalised for alpha release with SE and VE compilers
	--
	-- Revision 2.2  2005/09/27 06:14:47  finnerty
	-- Updated to use GOBO and work with SE and VE
	--
	-- Revision 2.1  2005/09/06 22:58:52  finnerty
	-- Renamed *.e to *.ge for gepp
	--
	-- Revision 2.0  2005/08/26 23:31:39  finnerty
	-- == alpha version ==
	--
	-- Revision 1.4  2005/08/24 12:36:20  finnerty
	-- Fixed some logic errors and name changes.
	--
	-- Revision 1.3  2005/08/21 11:55:57  finnerty
	-- Alpha 1 version
	--
	-- Revision 1.2  2005/08/17 06:43:43  finnerty
	-- Added factory methods for TRANSFORM sub-types.
	--
	-- Revision 1.1  2005/08/16 15:05:32  finnerty
	-- Initial abstract data type for a report ona sync dir
	--

deferred class SYNC_REPORT
	-- Report errors in a `SYNCHRONISED_DIRECTORY' object. Gives list
	-- of transformations that resolve the errors.

	-- Programming notes: Derived classes effect `generate' which
	-- should add objects to the `transforms' set. This set can then
	-- edited using a `REPORT_DISPLAY' object. Once editing of
	-- `transforms' is complete, `action' is used to change the
	-- `sync_dir'. If necessary these changes may be reversed using
	-- `undo'.

feature {ANY}
	-- Access
	help: UC_STRING is
			-- A description of what the report does.
		deferred
		end

	label: UC_STRING is
			-- A title or label for this report type
		deferred
		end

	sync_dir: SYNCHRONISED_DIRECTORY
			-- What this report pertains to. May not be `Void'.

	transforms: DS_LIST[TRANSFORM]
			-- Set of transforms to "fix" errors in `sync_dir'. May not
			-- be `Void'.

feature {ANY}
	-- Status Report
	has_result: BOOLEAN is
			-- Has `generate' given a meaningful result
		do
			Result := not transforms.is_empty
		ensure
			Result implies not transforms.is_empty
		end

	is_actionable: BOOLEAN is
			-- Can this report be done?
		do
			if has_result then
				Result := transforms.first.is_actionable
			end
		ensure
			Result implies has_result
			-- Result implies not already done
		end

	is_undoable: BOOLEAN is
			-- Can this report be undone?
		do
			if has_result then
				Result := transforms.last.is_undoable
			end
		ensure
			Result implies has_result
			-- Result implies already done
		end

	is_peer_only: BOOLEAN is
			-- Is this report for working directories only?
		do
		end

	is_store_only: BOOLEAN is
			-- Is this report for back-up directories only?
		do
		end

	is_repeating_type: BOOLEAN is
			-- Does this report needed to be performed repeatedly?

			-- For some reports it is simpler to detect and repair an
			-- error as you go rather than attempt to uncover all
			-- errors. When this feature is `True' a report may be
			-- repeatedly generated until `has_result' is `False'.
		do
		end

	is_editable: BOOLEAN is
			-- Can the list of action in this report be edited? Default 
			-- is that the `current_report's action list is not editable.
		do
		end

#ifdef SE
feature {SYNC_REPORT}
#else
feature {SYNC_REPORT, DP_COMMAND}
#endif
	-- Factories for transform objects
	frozen new_backup_transform(a_parent, an_fso: FILE_SYSTEM_OBJECT) is
			-- Add a special rename transform to list. The new name for
			-- `an_fso' will be unique in its parent directory and in
			-- `a_parent' (if `a_parent' is not its parent)
		local
			l_trans: TRANSFORM
			l_new_name: STRING
		do
			-- discover unique name
			l_new_name := an_fso.unique_backup_name (a_parent)
			!RENAME_TRANSFORM!l_trans.make(an_fso, l_new_name, Current)
			add_transform (l_trans)
		ensure
			-- transforms.last = new object
			Transform_made: transforms.count = old transforms.count + 1
		end

	frozen new_delete_transform(an_fso: FILE_SYSTEM_OBJECT) is
			-- Add a move-to-trash transform to list
		local
			l_trans: TRANSFORM
		do
			!DELETE_TRANSFORM!l_trans.make(an_fso, Current)
			add_transform (l_trans)
		ensure
			-- transforms.last = new object
			Transform_made: transforms.count = old transforms.count + 1
		end

	frozen new_move_transform(an_fso, a_new_parent: FILE_SYSTEM_OBJECT) is
			-- Add a rename transform to list
		local
			l_trans: TRANSFORM
		do
			!MOVE_TRANSFORM!l_trans.make(an_fso, a_new_parent, Current)
			add_transform (l_trans)
		ensure
			-- transforms.last = new object
			Transform_made: transforms.count = old transforms.count + 1
		end

	frozen new_rename_transform(an_fso: FILE_SYSTEM_OBJECT; a_new_name: STRING) is
			-- Add a rename transform to list
		require
			-- a_new_name is a valid file name for the real filesystem
			-- Valid_file_name: is_valid_path (a_new_name)
		local
			l_trans: TRANSFORM
		do
			!RENAME_TRANSFORM!l_trans.make(an_fso, a_new_name, Current)
			add_transform (l_trans)
		ensure
			-- transforms.last = new object
			Transform_made: transforms.count = old transforms.count + 1
		end

	frozen new_symlink_transform(a_from: FILE_SYSTEM_OBJECT; a_to: STRING) is
			-- Add a special symlink transform to list. The transfrom will
			-- add a delete transform for `a_from' and then add a new 
			-- file system object that will hold a symlink from `a_from' 
			-- to `a_to'
		local
			l_trans: TRANSFORM
			l_from_path, l_to_path: STRING
			l_depth: INTEGER
		do
			-- make relative path for symlink
			from
				-- find how deep a_from is from root
				l_depth := a_from.ancestor (sync_dir.root)
				!!l_to_path.make_from_string (a_to)
			until
				l_depth = 0
			loop
				l_to_path.prepend ("../")
				l_depth := l_depth - 1
			end
				
			-- save path of a_from
			l_from_path := a_from.path
			!DELETE_TRANSFORM!l_trans.make (a_from, Current)
			add_transform (l_trans)
			!SYMLINK_TRANSFORM!l_trans.make (l_from_path, l_to_path, Current)
			add_transform (l_trans)
		ensure
			-- transforms.last = new object
			Transform_made: transforms.count = old transforms.count + 2
		end

feature {ANY}
	-- Manipulate a report
	action is
			-- Perform the report's actions on the real file system
		require
			Has_result: has_result
		do
			from
				transforms.start
			until
				transforms.off
			loop
			   transforms.item_for_iteration.action
            transforms.forth
			end
		end

	generate is
			-- Analyse a directory and create report by building up the
			-- `transforms' set.
		require
			Not_generated: not has_result or is_repeating_type
		deferred
		ensure
			-- has_result implies fixable errors found
			-- not has_result implies no errors for this report
		end

	reset is
			-- Remove current transforms, undoing any actions on the
			-- `sync_dir' that have not been done to real file system.
		require
			Generated: has_result
			Not_done: is_actionable or is_repeating_type
		do
			from
			variant
				transforms.count
			until
				transforms.count = 0
			loop
				transforms.last.remove
				transforms.remove_last
			end
		ensure
			Not_generated: not has_result
		end

	undo is
			-- Undo the report's actions on the real file system
		require
			Has_result: has_result
		do
			from
				transforms.finish
			until
				transforms.off
			loop
			   transforms.item_for_iteration.undo
            transforms.back
			end
		ensure
			No_change_to_set: transforms.is_equal(old transforms)
		end

feature {REPORT_VIEW,SYNC_REPORT}
	-- Procedure to reduce transform set
	remove_transform (a_trans: TRANSFORM) is
			-- Remove a `TRANSFORM' object from the report set and undo
			-- its effect on the `sync_dir'
		require
			transforms.has (a_trans)
		do
			transforms.start
			transforms.search_forth (a_trans)
			transforms.remove_at
			a_trans.remove
		ensure
			Removed: transforms.count + 1 = old transforms.count
		end

feature {REPORT_CONTROL,SYNC_REPORT}
	-- Control the viewing object
	has_view: BOOLEAN is
			-- Set viewing object
		do
			Result := view /= Void
		end

	set_view (a_controller: REPORT_CONTROL) is
			-- Set viewing object
		require
			a_controller /= Void
		do
			view := a_controller.get_general_viewer
			view.set_report (Current)
		ensure
			has_view
		end

	unset_view is
			-- Set viewing object
		require
			has_view
		do
			view.unset_report
			view := Void
		ensure
			not has_view
		end

	view: REPORT_VIEW
			-- Displayer object for this report
	
feature {SYNC_REPORT}
	-- Hidden methods and attributes
	add_transform (a_trans: TRANSFORM) is
			-- Add a TRANSFORM to the report set
		do
			transforms.put_last (a_trans)
		ensure
			Has_result: has_result
			Added: transforms.count = old transforms.count + 1
					 a_trans = transforms.last
		end

	make_sync_report (a_sync_dir: SYNCHRONISED_DIRECTORY) is
			-- Initialise attributes to valid values
		require
			Exist_sync_dir: a_sync_dir /= Void
		do
			if not (is_peer_only and not a_sync_dir.is_peer) and then
				not (is_store_only and not a_sync_dir.is_store) then
				!DS_LINKED_LIST[TRANSFORM]!transforms.make_default
				sync_dir := a_sync_dir
			end
		end

invariant
	Valid_set: transforms /= Void implies sync_dir /= Void
	Usable: not (is_peer_only and is_store_only)
	Valid_directory: is_store_only implies sync_dir.is_store
	Valid_directory: is_peer_only implies sync_dir.is_peer
end -- class SYNC_REPORT
