note
	description: "Manager for documents."
	legal: "See notice at end of class."
	status: "See notice at end of class."
	date: "$Date$"
	revision: "$Revision$"

class
	DOCUMENT_MANAGER

inherit
	SHARED_OBJECTS
	
create
	make

feature -- Creation

	make
			-- Create manager
		do
			create documents.make (10)
			documents.compare_objects
			create modified_documents.make (5)
			modified_documents.compare_objects
			counter := 1
			create editor_panels.make (2)
		end

feature -- Schema	
		
	schema: DOCUMENT_SCHEMA
			-- The currently assigned schema	
		
	initialize_schema (schema_filename: STRING)
			-- Initialize `schema' with `a_filename'
		require
			schema_file_not_void: schema_filename /= Void
			schema_is_file: (create {PLAIN_TEXT_FILE}.make (schema_filename)).exists
		do
			create schema.make_from_schema_file (schema_filename)
			if schema.is_valid then
				set_schema (schema)				
			else
				shared_error_reporter.set_error (create {ERROR}.make (schema_filename + " is invalid."))
				set_schema (Void)				
			end
		end
		
	set_schema (a_schema: DOCUMENT_SCHEMA)
			-- Set `schema' to 'a_name'
		do
			schema := a_schema
			if shared_constants.application_constants.is_gui_mode then				
				application_window.render_schema	
			end
		ensure
			schema_set: schema = a_schema
		end		
		
	has_schema: BOOLEAN
			-- Is a valid schema loaded?
		do
			Result := schema /= Void	
		end	
		
	remove_schema
			-- Remove schema
		do
			schema := Void	
		end		

feature -- HTML Stylesheet

	stylesheet: PLAIN_TEXT_FILE
			-- The currently assigned stylesheet	
		
	has_stylesheet: BOOLEAN
			-- Is a stylesheet loaded?
		do
			Result := stylesheet /= Void	
		end	
		
	initialize_stylesheet (stylesheet_filename: STRING)
			-- Initialize `stylesheet' with `a_filename'
		require
			stylesheet_file_not_void: stylesheet_filename /= Void
			stylesheet_is_file: (create {PLAIN_TEXT_FILE}.make (stylesheet_filename)).exists
		do
			create stylesheet.make (stylesheet_filename)
		end	

	remove_stylesheet
			-- Remove stylesheet
		do
			stylesheet := Void	
		end		
		
feature -- Document Manipulation

	create_document
			-- Create new document
		local
			document: DOCUMENT
		do
			create document.make_new (new_name)
			add_document (document, True)
		end		

	open_document
			-- Called by `select_actions' of `open_xml_menu_item'.
		local
			l_open_dialog: EV_FILE_OPEN_DIALOG
		do
			create l_open_dialog
			l_open_dialog.show_modal_to_window (parent_window)
			if l_open_dialog.selected_button.is_equal ((create {EV_DIALOG_CONSTANTS}).ev_open) then
				load_document_from_file (l_open_dialog.file_name)
			end
		end	

	close_document
			-- 
		local
			l_dlg: EV_QUESTION_DIALOG
			l_doc_name: STRING
		do
			create l_dlg
			l_dlg.set_text ("Would you like to save this document?")
			l_dlg.show_modal_to_window (application_window)
			if l_dlg.selected_button.is_equal ((create {EV_DIALOG_CONSTANTS}).ev_yes) then
				save_document
			end
			l_doc_name ?= notebook.selected_item.data
			documents.remove (l_doc_name)
			notebook.prune (current_editor.widget)
			editor_panels.remove (l_doc_name)
		end	

	load_document_from_file (a_filename: STRING)
			-- Load a document with `a_filename'
		require
			filename_not_void: a_filename /= Void
			filename_not_empty: not a_filename.is_empty
		local
			l_util: UTILITY_FUNCTIONS
			l_file_type: STRING
			l_name: STRING
		do
			create l_util
			l_file_type := l_util.file_type (a_filename)
			l_name := a_filename
			l_name.replace_substring_all ("\", "/")
			if shared_constants.application_constants.allowed_file_types.has (l_file_type) then
				l_file_type.to_upper
				if (create {EV_ENVIRONMENT}).supported_image_formats.has (l_file_type) then
					load_image_document (a_filename)
				else				
					load_text_document (l_name)
					on_document_selected
				end
			else
				load_text_document (l_name)
				on_document_selected
			end
		end

	load_text_document (a_filename: STRING)
			-- Load document as plain text file
		require
			no_forward_slash: not a_filename.has ('\')
		local
			document: DOCUMENT
			file: PLAIN_TEXT_FILE
		do
			if documents.has (a_filename) then
				document := documents.item (a_filename)
				notebook.select_item (editor_panels.item (document.name).widget)
			else
				create file.make (a_filename)
				if file /= Void and then file.exists then
					create document.make_from_file (file)
					add_document (document, True)
					current_editor.load_text (document.text)
				end
			end
		end
		
	load_image_document (a_filename: STRING)
			-- Load image
		local
		do
			--not implemented
		end

	save_document
			-- Called by `select_actions' of `save_xml_menu_item'.
		do
			current_document.set_text (current_editor.text)
			current_document.save
		end				
		
	save_all
			-- Save all opened documents
		do
