indexing
	cluster: "demangler"
	namespace: "candidate"
	description: "Paginate etc text."
	original_author: "Justin Finnerty"
	original_date: "July 2005"
	current_date: "$Date: 2005/09/27 06:14:47 $"
	current_author: "$Author: finnerty $"
	revision: "$Revision: 2.1 $"	
	-- $Log: text_formatter.e,v $
	-- Revision 2.1  2005/09/27 06:14:47  finnerty
	-- Updated to use GOBO and work with SE and VE
	--
	-- Revision 2.0  2005/08/26 23:31:39  finnerty
	-- == alpha version ==
	--
	-- Revision 1.2  2005/08/24 12:38:17  finnerty
	-- Upgraded class to handle STRING and UNICODE_STRING objects equally.
	-- Added feature to split a string using an arbitrary character.
	--
	-- Revision 1.1  2005/08/21 11:56:21  finnerty
	-- Alpha 1 version
	--
	--

class TEXT_FORMATTER
	-- Left adjusted, ragged right, fixed width formatted output.

creation {ANY}
	make_text_formatter
	
feature {ANY}
	-- Access
	input_stream: KI_TEXT_INPUT_STREAM
			-- Stream for user input.

	output_stream: KI_TEXT_OUTPUT_STREAM
			-- Stream for text output.

	width: INTEGER
			-- The width of the output text.

	cursor: INTEGER
			-- The current position along a line of the output text.
feature {ANY}
	-- Output procedures
	put_new_line is
			-- Insert line break
		do
			output_stream.put_new_line
			cursor := 0
		end
	
	put_string (a_string: STRING) is
			-- Format a string to be `width' characters wide (with 
			-- folding)
		local
			lll, llu: INTEGER
		do
			from
				lll := 1
				llu := a_string.count.min(lll + width - cursor)
			variant
				a_string.count + 1 - lll
			until
				(llu - lll + cursor) < width
			loop
				debug
					output_stream.put_string ("["+lll.out+"]["+llu.out+"]")
				end
				if a_string.item (llu) = '%U' then
					from
					variant
						llu - lll
					until
						a_string.item (llu) /= '%U' or else
						llu = lll
					loop
						llu := llu - 1
					end
				else
					from
					variant
						llu - lll
					until
						a_string.item (llu) = ' ' or else
						llu = lll
					loop
						llu := llu - 1
					end
				end
				if llu = lll then
					llu := a_string.count.min(lll + width)
				end
				output_stream.put_line (a_string.substring (lll, llu))
				cursor := 0
				lll := llu + 1
				llu := a_string.count.min(lll + width)
			end
			debug
				output_stream.put_string ("["+lll.out+"]["+llu.out+">")
			end
			output_stream.put_string (a_string.substring (lll, llu))
			cursor := llu - lll
		end

	put_unicode_string (a_string: UC_STRING) is
			-- Format a string to be `width' characters wide (with 
			-- folding)
		do
			put_string (a_string.to_utf8)
		end

feature {ANY}
	-- User Interface methods
	pause (a_string: UC_STRING) is
			-- Print `a_string' and wait for any user input.
		do
			put_unicode_string (a_string)
			output_stream.flush
			input_stream.read_character
		end
			
	query (a_title, a_query, a_result_list: UC_STRING): INTEGER is
			-- Print `a_title' and `a_query' and wait for any user 
			-- input. If input is not in `a_valid' print error message 
			-- and reprint `a_query'. If input is in `a_valid' return 
			-- the character.
		local
			l_index, l_result: INTEGER
			l_list: DS_LIST[UC_STRING]
			l_colon: UC_CHARACTER
		do
			!!l_colon.make_from_character (':')
			l_list := split (a_query, l_colon)
			put_unicode_string (a_title)
			put_new_line
			from
				Result := 0
			until
				Result /= 0
			loop
				put_string ("Options are:")
				put_new_line
				from
					l_index := 1
				variant
					l_list.count - l_index + 1
				until
					l_list.count < l_index
				loop
					put_string (" (" + l_index.out + ") ")
					put_unicode_string (l_list.item (l_index))
					if l_index - l_list.count = 1 then
						put_string (" or")
					end
					put_new_line
					l_index := l_index + 1
				end
				put_string (" Choice - ")
				output_stream.flush
				input_stream.read_line
				if input_stream.last_string.is_integer then
					l_result := input_stream.last_string.to_integer
					if l_result <= a_result_list.count and then
						l_result >= 1 then
						Result := a_result_list.item_code (l_result)
					end
				end
				if Result = 0 then
					put_string ("Invalid index should be in range (1, "+l_list.count.out+").")
					put_new_line
				end
			end
		end

feature {ANY}
	-- String processing
	split (a_string: UC_STRING; a_char: UC_CHARACTER): DS_LIST[UC_STRING] is
			-- Split string into a list using a_char
		local
			lll, llu: INTEGER
		do
			!DS_LINKED_LIST[UC_STRING]!Result.make
			from
				lll := 1
				llu := 1
			until
				llu = 0 or else
				llu >= a_string.count
			loop
				llu := a_string.index_of_unicode (a_char, lll)
				if llu /= 0 then
					if lll /= llu then
						Result.put_last (a_string.substring (lll, llu - 1))
					end
					lll := llu + 1
					llu := llu + 1
				end
			end
			if lll /= a_string.count then
				Result.put_last (a_string.substring (lll, a_string.count))
			end
		end

feature {NONE}
	-- Creation procedures
	make_text_formatter (a_width: INTEGER; a_out_stream: KI_TEXT_OUTPUT_STREAM; a_in_stream: KI_TEXT_INPUT_STREAM) is
			-- Make formatter with spec width and given streams
		do
			width := a_width
			output_stream := a_out_stream
			input_stream := a_in_stream
		end

	make_std_text_formatter (a_width: INTEGER) is
			-- Make formatter with spec width and standard streams
		local
			l_streams: KL_SHARED_STANDARD_FILES
		do
			!!l_streams
			width := a_width
			output_stream := l_streams.std.output
			input_stream := l_streams.std.input
		end
invariant
		Valid_streams: input_stream /= Void and output_stream /= Void
end -- class TEXT_FORMATTER
