class EL_USER_INPUT_VALUE
Client examples: CLASS_RENAMING_COMMAND_SHELL ; DUPLICITY_RESTORE ; FILE_TREE_TRANSFORMER_SCRIPT
Get user input value for type G convertable by EL_STRING_CONVERSION_TABLE
note
	description: "Get user input value for type G convertable by ${EL_STRING_CONVERSION_TABLE}"
	author: "Finnian Reilly"
	copyright: "Copyright (c) 2001-2022 Finnian Reilly"
	contact: "finnian at eiffel hyphen loop dot com"
	license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
	date: "2024-09-28 8:01:35 GMT (Saturday 28th September 2024)"
	revision: "9"
		
		class
	EL_USER_INPUT_VALUE [G]
inherit
	ANY
	EL_MODULE_CONVERT_STRING; EL_MODULE_EIFFEL; EL_MODULE_LIO; EL_MODULE_USER_INPUT
	EL_SHARED_CLASS_ID
	EL_PROTOCOL_CONSTANTS
create
	make, make_valid, make_drag_and_drop
convert
	value: {G}
feature {NONE} -- Initialization
	make (a_prompt: READABLE_STRING_GENERAL)
		require
			convertable_type: Convert_string.has_converter ({G})
		do
			create prompt.make_from_general (a_prompt)
			value_type := {G}
			if Convert_string.has_converter (value_type)
				and then attached {like converter} Convert_string.found_item as c
			then
				converter := c
			end
		end
	make_drag_and_drop
		require
			valid_type: Convert_string.has_converter ({G}) and then Convert_string.found_item.is_path
		do
			make ("Drag and drop a ")
			prompt.append_string_general (converter.type_description)
		end
	make_valid (a_prompt, a_invalid_response: READABLE_STRING_GENERAL; a_value_valid: PREDICATE [G])
		do
			invalid_response := a_invalid_response; valid_value := a_value_valid
			make (a_prompt)
		end
feature -- Access
	value: G
		local
			line: ZSTRING; done: BOOLEAN; operands: TUPLE [G]
		do
			escape_pressed := False
			from until done loop
				line := line_input
				if User_input.escape_pressed then
					line := Zero -- we still need to return a value
					escape_pressed := True
				end
				if converter.is_convertible (line) and then attached converter.as_type (line) as v then
					Result := v; operands := [v]
					if line = Zero then
						done := True
					elseif attached {EL_PATH} v as path
						and then path_must_exist and then not path.exists
					then
						lio.put_labeled_string (Bad_input, Does_not_exist #$ [value_description])
						lio.put_new_line
					elseif attached valid_value as test and then test.valid_operands (operands) then
						test.set_operands (operands)
						test.apply
						if test.last_result then
							done := True
						else
							if attached {ZSTRING} invalid_response as template
								and then template.occurrences ('%S') = 1
							then
								lio.put_labeled_string (Bad_input, template  #$ [Result])
								lio.put_new_line
							else
								lio.put_line (invalid_response)
							end
						end
					else
						done := True
					end
				else
					lio.put_labeled_string (Bad_input, Not_convertible #$ [line, value_description])
					lio.put_new_line
				end
			end
		end
	value_description: STRING
		-- Eg. 32-bit integer
		do
			Result := converter.type_description
		end
	value_type: TYPE [G]
feature -- Status query
	is_path_type: BOOLEAN
		do
			Result := Eiffel.field_conforms_to (value_type.type_id, Class_id.EL_PATH)
		end
	is_uri_type: BOOLEAN
		do
			Result := Eiffel.field_conforms_to (value_type.type_id, Class_id.EL_URI_PATH)
		end
	path_must_exist: BOOLEAN
feature -- Status change
	check_existence
		do
			path_must_exist := True
		ensure
			appropriate_type: path_must_exist implies is_path_type
		end
	escape_pressed: BOOLEAN
feature {NONE} -- Implementation
	line_input: ZSTRING
		do
			if is_path_type then
				Result := User_input.path (prompt)
--				Allow base to equal "quit" for URI paths by ensuring preconditions met
				if is_uri_type and then not Result.has_substring (Colon_slash_x2) then
					if not Result.has_first ('/') then
						Result.prepend_character ('/')
					end
					Result.prepend_string_general (Protocol.file + Colon_slash_x2)
				end
			else
				Result := User_input.line (prompt)
			end
			lio.put_new_line
		end
feature {NONE} -- Internal attributes
	converter: EL_READABLE_STRING_GENERAL_TO_TYPE [G]
	invalid_response: READABLE_STRING_GENERAL
	valid_value: detachable PREDICATE [G]
	prompt: ZSTRING
feature {NONE} -- Constants
	Bad_input: STRING = "Bad input"
	Does_not_exist: ZSTRING
		once
			Result := "The %S does not exist"
		end
	Zero: ZSTRING
		once
			Result := "0"
		end
	Not_convertible: ZSTRING
		once
			Result := "[
				"#" is not a valid #
			]"
		end
end