--			from
--				notebook.start
--			until
--				notebook.after
--			loop
--				if current_document = documents.item_for_iteration  then
--					documents.item_for_iteration.set_text (text)
--				end
--				documents.item_for_iteration.save
--				documents.forth
--			end
		end		

	current_editor: DOCUMENT_EDITOR
			--
		local
			l_doc_name: STRING
		do
			if has_open_document then
				l_doc_name ?= notebook.selected_item.data
				if l_doc_name /= Void then
					Result := editor_panels.item (l_doc_name)
				end			
			end
		end	

	current_document: DOCUMENT
			-- Currently open document in notebook
		local
			l_doc_name: STRING
		do
			if has_open_document then
				l_doc_name ?= notebook.selected_item.data
				if l_doc_name /= Void then
					Result := documents.item (l_doc_name)
				end
			end
		end

feature {DOCUMENT_PROJECT, XML_TABLE_OF_CONTENTS, DOCUMENT_EDITOR, TABLE_OF_CONTENTS} -- Document Manipulation

	add_document (a_doc: DOCUMENT; display: BOOLEAN)
			-- Add a document
		require
			a_doc_not_void: a_doc /= Void
		local
			l_string: STRING
			l_editor: DOCUMENT_EDITOR
		do
			if not documents.has (a_doc.name) then
				l_string := a_doc.name
				l_string.replace_substring_all ("\", "/")
				documents.extend (a_doc, l_string)
			end
			
			if display then
				create l_editor.make
				l_editor.add_cursor_observer (application_window)
				l_editor.add_edition_observer (application_window)
				l_editor.add_selection_observer (application_window)
				editor_panels.extend (l_editor, l_string)
				notebook.extend (l_editor.widget)
				notebook.set_item_text (l_editor.widget, a_doc.short_name (l_string))
				l_editor.widget.set_data (l_string)
				notebook.select_item (l_editor.widget)
				l_editor.load_text (a_doc.text)
			end			
		end

	remove_document (a_doc: DOCUMENT)
			-- Remove document
		require
			a_doc_not_void: a_doc /= Void
		local
			l_name: STRING
		do
			l_name := a_doc.name.twin
			l_name.replace_substring_all ("\", "/")
			if documents.has (l_name) then
				documents.remove (l_name)
			end
		end		
	
feature -- Access

	notebook: EV_NOTEBOOK
			-- 
		once
			Result := application_window.editor_notebook
			Result.selection_actions.extend (agent on_document_selected)
		end

	documents: HASH_TABLE [DOCUMENT, STRING]
			-- Loaded documents		
			
	editor_panels: HASH_TABLE [DOCUMENT_EDITOR, STRING]
			-- Loaded document editor panels

	synchronizer: DOCUMENT_SYNCHRONIZER
			-- Used to synchronize documents between views
		once
			create Result		
		end		

feature -- Query

	hash_code: INTEGER
			-- Hash code
		do
			Result := counter
			counter := counter + 1
		end
		
	document_by_name (a_name: STRING): DOCUMENT
			-- Retrieve document with 'a_name', Void otherwise?  
		require
			a_name_not_void: a_name /= Void
		local
			l_name: STRING
		do
			l_name := a_name.twin
			l_name.replace_substring_all ("\", "/")
			if documents.has (l_name) then
				Result := documents.item (l_name)
			end
		end	

	has_open_document: BOOLEAN
			-- 
		do
			Result := not notebook.is_empty
		end	

feature -- Status Setting	
	
	add_modified_document (a_doc: DOCUMENT)
			-- Add `a_doc' to list of modifed documents
		require
			doc_not_void : a_doc /= Void
		do
			if not modified_documents.has (a_doc) then
				modified_documents.extend (a_doc)
				has_modified := True
			end
		end

feature -- Events

	on_document_selected
			-- Document was changed
		do		
			if has_open_document then
				application_window.set_title (current_document.name)
				if current_document /= Void then
					shared_web_browser.set_document (current_document)
				end
			end
		end

feature {NONE} -- Observer Pattern

	update
			-- Update
		do			
		end		

feature {NONE} -- Implementation

	parent_window: DOC_BUILDER_WINDOW
			-- Application window
		once
			Result := Application_window
		end		

	counter: INTEGER
			-- Rolling counter for creating new documents

	has_modified: BOOLEAN
			-- Has Current any new modifed files?

	modified_documents: ARRAYED_LIST [DOCUMENT]
			-- List of documents which have been modified
			
	new_name: STRING
			-- Return a new and unique name for a new document
		do
			create Result.make_from_string ("Document " + counter.out)
			counter := counter + 1
		ensure
			result_not_void: Result /= Void
		end		

invariant
	has_documents: documents /= Void

note
	copyright:	"Copyright (c) 1984-2006, Eiffel Software"
	license:	"GPL version 2 (see http://www.eiffel.com/licensing/gpl.txt)"
	licensing_options:	"http://www.eiffel.com/licensing"
	copying: "[
			This file is part of Eiffel Software's Eiffel Development Environment.
			
			Eiffel Software's Eiffel Development Environment is free
			software; you can redistribute it and/or modify it under
			the terms of the GNU General Public License as published
			by the Free Software Foundation, version 2 of the License
			(available at the URL listed under "license" above).
			
			Eiffel Software's Eiffel Development Environment is
			distributed in the hope that it will be useful,	but
			WITHOUT ANY WARRANTY; without even the implied warranty
			of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
			See the	GNU General Public License for more details.
			
			You should have received a copy of the GNU General Public
			License along with Eiffel Software's Eiffel Development
			Environment; if not, write to the Free Software Foundation,
			Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
		]"
	source: "[
			 Eiffel Software
			 356 Storke Road, Goleta, CA 93117 USA
			 Telephone 805-685-1006, Fax 805-685-6869
			 Website http://www.eiffel.com
			 Customer support http://support.eiffel.com
		]"
end -- class DOCUMENT_MANAGER