note
	description: "[
		Root class for all the game pieces in VITP.
		]"
	author: "Jimmy J. Johnson"

deferred class
	ATTACK_UNIT

inherit

	VITP_ITEM
		redefine
			make
		end

	COMPARABLE
		undefine
			copy,
			is_equal
		end

feature -- Initialization

	make (a_game: like game)
			-- Initialize with the values; these are initial values and cannot be changed
			--		`a_name' = name of the ship or unit
			--		`a_nationality' = country to which it belongs
			--		`a_arrival_turn' = turn 1 to 9 in which the unit enters the game
			--		`a_airstrike' = the unit's "airstrike factor"
			--		`a_guns' = the unit's "gunnery factor"
			--		`a_armor' = the unit's "armor factor"
			--		`a_speed' = the unit's "speed factor"
			--		`a_bonus' = true if the unit has an initial attack bonus
		local
			lin: LINEAR [PORT]
		do
			Precursor {VITP_ITEM} (a_game)
			create task_force.make (a_game)
			task_force.set_ordered
--			arrival_location := game.still_in_box
			position := [0, 0]
				-- Initialize to never return (changed for air and amphibious units)
			returning_turn := 0
			task_force.extend (Current)
		end

feature -- Access

	arrival_turn: INTEGER
			-- Turn on which this unit enters the game.
		deferred
		end

	airstrike_factor: INTEGER
			-- The initial number of dice the unit rolls when attacking
			-- during a "day action".
		deferred
		end

	gunnery_factor: INTEGER
			-- The initial value for the number of dice the unit rolls
			-- when attacking during a "night action".
		deferred
		end

	defense_factor: INTEGER
			-- The number of damage points a unit can have without sinking.
			-- (This is doubled when the unit is in port.)
		deferred
		end

	speed_factor: INTEGER
			-- The initial "speed" of the unit.
		deferred
		end

	attack_bonus: BOOLEAN
			-- The initial setting saying if a unit can add one to each die roll.
			-- If the unit is a carrier this applies only to the airstrike factor.
		deferred
		end

	returning_turn: INTEGER
			-- The turn on which this unit can reenter the game.

	home_port: PORT
			-- The {PORT} from which Current is basing this turn.
		attribute
			Result := game.default_port
		end

	location: LOCATION
			-- The sea, base, or port at which Current is located.
		attribute
