note
	description: "[
		Class that enable to set basic configuration, application environment, core modules and themes.
		]"
	date: "$Date: 2015-02-13 13:08:13 +0100 (ven., 13 févr. 2015) $"
	revision: "$Revision: 96616 $"

deferred class
	CMS_SETUP

inherit
	REFACTORING_HELPER

feature {NONE} -- Initialization	

	initialize
		local
			l_url: like site_url
		do
			site_location := environment.path

				--| Site id, used to identified a site, this could be set to a uuid, or else
			site_id := text_item_or_default ("site.id", "_EWF_CMS_NO_ID_")

				-- Site url: optional, but ending with a slash
			l_url := string_8_item ("site_url")
			if l_url /= Void and then not l_url.is_empty then
				if l_url [l_url.count] /= '/' then
					l_url := l_url + "/"
				end
			end
			site_url := l_url

				-- Site name
			site_name := text_item_or_default ("site.name", "EWF::CMS")

				-- Site email for any internal notification
				-- Can be also used to precise the "From:" value for email.
			site_email := text_item_or_default ("site.email", "webmaster")


				-- Location for public files
			if attached text_item ("files-dir") as s then
				create files_location.make_from_string (s)
			else
				files_location := site_location.extended ("files")
			end

				-- Location for modules folders.
			if attached text_item ("modules-dir") as s then
				create modules_location.make_from_string (s)
			else
				modules_location := environment.modules_path
			end

				-- Location for themes folders.
			if attached text_item ("themes-dir") as s then
				create themes_location.make_from_string (s)
			else
				themes_location := environment.themes_path
			end

				-- Selected theme's name
			theme_name := text_item_or_default ("theme", "default")

			debug ("refactor_fixme")
				fixme ("Review export clause for configuration and environment")
			end

			theme_location := themes_location.extended (theme_name)
		end

feature -- Access

	environment: CMS_ENVIRONMENT
			-- CMS environment.	

	layout: CMS_ENVIRONMENT
			-- CMS environment.
		obsolete "use `environment' [april-2015]"
		do
			Result := environment
		end

feature {CMS_API} -- API Access		

	enabled_modules: CMS_MODULE_COLLECTION
			-- List of enabled modules.
		local
			l_module: CMS_MODULE
		do
			create Result.make (modules.count)
			across
				modules as ic
			loop
				l_module := ic.item
				update_module_status_from_configuration (l_module)
				if l_module.is_enabled then
					Result.extend (l_module)
				end
			end
			across
				Result as ic
			loop
				l_module := ic.item
				update_module_status_within (l_module, Result)
				if not l_module.is_enabled then
					Result.remove (l_module)
				end
			end
		ensure
			only_enabled_modules: across Result as ic all ic.item.is_enabled end
		end

feature {CMS_MODULE, CMS_API, CMS_SETUP_ACCESS} -- Restricted access

	modules: CMS_MODULE_COLLECTION
			-- List of available modules.
		deferred
		end

