note
	description: "[
		A widget that holds and displays a set of {ATTACK_UNIT}
		moving as a single unit contained in the `task_force'.
		It allows the units to be arrange in various ways.
	]"
	author: "Jimmy J. Johnson"

class
	TASK_FORCE_WIDGET

inherit

	VITP_WIDGET
		rename
			target as task_force
		redefine
			create_interface_objects,
			build_widgets,
--			build_bounding_figure,
			add_actions,
			set_dimming_level,
			set_target,
			show,
			center_on_dot,
			paint,
--			on_pointer_enter,
--			on_pointer_leave,
			wipe_out,
			target_imp
		end

create
	default_create

feature {NONE} -- Initialization

	create_interface_objects
			-- Create attributes
		do
			Precursor {VITP_WIDGET}
			create unit_widgets.make (10)
			column_count := 12
		end

	build_widgets
			-- Set up the widgets in Current.
		do
			Precursor {VITP_WIDGET}
--			build_arrows
--			build_south_arrow
--			build_east_arrow
--			build_west_arrow
--			build_north_east_arrow
--			prune_all (dot)
		end

--	build_bounding_figure
--			-- Add points to the `jj_bounding_figure'.
--			-- The default builds a polygon from the `bounding_box'.
--		do
--			Precursor {VITP_WIDGET}
--				-- Add points to the `jj_bounding_figure' to give it six points
--				-- which can later be set to coincide with points from the
--				-- contained units
--			jj_bounding_figure.extend_point (create {EV_COORDINATE}.make (0, 0))
--			jj_bounding_figure.extend_point (create {EV_COORDINATE}.make (0, 0))
--			jj_bounding_figure.disable_events_sended_to_group
--		end

	add_actions
			-- Add callbacks to Current
		do
			Precursor {VITP_WIDGET}
			pointer_double_press_actions.extend (agent on_double_press)
			jj_defining_figure.pointer_enter_actions.extend (agent on_enter_bounding_figure)
			jj_defining_figure.pointer_leave_actions.extend (agent on_leave_bounding_figure)
--			bounding_figure.pointer_double_press_actions.extend (agent on_pointer_double_pressed_bounding_figure)
			jj_defining_figure.pointer_button_press_actions.extend (agent on_button_press_bounding_figure)
--			bounding_figure.pointer_motion_actions.extend (agent on_pointer_motion_bounding_figure)
--			bounding_figure.pointer_button_release_actions.extend (agent on_button_release_actions_bounding_figure)
		end

feature -- Status report

	is_stacked: BOOLEAN
			-- Are the units to be arranged [with some offset] on top \
			-- of each other?  If not they will be tiled.
			-- Set by `stack' and `tile'

	is_expanded: BOOLEAN
			-- Should the units be overlapped less [greater offset]
			-- when `is_stacked'?
			-- Set by `expand' and `collapse'.

	expected_rows: INTEGER
			-- The number of rows in which Current tries to arrange its widgets

feature -- Status seting

	stack
			-- Stack units on top of each other
		do
			is_stacked := True
			jj_defining_figure.hide
			position_attack_unit_widgets
		end

	tile
			-- Do not stack the units
		do
			is_stacked := False
			jj_defining_figure.show
			position_attack_unit_widgets
		end

	expand
			-- Spead stacked units a little more
		do
			is_expanded := True
			position_attack_unit_widgets
		end

	collapse
			-- Stack the units a little closer together
		do
			is_expanded := False
			position_attack_unit_widgets
		end

feature -- Query

	point_on_bounding_figure (ax, ay: INTEGER): BOOLEAN
			-- Is this point on the `jj_bounding_figure'?
			-- Can be used to prevent actions intended only for Current
		do
			Result := jj_defining_figure.position_on_figure (ax, ay)
		end

	has_widget (a_widget: ATTACK_UNIT_WIDGET): BOOLEAN
			-- Does Current contain `a_widget'?
		do
			Result := unit_widgets.has_item (a_widget)
		end

