indexing
	namespace: "candidate"
	cluster: "configuration"
	description: "Command class tailored to configuration information"
	original_author: "Justin Finnerty"
	original_date: "Aug 2005"
	current_date: "$Date: 2005/09/28 13:37:35 $"
	current_author: "$Author: finnerty $"
	revision: "$Revision: 2.4 $"
	--  $Log: configuration_option.ge,v $
	--  Revision 2.4  2005/09/28 13:37:35  finnerty
	--  Updated to work with ISE (which HAS_AGENT but no PREDICATE class)
	--
	--  Revision 2.3  2005/09/27 06:12:39  finnerty
	--  Corrected logic error that converted all arguments to lower-case, instead
	--  of only when checking if argument is a 'true' or 'false'.
	--
	--  Revision 2.2  2005/09/03 11:06:12  finnerty
	--  Updated to conform to cursors/containers in the GOBO library and
	--  test programs compile with SE and VE.
	--
	--  Revision 2.1  2005/09/02 07:20:53  finnerty
	--  Renamed configuration_option.e to configuration_option.ge for gepp
	--
	--  Revision 2.0  2005/08/26 23:20:16  finnerty
	--  == alpha version ==
	--
	--  Revision 1.4  2005/08/24 11:56:20  finnerty
	--  Added "tab_label" attribute to allow logically connected options to be
	--  grouped.
	--
	--  Revision 1.3  2005/08/21 11:53:41  finnerty
	--  Alpha 1 version
	--
	--  Revision 1.2  2005/08/16 12:11:13  finnerty
	--  Modified design; options are now derived from OBSERVABLE. Finished (alpha)
	--  coding of all features.
	--
	--  Revision 1.1  2005/08/12 07:06:22  finnerty
	--  Initial abstract data type for a configuration option
	--
class CONFIGURATION_OPTION
	-- Command class tailored to configuration information.

inherit
	OBSERVABLE
#ifdef VE || ISE
		rename
			make as make_observable
		redefine
			is_equal
		select
			is_equal
		end
#else
		redefine
			is_equal
		end
#endif
	HASHABLE
		rename
			is_equal as is_equal_hashable
		end

creation {ANY}
	make

feature {ANY}
	-- queries
	allow_no_override: BOOLEAN
			-- Can value be changed?

	allow_from_environment: BOOLEAN
			-- Do we check the environment for this option?

	default_value: STRING
			-- Default value of option. For boolean options this must be
			-- set as `value' is assigned this when the option is set.

	hash_code: INTEGER is
		do
			Result := name.hash_code
		end

	help: STRING
			-- Default descriptive help text for option.

			-- If an option has `help' or `help_short' as `Void' then no
			-- help will be displayed for that option, although the text will 
			-- appear in the configuration file.

	help_short: STRING
			-- Default brief help text for option
		
			-- If an option has `help' or `help_short' as `Void' then no
			-- help will be displayed for that option, although the text will 
			-- appear in the configuration file.

	is_boolean: BOOLEAN
			-- Is this only T/F?

	is_death: BOOLEAN
			-- Indicate that invoking this option represents a query of
			-- the configuration system and the application should
			-- terminate. Common examples of these options are "-help"
			-- or "-?" which print a help message and exit or
			-- "-configuration" which outputs the current configuration
			-- and exits.

	is_equal (other: like Current): BOOLEAN is
		do
			Result := (hash_code = other.hash_code)
		end

	is_set: BOOLEAN
			-- Was this option used in argument list?
		
	is_valid(an_arg: STRING): BOOLEAN is
			-- Test argument
#ifdef HAS_AGENT
		do
			Result := validator = Void or else validator.item ([an_arg])
		end
#else
		do
			Result := validator = Void or else validator.execute (an_arg)
		end
#endif
	
	name: STRING
			-- Entity used in configuration file and command line. Hence
			-- if name = "pepper", command line would be "-pepper",
			-- environment variable would be "PEPPER" or "PREFIX_PEPPER"
			-- (see `env_prefix' of `CONFIGURATION_MANAGER') and
			-- configuration file would be "<option name='pepper'/>"

			-- From preceding uses it is obvious that case is not
			-- important. For coding simplicity `name' will always be in
			-- lower case.

	no_prefix: BOOLEAN
			-- Is environment variable "PREFIX_PEPPER" not allowed as an
			-- alias for "PEPPER"?

	set_tab_label (a_label: STRING) is
			-- Set the grouping label
		do
			m_tab_label := a_label
		end

	tab_label: STRING is
			-- A grouping label for options
		do
			if m_tab_label = Void then
				Result := "Base"
			else
#ifdef SE
            Result := m_tab_label.twin
#else
				!!Result.make_from_string (m_tab_label)
#endif
			end
		end
	
#ifdef HAS_AGENT
	validator: FUNCTION[ANY,TUPLE[STRING],BOOLEAN]
#else
	validator: AGENT_ARG[STRING,BOOLEAN]
#endif
			-- Strategy for validating input
				
	value: STRING
			-- Final value of option. For boolean options this will be
			-- the value of `default_value' when option is set. For non-boolean
			-- options this will be the argument when given or `default_value'
			-- and when no `default_value' an argument is required.

	frozen write_to (a_stream: KL_STDOUT_FILE) is
			-- Write current configuration option to stream in the
			-- standard file format.
		do
			-- Option tag
			a_stream.put_string ("<option name='")
			a_stream.put_string (name)
			a_stream.put_string ("' bool='")
			a_stream.put_boolean (is_boolean)
			a_stream.put_string ("' no-prefix='")
			a_stream.put_boolean (no_prefix)
			a_stream.put_string ("' allow-no-override='")
			a_stream.put_boolean (allow_no_override)
			a_stream.put_string ("' tab='")
			a_stream.put_string (tab_label)
			a_stream.put_string ("'>")
			a_stream.put_character ('%N')
			if help /= Void and then not help.is_empty then
				-- help tag
				a_stream.put_string ("<help language='en'>")
				a_stream.put_string (help)
				a_stream.put_string ("</help>")
				a_stream.put_character ('%N')
			end
			if help_short /= Void and then not help_short.is_empty then
				-- short(help) tag
				a_stream.put_string ("<short language='en'>")
				a_stream.put_string (help_short)
				a_stream.put_string ("</short>")
				a_stream.put_character ('%N')
			end
			if default_value /= Void then
				-- default tag
				a_stream.put_string ("<default>")
				a_stream.put_string (default_value)
				a_stream.put_string ("</default>")
				a_stream.put_character ('%N')
			end
			if value /= Void then
				-- value tag
				a_stream.put_string ("<value>")
				a_stream.put_string (value)
				a_stream.put_string ("</value>")
				a_stream.put_character ('%N')
			end
			-- closing tag
			a_stream.put_string ("</option>")
			a_stream.put_character ('%N')
		end