--			Result := game.still_in_box
			if Current.is_japanese then
				Result := game.japanese_oa_chart
			else
				if Current.arrival_turn = 1 then
					Result := game.allied_starting_forces_chart
				else
					Result := game.allied_oa_chart
				end
			end
		end

	damage: INTEGER
			-- The amount of total damage Current has taken

	gunnery_count: INTEGER
			-- Number of dice the unit rolls when attacking during a "night action".
			-- It is the `Gunnery_factor' reduced by the amount of `damage'.
		do
			Result := (gunnery_factor - damage).max (1)
		end

	defense_count: INTEGER
			-- The amount of armor remaining, used to determine if a unit is "sunk".
		do
			Result := defense_factor - damage
		end

	speed_count: INTEGER
			-- The actual speed of Current calculated from other factors
		do
			Result := (speed_factor - damage).max (1)
		end

	airstrike_count: INTEGER
			-- Number of dice the unit rolls when attacking during a "day actions".
		do
			Result := airstrike_factor
		end

	task_force: TASK_FORCE
			-- The whole force including Current if others

	target: ATTACK_UNIT
			-- The target (if `is_targetting')
		do
			check attached target_imp as t then
				Result := t
			end
		end

	relative_value: INTEGER
			-- Relative value of current to other units, calculated from the
			-- current values of the gunnery, defense, and speed counts.
		local
			b_fac: INTEGER
		do
			if attack_bonus then
				if airstrike_factor > 0 then
						-- Apply bonus to airstrike only
					b_fac := Bonus_weight * airstrike_weight
--					Result := (airstrike_count + Bonus_weight) * Airstrike_weight
--					Result := Result + gunnery_count * Gunnery_weight
				else
						-- apply bonus to guns unless too much damage
					if defense_count > 0 then
						b_fac := Bonus_weight * Gunnery_weight
--						Result := (gunnery_count + Bonus_weight) * Gunnery_weight
--						Result := Result + airstrike_count * Airstrike_weight
					end
				end
			end
			Result := b_fac + airstrike_count + gunnery_count
			Result := Result + defense_count * Defense_weight + speed_factor * Speed_weight
--			if Current = Tone then
--				do_nothing
--			end
--			if Current = Mutsu then
--				do_nothing
--			end
		end

	patrol_distance: INTEGER
			-- How may sea areas can Current move through as patroller?
			-- Determined by the unit type and nationality
		do
			Result := 2
		end

	raid_distance: INTEGER
			-- How many sea areas can Current move through as raider?
			-- Determined by the unit type and nationality
		local
			has_non_major: BOOLEAN
		do
			if is_task_force then
				from task_force.start
				until task_force.exhausted or has_non_major
				loop
					if not task_force.item.is_major_power then
						has_non_major := true
					end
					task_force.forth
				end
			end
			if not has_non_major then
				Result := patrol_distance + 1
			end
		end

feature -- Access

	sailing_distance: INTEGER
				-- The distance Current can patrol or raid (depending on `is_raiding').
				-- This is the minimum of all contained units.
		local
			f: INTEGER
			u: ATTACK_UNIT
		do
			Result := {INTEGER}.Max_value
			from task_force.start
			until task_force.is_after
			loop
				u := task_force.item
				if u.sailing_distance < Result then
					Result := f
				end
				task_force.forth
			end
		end

	reinforceable_ports: LINKED_SET [PORT]
			-- A list containing each {PORT} to which Current
			-- can be moved during the reinforcement step.
		require
			is_reinforcing: game.sequence_of_play.is_reinforcement_step
		deferred
		end

	patrolable_sea_areas: LINKED_SET [SEA_AREA]
			-- A list containing each {SEA_AREA} to which Current
			-- can be moved during the moving patrollers step.
		local
			sop: VITP_SEQUENCE_OF_PLAY
			sd: INTEGER
			s: SEA_AREA
			dist: INTEGER
		do
--			io.put_string ("ATTCK_UNIT.patrolable_sea_areas:  fix using GRAPH_ITERATOR.shortest_paths %N")
			create Result.make
			sop := game.sequence_of_play
			if sop.is_patrolling_step and
					((not game.is_allied_nationality (nationality) and then sop.is_japanese_player) or else
					(game.is_allied_nationality (nationality) and then sop.is_allied_player)) then
				if home_port = game.yokosuka_navy_yard or home_port = game.okinawa then
					Result.extend (game.japanese_islands)
					if not is_opposed (game.japanese_islands) then
						Result.extend (game.indonesia)
						Result.extend (game.marianas_islands)
						Result.extend (game.central_pacific_ocean)
						Result.extend (game.aleutian_islands)
					end
				elseif home_port = game.saigon or home_port = game.singapore then
					Result.extend (game.indonesia)
					if not is_opposed (game.indonesia) then
						Result.extend (game.bay_of_bengal)
						Result.extend (game.indian_ocean)
						Result.extend (game.south_pacific_ocean)
						Result.extend (game.marianas_islands)
						Result.extend (game.japanese_islands)
					end
				elseif home_port = game.ceylon or home_port = game.andaman_islands then
					Result.extend (game.bay_of_Bengal)
					if not is_opposed (game.bay_of_bengal) then
						Result.extend (game.indonesia)
						Result.extend (game.indian_ocean)
					end
				elseif home_port = game.philippines then
					Result.extend (game.indonesia)
					Result.extend (game.marianas_Islands)
					if not is_opposed (game.indonesia) then
						Result.extend (game.bay_of_bengal)
						Result.extend (game.indian_ocean)
						Result.extend (game.south_pacific_ocean)
						Result.extend (game.marianas_islands)
						Result.extend (game.japanese_islands)
					end
					if not is_opposed (game.marianas_islands) then
						Result.extend (game.south_pacific_ocean)
						Result.extend (game.marshall_islands)
						Result.extend (game.central_pacific_ocean)
						Result.extend (game.japanese_islands)
					end
				elseif home_port = game.lae then
					Result.extend (game.south_pacific_ocean)
					Result.extend (game.indonesia)
					if not is_opposed (game.indonesia) then
						Result.extend (game.japanese_islands)
						Result.extend (game.marianas_islands)
					end
					if not is_opposed (game.south_pacific_ocean) then
						Result.extend (game.marianas_islands)
						Result.extend (game.coral_sea)
						Result.extend (game.us_mandate)
						Result.extend (game.marshall_islands)
					end
				elseif home_port = game.australia or home_port = game.port_moresby then
					Result.extend (game.indian_ocean)
					Result.extend (game.coral_sea)
					if not is_opposed (game.indian_ocean) then
						Result.extend (game.bay_of_bengal)
						Result.extend (game.indonesia)
					end
					if not is_opposed (game.coral_sea) then
						Result.extend (game.south_pacific_ocean)
						Result.extend (game.us_mandate)
					end
				elseif home_port = game.guadalcanal then
					Result.extend (game.coral_sea)
					Result.extend (game.south_pacific_ocean)
					if not is_opposed (game.coral_sea) then
						Result.extend (game.indian_ocean)
						Result.extend (game.us_mandate)
					end
					if not is_opposed (game.south_pacific_ocean) then
						Result.extend (game.indonesia)
						Result.extend (game.marianas_islands)
						Result.extend (game.marshall_islands)
						Result.extend (game.us_mandate)
					end
				elseif home_port = game.new_hebrides then
					Result.extend (game.coral_sea)
					Result.extend (game.us_mandate)
					if not is_opposed (game.coral_sea) then
						Result.extend (game.indian_ocean)
						Result.extend (game.south_pacific_ocean)
					end
					if not is_opposed (game.us_mandate) then
						Result.extend (game.south_pacific_ocean)
						Result.extend (game.marshall_islands)
						Result.extend (game.hawaiian_islands)
					end
				elseif home_port = game.samoa then
					Result.extend (game.us_mandate)
					if not is_opposed (game.us_mandate) then
						Result.extend (game.coral_sea)
						Result.extend (game.south_pacific_ocean)
						Result.extend (game.marshall_islands)
						Result.extend (game.hawaiian_islands)
					end
				elseif home_port = game.johnston_island or home_port = game.pearl_harbor then
					Result.extend (game.hawaiian_islands)
					if not not is_opposed (game.hawaiian_Islands) then
						Result.extend (game.us_mandate)
						Result.extend (game.marshall_islands)
						Result.extend (game.central_pacific_ocean)
						Result.extend (game.north_pacific_ocean)
					end
				elseif home_port = game.kwajalein or home_port = game.maloelap then
					Result.extend (game.marshall_islands)
					if not is_opposed (game.marshall_islands) then
						Result.extend (game.south_pacific_ocean)
						Result.extend (game.us_mandate)
						Result.extend (game.hawaiian_islands)
						Result.extend (game.central_pacific_ocean)
						Result.extend (game.marianas_islands)
					end
				elseif home_port = game.truk then
					Result.extend (game.south_pacific_ocean)
					Result.extend (game.marshall_islands)
					Result.extend (game.marianas_islands)
					if not is_opposed (game.south_pacific_ocean) then
						Result.extend (game.indonesia)
						Result.extend (game.coral_sea)
						Result.extend (game.us_mandate)
					end
					if not is_opposed (game.marshall_islands) then
						Result.extend (game.us_mandate)
						Result.extend (game.hawaiian_islands)
						Result.extend (game.central_pacific_ocean)
					end
					if not is_opposed (game.marianas_islands) then
						Result.extend (game.indonesia)
						Result.extend (game.japanese_islands)
						Result.extend (game.central_pacific_ocean)
					end
				elseif home_port = game.saipan then
					Result.extend (game.marianas_islands)
					if not is_opposed (game.marianas_islands) then
						Result.extend (game.japanese_Islands)
						Result.extend (game.indonesia)
						Result.extend (game.south_pacific_ocean)
						Result.extend (game.marshall_islands)
						Result.extend (game.central_pacific_ocean)
					end
				elseif home_port = game.midway then
					Result.extend (game.central_pacific_ocean)
					if not is_opposed (game.central_pacific_ocean) then
						Result.extend (game.japanese_islands)
						Result.extend (game.marianas_islands)
						Result.extend (game.marshall_islands)
						Result.extend (game.hawaiian_islands)
						Result.extend (game.north_pacific_ocean)
						Result.extend (game.aleutian_islands)
					end
				elseif home_port = game.dutch_harbor then
					Result.extend (game.north_pacific_ocean)
					Result.extend (game.aleutian_islands)
					if not is_opposed (game.north_pacific_ocean) then
						Result.extend (game.central_pacific_ocean)
						Result.extend (game.hawaiian_islands)
					end
					if not is_opposed (game.aleutian_islands) then
						Result.extend (game.japanese_islands)
						Result.extend (game.central_pacific_ocean)
					end
				elseif home_port = game.attu then
					Result.extend (game.aleutian_islands)
					if not is_opposed (game.aleutian_islands) then
						Result.extend (game.japanese_islands)
						Result.extend (game.central_pacific_ocean)
						Result.extend (game.north_pacific_ocean)
					end
				else
				end
			end
		end

	landable_ports: LINKED_SET [PORT]
			-- A list containing each {PORT} at which Current can make
			-- a landing if at the appropriate point in the game
		local
			lin: LINEAR [PORT]
		do
			create Result.make
			if attached {SEA_AREA} location as s then
				lin := s.adjoining_ports
				from lin.start
				until lin.exhausted
				loop
					if not lin.item.is_enemy_controlled (nationality) then
						Result.extend (lin.item)
					end
					lin.forth
				end
			end
				-- Add all major ports to the set
			from game.major_ports.start
			until game.major_ports.after
			loop
				if not game.major_ports.item_for_iteration.is_enemy_controlled (nationality) then
					Result.extend (game.major_ports.item_for_iteration)
				end
				game.major_ports.forth
			end
		end

	arrivable_locations: LINKED_LIST [LOCATION]
			-- The possible locations to which Current can move when
			-- coming into [or back into] the game
		local
			sop: VITP_SEQUENCE_OF_PLAY
		do
			create Result.make
			sop := game.sequence_of_play
			if arrival_turn = sop.turn or returning_turn = sop.turn then
				if nationality = sop.nationality then
					if nationality = game.japanese then

					end
				end
			end
		end

	arrival_location: LOCATION
			-- The port or sea area at which this unit may enter the game
		do
			if nationality = game.japanese and game.yokosuka_navy_yard.nationality = game.japanese then
				Result := game.yokosuka_navy_yard
			elseif nationality = game.us then
				if game.pearl_harbor.nationality = game.us then
					Result := game.pearl_harbor
				elseif game.samoa.nationality = game.us then
					Result := game.samoa
				else
					io.put_string ("ATTACK_UNIT.arrival_location -- put it on US_chart. %N")
					Result := game.still_in_box
				end
			elseif nationality = game.british and game.ceylon.nationality = game.us then
				Result := game.ceylon
			elseif nationality = game.australian then
				Result := game.australia
			else
				Result := game.still_in_box
				check
					should_not_happpen: False
						-- because all nationalities have been checked
				end
			end
		end

	arrival_port: like home_port
			-- The port to which Current is assigned when it comes into
			-- the game during a reinforcement action.
		do
			Result := game.default_port
			if nationality = game.japanese and game.yokosuka_navy_yard.nationality = game.japanese then
				Result := game.yokosuka_navy_yard
			elseif nationality = game.us then
				if game.pearl_harbor.nationality = game.us then
					Result := game.pearl_harbor
				else
					Result := game.samoa
				end
			elseif nationality = game.british then
				if Current = game.victorious and game.pearl_harbor.nationality = game.us then
					Result := game.pearl_harbor
				elseif game.ceylon.nationality = game.us then
					Result := game.ceylon
				end
			elseif nationality = game.australian then
				Result := game.australia
			else
				check
					should_not_happpen: False
						-- because all nationalities have been checked
				end
			end
		end

	arrival_position: like position
			-- The location (latitude/longitude-like coordinates) where Current will enter the game
		do
				-- The following measurements in millimeters were taken from the game board
			if arrival_location = game.Yokosuka_navy_yard then
				Result := [300, 140]
			elseif arrival_location = game.Pearl_Harbor then
				Result := [700, 330]
			elseif arrival_location = game.Samoa then
				Result := [570, 480]
			elseif arrival_location = game.Ceylon then
				Result := [185, 15]
			elseif arrival_location = game.Bay_of_Bengal then
				Result := [10, 370]
			elseif arrival_location = game.Indonesia then
				Result := [130, 350]
			elseif arrival_location = game.Philippines then
				Result := [210, 270]
			elseif arrival_location = game.Australia then
				Result := [240, 470]
			elseif arrival_location = game.Singapore then
				Result := [90, 280]
			elseif arrival_location = game.Coral_sea then
				Result := [370, 520]
			elseif arrival_location = game.US_mandate then
				Result := [500, 500]
			elseif arrival_location = game.Hawaiian_islands then
				Result := [570, 380]
			else
					-- Return its Current position
				Result := [position.longitude, position.latitude]
			end
		end

feature -- Element change

	set_location (a_location: LOCATION)
			-- Move all ships in `task_force' to `a_location'
		require
			is_valid_move: is_valid_move (a_location)
		local
			u: ATTACK_UNIT
		do
			io.put_string ("ATTACK_UNIT.set_location:  " + name.out + " to " + a_location.name + "%N")
			from task_force.start
			until task_force.is_after
			loop
				u := task_force.item
				u.set_location_internal (a_location)
				task_force.forth
			end
		ensure
			location_set: location = a_location
			location_set_for_all:
		end

	set_home_port (a_port: PORT)
			-- Change the unit's `home_port'
		require
			is_valid_base: is_valid_unit_move (a_port)
		do
			home_port := a_port
		end

	set_returning_turn (a_turn: INTEGER)
			-- Set the turn on which Current can reenter the game
		require
			valid_turn: a_turn >= 3 and a_turn <= 9
		do
			returning_turn := a_turn
		end

	set_location_internal (a_location: LOCATION)
			-- Used internally to bypass referential invariant checking
		do
			if location /= a_location then
				is_stable := False
				location.prune (Current)
				location := a_location
				if not a_location.has (Current) then
					a_location.put (Current)
				end
				is_stable := True
			end
		end

	set_target (a_target: ATTACK_UNIT)
			-- Get ready to attack `a_target'
		require
			same_locations: location = a_target.location
		do
			target_imp := a_target
		end

	remove_target
			-- Remove any target from Current sights
		do
			target_imp := Void
		end

feature -- Query

	is_valid_move (a_location: LOCATION): BOOLEAN
			-- Can this {TASK_FORCE} (all units) move to `a_location'?
		do
			Result := True
			from task_force.start
			until task_force.is_after or not Result
			loop
				Result := task_force.item.is_valid_unit_move (a_location)
				task_force.forth
			end
		end

	is_valid_unit_move (a_location: LOCATION): BOOLEAN
			-- Can Current (regardless of any other units that
			-- may be in the `task_force') move to `a_location'?
		do
			io.put_string ("{ATTACK_UNIT}.is_valid_unit_move:  fix to for restricted port %N")
			Result := True
		end

feature -- Access

	position: VITP_POSITION
			-- The position in millimeters (east/west and up/down) from the
			-- top-left of the [logical] VITP world.  That is, the position
			-- of an attack unit is relative to the top-left corner of the
			-- game board which is at point (0, 0).

	unit_size: INTEGER
			-- The size of Current (square).
			-- Assume it is `Ship_size' and redefine for {AIR_UNIT} and
			-- for {AMPHIBIOUS_UNIT}.
		once
			Result := game.initial_ship_size
		end

	corners: ARRAY [VITP_POSITION]
			-- The four corner points of Current (square ships) calculated
			-- from Current's location and `unit_size', starting at the top/
			-- left and going clockwise.
		local
			p: VITP_POSITION
			h: INTEGER
		do
			h := unit_size // 2
			create Result.make_filled (create {VITP_POSITION}, 1, 4)
			create p.set_xy (position.longitude - h, position.latitude - h)
			Result.put (p, 1)
			create p.set_xy (position.longitude + h, position.latitude - h)
			Result.put (p, 2)
			create p.set_xy (position.longitude + unit_size, position.latitude + h)
			Result.put (p, 3)
			create p.set_xy (position.longitude - unit_size, position.latitude + unit_size)
			Result.put (p, 4)
		end

feature -- Element change

	set_position (a_position: like position)
			-- Change the `position' of Current [and all units in `task_force']
		require
			position_exists: a_position /= Void
			is_valid_position: not is_incompatible_position (a_position)
		local
			u: ATTACK_UNIT
		do
			from task_force.start
			until task_force.is_after
			loop
				u := task_force.item
				u.internal_set_position (a_position)
				task_force.forth
			end
		ensure
			position_set: position ~ a_position
		end

feature -- Query

--	is_valid_position (a_position: VITP_POSITION): BOOLEAN
--			-- Is `a_position' valid?  Yes if the position is on the board/table,
--			-- (garanteed by invariant of {VITP_POSITION}), not on an enemy unit,
--			-- and not on a unit of the wrong type (i.e. a submarine cannot join
--			-- a task force.)
--		do
--			Result := not is_on_incompatible_unit (a_position)
--		end

	is_incompatible_position (a_position: VITP_POSITION): BOOLEAN
			-- Yes if repositioning Current to `a_position' would cause Current
			-- to overlap a unit that is incompatible for a `join_force' (e.g.
			-- on a submarine or on an enemy)?
		deferred
		end

	contains_position (a_position: VITP_POSITION): BOOLEAN
			-- Is `a_position' on or in Current?
			-- This feature uses a ray-casting algorithm which determines if the
			-- number of edge crossings made by a ray to the right is odd (inside)
			-- or even (outside).
		local
			pts: like corners
			i, j: INTEGER
		do
			pts := corners
			from
				i := 1
				j := 4
			until i > 4
			loop
					-- Get integer values so algorithm can work.
--				if ( ((pts[i] >= a_position) /= (pts[j] >= a_position)) and
--					(a_position <= (pts[j] - pts[i]) *
--						(a_position - pts[i]) //
--						(pts[j] - pts[i]) + pts[i]) ) then
--							-- Invert Result every time an edge is crossed.
--					Result := not Result
--				end
				j := i
				i := i + 1
			end
		end

	overlaps (a_other: ATTACK_UNIT): BOOLEAN
			-- Does Current occupy any space occupied by a_other
		local
			pts: like corners
			i: INTEGER
		do
			if Current /= a_other then
				pts := corners
				from i := 1
				until i > pts.count or Result
				loop
					Result := a_other.contains_position (pts[i])
					i := i + 1
				end
					-- Check the other way around
				if not Result then
					pts := a_other.corners
					from i := 1
					until i > pts.count or Result
					loop
						Result := contains_position (pts[i])
						i := i + 1
					end
				end
			end
		end

--	is_same_power (a_nationality: NATIONALITY): BOOLEAN
--			-- Is Current the same power (Axis or Allied) as `a_natinality'?
--		do
--			Result := (nationality.is_allied and a_nationality.is_allied) or else
--						(not nationality.is_allied and not a_nationality.is_allied)
--		end

feature -- Basic operations

	join_force (a_other: ATTACK_UNIT)
			-- Join forces with `a_other' as a single `task_force'
		require
			not_submarine: not attached {SUBMARINE} a_other and not attached {SUBMARINE} Current
			lba_implication: attached {AIR_UNIT} task_force.first implies attached {AIR_UNIT} a_other
			other_lba_implication: attached {AIR_UNIT} a_other implies attached {AIR_UNIT} task_force.first
			not_lba_implication: not attached {AIR_UNIT} task_force.first implies not attached {AIR_UNIT} a_other
			not_other_lba_implication: not attached {AIR_UNIT} a_other implies not attached {AIR_UNIT} task_force.first
			not_same_units: not (a_other = Current)
			not_same_task_forces: (is_task_force and a_other.is_task_force) implies
									not (task_force = a_other.task_force)
			not_opposing_sides: not is_opposed (a_other)
			same_location: location = a_other.location
		local
			u: ATTACK_UNIT
			pos: VITP_POSITION
		do
			is_stable := False
				-- Put all units into `a_other's `task_force'
			pos := a_other.position
			from task_force.start
			until task_force.is_after
			loop
				u := task_force.item
--				u.position.set_xy (pos.longitude, pos.latitude)
				a_other.task_force.extend (u)
				task_force.forth
			end
				-- Remove all the units from Current's `task_force'
			task_force.wipe_out
				-- Make to two tasks forces the same one
			set_task_force (a_other.task_force)
			is_stable := True
		ensure
			same_task_forces: task_force = a_other.task_force
			has_multiple_units: task_force.count >= 2
		end

	leave_force
			-- Remove Current from the `task_force' to which it belongs, but only
			-- if there are other ships in the force, and put it in its own.
		require
			is_in_task_force: is_task_force
		local
			u: ATTACK_UNIT
		do
			task_force.prune (Current)
			create task_force.make (game)
			task_force.extend (Current)
		ensure
			not_in_force: not is_task_force
		end

feature -- Status report

	is_task_force: BOOLEAN
			-- Is this unit part of a task force?
		do
			Result := task_force.count > 1
		ensure
			result_implies_in_force: task_force.has (Current)
			result_implies_others: Result implies task_force.count >= 2
		end

	is_in_game: BOOLEAN
			-- Is this unit in the game?  (I.e. not sunk, not still to enter)
		do
			Result := is_at_sea or is_in_port or
					location = game.uncommitted_japanese_location or
					location = game.uncommitted_allied_location
		end

	is_at_sea: BOOLEAN
			-- Is this unit at sea?
		do
			Result := attached {SEA_AREA} location
		end

	is_in_port: BOOLEAN
			-- Is this unit in port?
		do
			Result := attached {PORT} location
		end

	is_movable: BOOLEAN
			-- Can Current move (to sea or back to port) at
			-- this time in the game?
		local
			u: ATTACK_UNIT
		do
			Result := true
			from task_force.start
			until task_force.is_after or not Result
			loop
				u := task_force.item
				Result := u.internal_is_movable
				task_force.forth
			end
		end

	internal_is_movable: BOOLEAN
			-- Can Current move (not the whole `task_force') move at this time?
		local
			sop: VITP_SEQUENCE_OF_PLAY
		do
			sop := game.sequence_of_play
			print ("ATTACK_UNIT.internal_is_movable: %N")
			print ("    sop.is_allied_player = " + sop.is_allied_player.out + "%N")
			print ("    " + name + ".is_allied = " + is_allied.out + "%N")
			print ("    sop.is_japaneses_player = " + sop.is_japanese_player.out + "%N")
			print ("    " + name + ".is_japanese = " + is_japanese.out + "%N")
			print ("    sop.is_patrolling_step = " + sop.is_patrolling_step.out + "%N")
			print ("    " + name + ".is_patrolling = " + is_patrolling.out + "%N")
			Result := (	(sop.is_allied_player and is_allied) or
						(sop.is_japanese_player and is_japanese)) and then
					(	(sop.is_reinforcement_step and is_returning_unit) or
	--					(sop.is_removing_sunk_units_phase and is_sunk) or
	--					(sop.is_returning_disabled_units_stage and is_disabled) or
	--					(sop.is_removing_sunk_units_phase and is_sunk) or
	--					(sop.is_returning_to_port_stage and is_at_sea and not is_sunk) or
						(sop.is_patrolling_step and is_patrolling) or
						(sop.is_raiding_step and is_raiding))
			print (" Result = " + Result.out + "%N")
		end

	is_stable: BOOLEAN
			-- Set to false when pruning and adding for invariant checking
			-- of referential integrity between units and locations

	is_major_power: BOOLEAN
			-- Is Current's `nationality' one of Japanese or US?
		do
			Result := nationality = game.japanese or nationality = game.us
		end

	is_sunk: BOOLEAN
			-- Has this unit been sunk?
		deferred
		end

	is_bottomed: BOOLEAN
			-- Is unit in port with too much damage to sail?
			-- Default is Fasle, so redefine for {SHIP}
		do
			Result := False
		ensure
			implication: Result implies is_in_port
		end

	is_disabled: BOOLEAN
			-- Is the unit disabled?

	is_returning_unit: BOOLEAN
			-- Is the unit returning on this turn?
		do
			Result := returning_turn = game.sequence_of_play.turn
		end

	is_patrollable: BOOLEAN
			-- Can this unit be a patroller for area control purposes?
		deferred
		end

	is_raidable: BOOLEAN
			-- Can this unit be a raider?
		deferred
		end

	is_patrolling: BOOLEAN
			-- Is this unit a patroller (as opposed to a raider)?
		deferred
		end

	is_raiding: BOOLEAN
			-- Is this unit a raider?
		deferred
		end

feature -- Status setting


	set_disabled
			-- Mark Current as `is_disabled'
		do
			is_disabled := True
		end

	set_not_disabled
			-- Mark Current as not `is_disabled'
		do
			is_disabled := False
		end

feature {ATTACK_UNIT} -- Implementation

	internal_set_position (a_position: VITP_POSITION)
			-- Change the `position' of [only] Current
		require
			position_exists: a_position /= Void
		do
			position.set_xy (a_position.longitude, a_position.latitude)
		end

feature {ATTACK_UNIT} -- Implementation

feature -- Comparison

	is_less alias "<" (other: like Current): BOOLEAN
			-- Is current object less than `other'?
		do
				-- Weight the attack, defense, speed factors and compare result
			Result := (relative_value > other.relative_value) or else
						(relative_value = other.relative_value and then name < other.name)
--			Result := name < other.name
		end

feature {NONE} -- Implementation (weighting factors for `relative_value')

	gunnery_weight: INTEGER = 10
	defense_weight: INTEGER = 1
	speed_weight: INTEGER = 1
	airstrike_weight: INTEGER = 10
	bonus_weight: INTEGER = 2

feature {ATTACK_UNIT} -- Implementation

	set_task_force (a_force: like task_force)
			-- Set `task_force' to `a_force'
		require
			has_current: a_force.has (Current)
		do
			task_force.prune (Current)
			task_force := a_force
		ensure
			task_force_assigned: task_force = a_force
			in_task_force: task_force.has (Current)
		end

	remove_task_force
			-- Remove Current from `task_force' and put it in its own `task_force'
		do
			task_force.prune (Current)
			create task_force.make (game)
		end

feature {NONE} -- Implementation (invariant routines)

	same_location_for_all: BOOLEAN
			-- Do all the unit have the same `location'?
		local
			c: CURSOR
		do
			c := task_force.cursor
			Result := true
			if is_task_force then
				from task_force.start
				until task_force.is_after
				loop
					Result := task_force.item.location = location
					task_force.forth
				end
			end
			task_force.go_to (c)
		end

	same_position_for_all: BOOLEAN
			-- Do all the units have the same `location'?
		local
			c: CURSOR
		do
			c := task_force.cursor
			Result := true
			if is_task_force then
				from task_force.start
				until task_force.is_after
				loop
					Result := task_force.item.position ~ position
					task_force.forth
				end
			end
			task_force.go_to (c)
		end

feature {NONE} -- Implementation

	target_imp: detachable ATTACK_UNIT
			-- The unit if any that Current is set to attack



invariant

	location_exists: location /= Void
	task_force_exists: task_force /= Void

--	longitude_big_enough: position.longitude >= {POSITION_CONSTANTS}.Minimum_longitude
--	longitude_small_enough: position.longitude <= {POSITION_CONSTANTS}.Maximum_longitude
--	latitude_big_enough: position.latitude >= {POSITION_CONSTANTS}.Minimum_latitude
--	latitude_small_enough: position.latitude <= {POSITION_CONSTANTS}.Maximum_latitude

	contains_itself: task_force.has (Current)
	valid_arrival_turn: arrival_turn >= 1 and arrival_turn <= 9

	valid_gunnery_factor: gunnery_factor >= 0 and gunnery_factor <= 9
	valid_defense_factor: defense_factor >= 0 and defense_factor <= 9
	valid_speed_factor: speed_factor >= 3 and speed_factor <= 9

--	contains_current: task_force.first = Current
--	contains_only_current: task_force.count = 1

	location_integrity: is_stable implies location.has (Current)
	task_force_integrity: (is_stable and then is_task_force and then task_force.is_stable)
								implies task_force.has (Current)

--	task_force_location_implication: is_stable implies (is_task_force implies same_location_for_all)
--	task_force_position_implication: is_stable implies (is_task_force implies same_position_for_all)

end