feature -- Basic operations

	set_target (a_task_force: like task_force)
			-- Change `task_force' to `a_task_force'
		do
			Precursor {VITP_WIDGET} (a_task_force)
			populate
		end

	prune_widget (a_widget: ATTACK_UNIT_WIDGET)
			-- Remove `a_widget' from Current.
		do
			unit_widgets.start
			unit_widgets.prune (a_widget)
		end

	wipe_out
			-- Move all unit_widgets back to the `board_world';
			-- Current removes itself from the `board_world'
		local
			w: ATTACK_UNIT_WIDGET
		do
			unit_widgets.wipe_out
				-- Clean widgets from Current and put back in board
--			check attached {BOARD_VIEW} board_world as bw then
--				from unit_widgets.start
--				until unit_widgets.after
--				loop
--					w := unit_widgets.item_for_iteration
--					prune_all (w)
--					bw.extend (w)
--					unit_widgets.forth
--				end
--				unit_widgets.wipe_out
--				bw.task_force_widgets.remove (task_force)
--				bw.prune_all (Current)
--			end
		end

	populate
			-- Ensure the widgets corresponding to the `task_force' units
			-- and none others are in Current
		local
			w: ATTACK_UNIT_WIDGET
			u: ATTACK_UNIT
--			bw: VITP_WORLD
		do
			check attached vitp_world as bw then
----			check attached {BOARD_TOOL} parent_tool as bt then
----			bw := bt.board_view.world
--				from bw.attack_widgets.start
--				until bw.attack_widgets.after
--				loop
--					w := bw.attack_widgets.item_for_iteration
--					u := w.unit
--					if task_force.has (u) and not unit_widgets.has (u)then
--	--					world.place_widget_at_units_location (w)
--						unit_widgets.extend (w, u)
--						bw.prune_all (w)
--						extend (w)
--					end
--					if not task_force.has (u) and unit_widgets.has (u) then
--						unit_widgets.remove (u)
--						prune_all (w)
--						bw.extend (w)
--					end
--					bw.attack_widgets.forth
--				end
--				if task_force.count = 1 then
--					w := unit_widgets.widget (task_force.first)
--					prune_all (w)
--					bw.extend (w)
--				end
			end
		end

	show
			-- Ensure show is requested for each widget in Current
		do
			from unit_widgets.start
			until unit_widgets.after
			loop
				unit_widgets.item_for_iteration.show
				unit_widgets.forth
			end
		end

	center_on_dot (a_dot: EV_MODEL_DOT)
			-- Place the center of the first ship on `a_dot'
		local
		--	u: ATTACK_UNIT_WIDGET
		do
			check attached {ATTACK_UNIT_WIDGET} unit_widgets.item (task_force.i_th (1)) as u then
				u.center_on_dot (a_dot)
			end
			position_attack_unit_widgets
		end

	position_attack_unit_widgets
			-- Position the widgets in a stack or tiled
		local
			w, prev_w: ATTACK_UNIT_WIDGET
			i: INTEGER
			p: EV_COORDINATE
			r, c, n: INTEGER
			a2: ARRAY2 [detachable ATTACK_UNIT_WIDGET]
		do
			io.put_string ("TASK_FORCE_WIDGET.position_widgets:  %N")
--			populate
				-- Place widgets in stack or tiled
			if is_stacked then
				from
					unit_widgets.start
					prev_w := unit_widgets.item_for_iteration
					unit_widgets.forth
				until unit_widgets.after
				loop
					w := unit_widgets.item_for_iteration
					w.align_midpoints_with_offset (prev_w, 0.1, -0.1)
					prev_w := w
					unit_widgets.forth
				end
			else
				column_count := column_count.min (task_force.count)
				expected_rows := task_force.count // column_count
				if task_force.count \\ column_count > 0 then
					expected_rows := expected_rows + 1
				end
					-- Use `a2' to memoize the widgets as they are accessed
				create a2.make_filled (Void, expected_rows, column_count)
				from
					c := 1
					r := 1
					n := 2
					w := unit_widgets.widget (task_force.i_th (1))
					a2.put (w, 1, 1)
				until n > task_force.count
				loop
						-- Get the widget to place
					w := unit_widgets.widget (task_force.i_th (n))
					c := c + 1
					if c > column_count then
						c := 1
						r := r + 1
					end
						-- Get widget with which to align `w'
					if c = 1 then
						check attached a2.item (r - 1, c) as pw then
							prev_w := pw
							w.align_lefts (prev_w)
							w.align_top_to_others_bottom (prev_w)
						end
					else
						check attached a2.item (r, c - 1) as pw then
							prev_w := pw
							w.align_tops (prev_w)
							w.align_left_to_others_right (prev_w)
						end
					end
					a2.put (w, r, c)
					n := n + 1
				end
			end
				-- Position the `jj_bounding_figure' based on the widget positions
			position_bounding_figure
		end

	position_bounding_figure
			-- Size the box to just fit around the positioned widgets
		local
			w: ATTACK_UNIT_WIDGET
			p: EV_COORDINATE
			bb: like bounding_box
			min_x, max_x: REAL_64
			min_y, max_y: REAL_64
			o_set: REAL_64
		do
				-- Find the extend of the widgets
			min_x := {REAL_32}.Max_value
			max_x := {REAL_32}.Min_value
			min_y := {REAL_32}.Max_value
			max_y := {REAL_32}.Min_value
			from unit_widgets.start
			until unit_widgets.after
			loop
				w := unit_widgets.item_for_iteration
				bb := w.bounding_box
				if bb.upper_left.x_precise < min_x then
					min_x := bb.upper_left.x_precise
				end
				if bb.upper_left.y_precise < min_y then
					min_y := bb.upper_left.y_precise
				end
				if bb.lower_right.x_precise > max_x then
					max_x := bb.lower_right.x_precise
				end
				if bb.lower_right.y_precise > max_y then
					max_y := bb.lower_right.y_precise
				end
				unit_widgets.forth
			end
				-- Position the `jj_bounding_figure' based on the contained widgets
				-- Remember, point_array is a {SPECIAL} indexed from zero.
					-- Set point 1
			o_set := jj_defining_figure.line_width / 2
			w := top_left_unit_widget
			p := jj_defining_figure.point_array.at (0)
			p.set_precise (w.point.x_precise - o_set, w.point.y_precise - o_set)
				-- point 2
			w := top_right_unit_widget
			p := jj_defining_figure.point_array.at (1)
			p.set_precise (w.point.x_precise, w.point.y_precise - o_set)
				-- point 3
			p := jj_defining_figure.point_array.at (2)
			p.set_precise (w.point.x_precise + w.size_values.x_precise + o_set, w.point.y_precise - o_set)
				-- point 4
			w := bottom_right_unit_widget
			p := jj_defining_figure.point_array.at (3)
			p.set_precise (w.point.x_precise + w.size_values.x_precise + o_set, w.point.y_precise + w.size_values.y_precise + o_set)
				-- point 5
			w := last_unit_widget
			p := jj_defining_figure.point_array.at (4)
			p.set_precise (w.point.x_precise + w.size_values.x_precise + o_set, w.point.y_precise + w.size_values.y_precise + o_set)
				-- point 6
			w := bottom_left_unit_widget
			p := jj_defining_figure.point_array.at (5)
			p.set_precise (w.point.x_precise - o_set, w.point.y_precise + w.size_values.y_precise + o_set)
--				-- Also place the text at top left
--			create p.make_precise (min_x, min_y)
--			text_widget.center_on_point (p)
		end

	top_left_unit_widget: ATTACK_UNIT_WIDGET
			-- The widget positioned at the top left when `is_tiled' and the bottom widget
			-- when `is_stacked'.  (It corresponds to the first unit in the `task_force'.)
		do