feature {NONE} -- Implementation: update		

	update_module_status_within (a_module: CMS_MODULE; a_collection: CMS_MODULE_COLLECTION)
			-- Update status of module `a_module', taking into account its dependencies within the collection `a_collection'.
		require
			a_module_is_enabled: a_module.is_enabled
		do
			if attached a_module.dependencies as deps then
				across
					deps as ic
				until
					not a_module.is_enabled
				loop
					if ic.item.is_required then
						if
							attached a_collection.item (ic.item.module_type) as mod and then
							mod.is_enabled
						then
							update_module_status_within (mod, a_collection)
						else
								--| dependency not found or disabled
							a_module.disable
						end
					end
				end
			end
		end

	update_module_status_from_configuration (m: CMS_MODULE)
			-- Update status of module `m' according to configuration.
		local
			b: BOOLEAN
			dft: BOOLEAN
		do
				-- By default enabled.
			if false and attached text_item ("modules.*") as l_mod_status then
				dft := l_mod_status.is_case_insensitive_equal_general ("on")
			else
				dft := True
			end
			if attached text_item ("modules." + m.name) as l_mod_status then
				b := l_mod_status.is_case_insensitive_equal_general ("on")
			else
				b := dft
			end
			if b then
				m.enable
			else
				m.disable
			end
		end

feature -- Access: Site

	site_id: READABLE_STRING_8
			-- String identifying current CMS.
			-- This could be used in webform, for cookie name, ...

	site_name: READABLE_STRING_32
			-- Name of the site.

	site_email: READABLE_STRING_8
			-- Admin email address for the site.
			-- Mainly used for internal notification.

	site_url: detachable READABLE_STRING_8
			-- Optional url of current CMS site.

	front_page_path: detachable READABLE_STRING_8
			-- Optional path defining the front page.
			-- By default "" or "/".

feature -- Query

	text_item (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
			-- Configuration value associated with `a_name', if any.
		deferred
		end

	text_list_item (a_name: READABLE_STRING_GENERAL): detachable LIST [READABLE_STRING_32]
			-- Configuration values associated with `a_name', if any.
		deferred
		end

	text_table_item (a_name: READABLE_STRING_GENERAL): detachable STRING_TABLE [READABLE_STRING_32]
			-- Configuration indexed values associated with `a_name', if any.
		deferred
		end

	text_item_or_default (a_name: READABLE_STRING_GENERAL; a_default_value: READABLE_STRING_GENERAL): READABLE_STRING_32
			-- `text_item' associated with `a_name' or if none, `a_default_value'.
		do
			if attached text_item (a_name) as v then
				Result := v
			else
				Result := a_default_value.as_string_32
			end
		end

	string_8_item (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_8
			-- Configuration value associated with `a_name', if any.
		deferred
		end

feature -- Access: Theme

	site_location: PATH
			-- Path to CMS site root dir.

	files_location: PATH
			-- Path to public "files" dir.			

	modules_location: PATH
			-- Path to modules.	

	themes_location: PATH
			-- Path to themes.

	theme_location: PATH
			-- Path to a active theme.

	theme_information_location: PATH
			-- Active theme informations.
		do
			Result := theme_location.extended ("theme.info")
		end

	theme_name: READABLE_STRING_32
			-- theme name.

feature -- Access

	mailer: NOTIFICATION_MAILER
			-- Email processor.
		deferred
		end

feature -- Access: storage

	storage_drivers: STRING_TABLE [CMS_STORAGE_BUILDER]
			-- Table of available storage drivers.
			-- i.e: mysql, sqlite, ...
		deferred
		end

	storage (a_error_handler: ERROR_HANDLER): detachable CMS_STORAGE
			-- CMS Storage object defined according to the configuration or default.
			-- Use `a_error_handler' to get eventual error information occurred during the storage
			-- initialization.
		local
			retried: BOOLEAN
			l_message: STRING
		do
			if not retried then
				to_implement ("Refactor database setup")
				if
					attached (create {APPLICATION_JSON_CONFIGURATION_HELPER}).new_database_configuration (environment.application_config_path) as l_database_config and then
					attached storage_drivers.item (l_database_config.driver) as l_builder
				then
					Result := l_builder.storage (Current, a_error_handler)
				end
			else
				to_implement ("Workaround code, persistence layer does not implement yet this kind of error handling.")
					-- error handling.
				create l_message.make (1024)
				if attached ((create {EXCEPTION_MANAGER}).last_exception) as l_exception then
					if attached l_exception.description as l_description then
						l_message.append (l_description.as_string_32)
						l_message.append ("%N%N")
					elseif attached l_exception.trace as l_trace then
						l_message.append (l_trace)
						l_message.append ("%N%N")
					else
						l_message.append (l_exception.out)
						l_message.append ("%N%N")
					end
				else
					l_message.append ("The application crash without available information")
					l_message.append ("%N%N")
				end
				a_error_handler.add_custom_error (0, " Database Connection ", l_message)
			end
		rescue
			retried := True
			retry
		end

feature -- Status Report: Modules

	module_registered (m: CMS_MODULE): BOOLEAN
			-- Is the module `m' registered?
		do
			Result := modules.has (m)
		end

	module_with_same_type_registered (m: CMS_MODULE): BOOLEAN
			-- Is there a module `m' already registered with the same type?
		do
			Result := modules.has_module_with_same_type (m)
		end

feature -- Element change

	register_module (m: CMS_MODULE)
			-- Add module `m' to `modules'.
		require
			module_not_registered: not module_registered (m)
			no_module_with_same_type_registered: not module_with_same_type_registered (m)
		deferred
		ensure
			module_registered: module_registered (m)
		end

note
	copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
	license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end
