note
	description: "[
		A command to cause a {ATTACK_UNIT} to join another as a task force,
		If Current `is_task_force' already and make is called with `a_transfer'
		set to true it will first leave its current task force before joining
		the other; if `a_transfer' is false, all the units in Current's force
		will join the other.
		]"
	author: "Jimmy J. Johnson"

class
	JOIN_TASK_FORCE_COMMAND

inherit

	VITP_COMMAND
		redefine
--			default_create,
			text,
			execute,
			undo
		end

--	LOCATION_CONSTANTS
--		undefine
--			default_create
--		end

--	ATTACK_UNIT_CONSTANTS		-- needed for `Default_ship' in `default_create'
--		undefine
--			default_create
--		end

create
--	default_create,
	make

feature {NONE} -- Initialization

--	default_create
--			-- Create an instance
--		do
--			Precursor {VITP_COMMAND}
--			create saved_units.make
--			unit := Default_ship
--			other_unit := Default_ship
--		end

	make (a_unit: like unit; a_other_unit: like unit; a_transfer: BOOLEAN)
			-- Initialize a command that causes `a_unit' to join `a_other_unit' as a task_force
			-- If `a_transfer' then `a_unit' leaves its task force before joining `a_other_unit'.
		require
			unit_exists: a_unit /= Void
			other_exists: a_other_unit /= Void
			unit_not_submarine: not attached {SUBMARINE} a_unit
			other_not_submarine: not attached {SUBMARINE} a_other_unit
			not_same_task_force: (a_unit.is_task_force and a_other_unit.is_task_force) implies
									a_unit.task_force /= a_other_unit.task_force
		local
			tf: TASK_FORCE
			i: INTEGER
		do
			default_create
			create saved_units.make
			is_transferring := a_transfer
			unit := a_unit
			other_unit := a_other_unit
				-- If both units comprise a task force, then must mark so the units
				-- comprising the task force of `unit' are saved for undo purposes.
			if a_other_unit.is_task_force then
				if a_unit.is_task_force then
					if is_transferring then
						saved_other_unit_imp := some_other_unit_in_task_force
					else
						is_two_task_forces := true
						tf := a_unit.task_force
						from i := 1
						until i > tf.count
						loop
								-- Save units to be removed from `other_unit' on `undo'
							saved_units.extend (tf.i_th (i))
							i := i + 1
						end
					end
				end
			end
			affected_objects.extend (unit.game)
		end

feature -- Access

	text: STRING
			-- Description of the command
		do
			Result := "COMMAND: Join Task Force -- "+ unit.name + " joins "
			if other_unit.is_task_force then
				Result := Result + other_unit.task_force.first.name
			else
				Result := Result + other_unit.name
			end
		end

	unit: ATTACK_UNIT
			-- The unit to be moved

	other_unit: ATTACK_UNIT
			-- The other unit to which `unit' is to be joined as a task force

feature -- Basic operations

	execute
			-- Perform the action
		do
			Precursor {VITP_COMMAND}
			if is_transferring then
				unit.leave_force
			end
			unit.join_force (other_unit)
		end

	undo
			-- Reverse the effects of executing the command
		local
			m1, m2: detachable ATTACK_UNIT
		do
			Precursor {VITP_COMMAND}
				-- Removed the saved_units from the task force
			from saved_units.start
			until saved_units.exhausted
			loop
				saved_units.item.leave_force
				saved_units.forth
			end
			unit.leave_force
				-- Restore the saved units to their own task force
			if is_transferring then
				unit.join_force (saved_other_unit)
			else
					-- Must restore all the units to their own task force
				check
					multiple_units: saved_units.count >= 2
						-- because it would not have been a task force during creation,
						-- leading to creation and saving of the list of units
				end
				from
					saved_units.start
					m1 := saved_units.first
					saved_units.forth
				until saved_units.exhausted
				loop
					m2 := saved_units.item
					m2.join_force (m1)
					saved_units.forth
				end
				check
					unit.task_force /= other_unit.task_force
						-- because original task force was restored
				end
			end
		end

feature -- Status report

	is_transferring: BOOLEAN
			-- Is `unit' being transferred out of its task force?

	is_two_task_forces: BOOLEAN
			-- Will the command, at creation, join two task forces?

feature {NONE} -- Implementation

	some_other_unit_in_task_force: ATTACK_UNIT
			-- A unit other than `unit' that is in the `task_force' of `unit'
		require
			is_task_force: unit.is_task_force
		local
			tf: TASK_FORCE
			i: INTEGER
		do
			tf := unit.task_force
			Result := tf.i_th (1)
			from i := 1
			until Result /= unit
			loop
				Result := tf.i_th (i)
				i := i + 1
			end
		end

	saved_other_unit: ATTACK_UNIT
			-- In case we need to restore during an undo
		do
			check attached saved_other_unit_imp as ou then
				Result := ou
			end
		end

	saved_other_unit_imp: detachable ATTACK_UNIT
			-- In case we need to restore during an undo

	saved_units: LINKED_LIST [ATTACK_UNIT]
			-- Used during undo when `unit' was a task force

end