--			check attached {WIDGET_FACTORY} board_world as bw then
--				Result := bw.attack_widgets.widget (task_force.i_th (1))
--			end
			Result := unit_widgets.widget (task_force.i_th (1))
		end

	top_right_unit_widget: ATTACK_UNIT_WIDGET
			-- The widget positioned at the top-right when `is_tiled' and `is_stacked'.
		do
--			check attached {WIDGET_FACTORY} board_world as bw then
--				if is_stacked then
--					Result := bw.attack_widgets.widget (task_force.i_th (task_force.count))
--				else
--					Result := bw.attack_widgets.widget (task_force.i_th (column_count))
--				end
--			end
			if is_stacked then
				Result := unit_widgets.widget (task_force.i_th (task_force.count))
			else
				Result := unit_widgets.widget (task_force.i_th (column_count))
			end
		end

	bottom_right_unit_widget: ATTACK_UNIT_WIDGET
			-- The widget positioned at the bottom-right.
		local
			r: INTEGER
			i: INTEGER
		do
--			check attached {WIDGET_FACTORY} board_world as bw then
--				if is_stacked then
--					Result := bw.attack_widgets.widget (task_force.i_th (1))
--				else
--					r := task_force.count // column_count
--					i := r * column_count
--					Result := bw.attack_widgets.widget (task_force.i_th (i))
--				end
--			end
			if is_stacked then
				Result := unit_widgets.widget (task_force.i_th (1))
			else
				r := task_force.count // column_count
				i := r * column_count
				Result := unit_widgets.widget (task_force.i_th (i))
			end
		end

	bottom_left_unit_widget: ATTACK_UNIT_WIDGET
			-- The widget positioned at the bottom-left
		local
			i: INTEGER
		do