feature {ANY}
	-- procedures
	set_allow_environment is
		do
			allow_from_environment := True
		end

	set_default_value (an_arg: STRING) is
			-- Set default_value from `an_arg'
		require
			is_valid (an_arg)
		do
#ifdef SE
			default_value := an_arg.twin
#else
			!!default_value.make_from_string (an_arg)
#endif
		ensure
			default_value.is_equal (an_arg)
		end

	set_is_death is
		do
			is_death := True
		end

	set_is_boolean is
		do
			is_boolean := True
		end

	set_no_prefix is
		do
			no_prefix := True
		end

	set_override is
			-- Stop changes
		do
			allow_no_override := True
		ensure
			allow_no_override = True
		end

	set_to_default is
			-- Set value from `default'
		require
			not allow_no_override
			is_valid (default_value)
		do
			value := default_value
		ensure
			value = default_value
		end

	set_is_set is
			-- Indicate option was in argument list.
		do
			is_set := True
		end

#ifdef HAS_AGENT
	set_validator (a_validator: FUNCTION[ANY,TUPLE[STRING],BOOLEAN]) is
#else
   set_validator (a_validator: AGENT_ARG[STRING,BOOLEAN]) is
	   require
			a_validator.is_executable
#endif
		do
			validator := a_validator
		end

	set_value (an_arg: STRING) is
			-- Set value from `an_arg'
		require
			not allow_no_override
			an_arg /= Void
			is_valid (an_arg)
#ifdef VE
			is_boolean implies an_arg.as_lower.is_boolean
#else
			is_boolean implies an_arg.is_boolean
#endif
		do
			if is_boolean then
				-- Treat an_arg as BOOLEAN
#ifdef VE
				if an_arg.as_lower.to_boolean then
#else
				if an_arg.to_boolean then
#endif
					set_to_default
				else
					value := Void
				end
			else
#ifdef SE
				value := an_arg.twin
#else
				!!value.make_from_string (an_arg)
#endif
			end
			notify
		ensure
			not is_boolean implies value.is_equal (an_arg)
		end

feature {CONFIGURATION_OPTION}
	-- heirarchy implementation

	make(a_name, a_help, a_shorthelp: STRING) is
			-- Create an option!
		require
			a_name /= Void and then not a_name.is_empty
		do
#ifdef SE
         !LINKED_LIST[OBSERVER[CONFIGURATION_OPTION]]!observers.make
#else
			make_observable
#endif
			name := a_name.as_lower
			default_value := Void
#ifdef SE
			help := a_help.twin
			help_short := a_shorthelp.twin
#else
			!!help.make_from_string (a_help)
			!!help_short.make_from_string (a_shorthelp)
#endif
			allow_no_override := False
			is_boolean := False
			is_death := False
			allow_from_environment := False
			no_prefix := False
			validator := Void
		end
feature {NONE}
	-- Private attribute
	m_tab_label: STRING
			-- A grouping label for options
invariant
	Need_default: is_boolean and not is_death implies default_value /= Void
	-- config_man.status = Continue and not is_boolean implies value /= Void
end -- class CONFIGURATION_OPTION