--			check attached {WIDGET_FACTORY} board_world as bw then
--				if is_stacked then
--					Result := bw.attack_widgets.widget (task_force.i_th (1))
--				else
--					i := (expected_rows - 1) * column_count + 1
--					if i > task_force.count then
--						i := 1
--					end
--					Result := bw.attack_widgets.widget (task_force.i_th (i))
--				end
--			end
			if is_stacked then
				Result := unit_widgets.widget (task_force.i_th (1))
			else
				i := (expected_rows - 1) * column_count + 1
				if i > task_force.count then
					i := 1
				end
				Result := unit_widgets.widget (task_force.i_th (i))
			end
		end

	last_unit_widget: ATTACK_UNIT_WIDGET
			-- The widget at the bottom
		do
--			check attached {WIDGET_FACTORY} board_world as bw then
--				if is_stacked then
--					Result := bw.attack_widgets.widget (task_force.i_th (1))
--				else
--					Result := bw.attack_widgets.widget (task_force.i_th (task_force.count))
--				end
--			end
			if is_stacked then
				Result := unit_widgets.widget (task_force.i_th (1))
			else
				Result := unit_widgets.widget (task_force.i_th (task_force.count))
			end
		end


feature -- Basic operations

	paint
			-- Set the colors for the widgets in Current
		do
			Precursor {VITP_WIDGET}
			from unit_widgets.start
			until unit_widgets.after
			loop
				unit_widgets.item_for_iteration.paint
				unit_widgets.forth
			end
		end

	set_dimming_level (a_level: like dimming_level)
			-- Change the `dimming_level'
		do
--			Precursor {MOVEABLE_WIDGET} (a_level)
			if is_stacked then
				from unit_widgets.start
				until unit_widgets.after
				loop
					unit_widgets.item_for_iteration.set_dimming_level (a_level)
					unit_widgets.forth
				end
			end
		end

	fill_widgets
			-- Nothing to do here.
		do
		end

feature -- Actions

	on_double_press (ax: INTEGER; ay: INTEGER; a_button: INTEGER;
						x_tilt: DOUBLE; y_tilt: DOUBLE; pressure: DOUBLE;
						a_screen_x: INTEGER; a_screen_y: INTEGER)
			-- React to a double press on Current, toggling `is_stacked'.
		do
			if is_stacked then
				tile
			else
				stack
			end
		end

--	on_pointer_enter
--			-- React to the pointer entering Current by showing
--			-- the `jj_bounding_figure' if not `is_stacked'
--		do
--			io.put_string ("TASK_FORCE_WIDGET.on_enter %N")
--			if not is_stacked then
--				jj_bounding_figure.show
--			end
--			Precursor {VITP_WIDGET}
--		end

--	on_pointer_leave
--			-- React to the pointer leaving Current by hiding
--			-- the `jj_bounding_figure'
--		do
--			io.put_string ("TASK_FORCE_WIDGET.on_leave %N")
--			jj_bounding_figure.hide
--			Precursor {VITP_WIDGET}
--		end

	on_enter_bounding_figure
			-- React to the pointer entering the bounding figure
		do
			io.put_string ("TASK_FORCE_WIDGET.on_enter_bounding_figure %N")
			if not is_stacked then
				jj_defining_figure.show
				bring_to_front (jj_defining_figure)
			end
		end

	on_leave_bounding_figure
			-- React to the pointer leaving the bounding figure
		do
			io.put_string ("TASK_FORCE_WIDGET.on_leave_bounding_figure %N")
--			bounding_figure.hide
		end

	on_button_press_bounding_figure (ax: INTEGER; ay: INTEGER; a_button: INTEGER; x_tilt: DOUBLE; y_tilt: DOUBLE;
								pressure: DOUBLE; a_screen_x: INTEGER; a_screen_y: INTEGER)
			-- React to a button press on the `jj_bounding_figure'
		do
			io.put_string ("TASK_FORCE_WIDGET}.on_button_pressed_bounding_figure:  button =  " + a_button.out)
			if a_button = 1 then
				column_count := (column_count - 1).max (1)
				position_widgets
			elseif a_button = 3 then
				column_count := (column_count + 1)
				position_widgets
			else
				io.put_string (" reacting to button ??? %N")
			end
		end

feature {NONE} -- Implementation

	column_count: INTEGER
			-- The number of columns in which Current tries to arrange its widgets

	target_imp: detachable TASK_FORCE
			-- Anchor for `target'

	unit_widgets: VITP_WIDGET_TABLE [ATTACK_UNIT_WIDGET, ATTACK_UNIT]
			-- Table to associate a widget with a unit

invariant

--	in_this_view: not unit_widgets.is_empty implies across unit_widgets as uw all view.has (uw.item_for_iteration) end
--	same_widget_and_unit_counts: attached item_imp implies task_force.count = unit_widgets.count

end
