//===========================================================================//
// File:     notation.hpp                                                    //
// Title:    Declaration of NotationFile classes.                            //
// Project:  Munga                                                           //
// Author:   Ken Olsen                                                       //
// Purpose:  Provide general purpose access to data stored in a formatted    //
//           text file.                                                      //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 01/06/95  KEO  Converted from Tool Architecture I.                        //
// 02/07/95  KEO  Add AppendEntry methods.                                   //
// 02/17/95  KEO  Change page and entry lists to make nomenclature.          //
// 03/24/95  KEO  Add methods to read and write text in memory.              //
// 03/31/95  KEO  Add methods for lab only mark.                             //
// 05/23/95  KEO  Add getfilename, setpage and appendpage.                   //
// 11/11/95  KEO  Add operation modes and correct small bugs.                //
// 04/01/97  GAH  Added "DeleteAllPages" method.									  //
//---------------------------------------------------------------------------//
// Copyright (c) 1994-1995 Virtual World Entertainment, Inc.                 //
// Copyright (c) 1996-1997 Fasa Interactive Technologies, Inc.               //
//   All rights reserved worldwide.                                          //
// This unpublished source code is PROPRIETARY and CONFIDENTIAL.             //
//===========================================================================//

#pragma once

#include "Stuff.hpp"
#include "Scalar.hpp"
#include "FileStream.hpp"
#include "Tree.hpp"

namespace Stuff {

	class NotationFile;
	class Page;
	class Note;

	class Macro
	{
	public:
		MString m_replacement;
		bool m_inUse;

		explicit Macro(MString *replace);

		static void AddValue(
			void *macro_tree,
			const char* name,
			const char* value
		);

		static void ReplaceMacros(
			void *macro_tree,
			const char *buffer,
			char *new_buf,
			int new_buf_size
		);

		void TestInstance() {}
	};

	//=======================================================================
	// Format of notation file:
	//
	// !include file1.txt
	// !include=file1a.txt
	// !include "file2.txt"
	//
	// !example_macro=Field2Data
	//
	// // comment
	//
	// [RecordName]	// comment
	// FieldName=FieldData
	// Field2Name=Field2Data
	// Field3Name=test.ini
	//
	// [Record2Name]
	// FieldName=FieldData
	// Field4Name=$(example_macro)
	// Field5Name={
	//  [Record3Name]
	//  Field6Name=Whatever
	// }
	//
	// /* [Page3Name]
	// Field7Name=Uhhm
	// Field8Name=Uhhh */
	// ...
	//
	//=======================================================================

	//##########################################################################
	//##############    NotationFile    ########################################
	//##########################################################################

	class NotationFile
		#if defined(_ARMOR)
			: public Stuff::Signature
		#endif
	{
		friend class Page;
		friend class Note;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructor/Destructors
	//
	public:
		enum Type {
			Standard,
			NonEmpty,
			Raw
		};

		NotationFile(
			const char *file_name,
			Type type=Standard,
			bool preserve_case=false
		);
		explicit NotationFile(MemoryStream *stream=NULL);

		~NotationFile();

		void TestInstance() const;
		static bool TestClass();

		static void *s_cachedIncludes;

	protected:
		NotationFile(
			MemoryStream *stream,
			void *macro_tree
		);

		void CommonConstruction(
			MemoryStream *memory_stream,
			void *macro_tree
		);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Stream access
	//
	public:
		const FileDependencies* GetFileDependencies() const
			{Check_Object(this); return &m_fileDependencies;}

		const char* GetFileName() const
			{Check_Object(this); return m_fileName;}

		void SaveAs(const char* file_name);
		void Save();

		void IgnoreChanges()
			{Check_Object(this); m_dirtyFlag = false;}

		bool IsChanged() const
			{Check_Object(this); return m_dirtyFlag;}

		void Write(MemoryStream *stream);

	protected:
		void Read(
			MemoryStream *stream,
			void *macro_tree,
			Page **page,
			bool nested
		);

		void ProcessLine(
			MemoryStream *stream,
			void *macro_tree,
			Page **notepage,
			char* buffer
		);

		void HandleBangStuff(
			char *buffer,
			void *macro_tree,
			Page **page
		);
		void HandlePoundStuff(
			char *buffer,
			void *macro_tree,
			Page **page
		);

		void SetDirty()
			{ Check_Object(this); m_dirtyFlag = true; }

		Stuff::MString m_fileName;
		bool
			m_dirtyFlag,
			m_concatenate,
			m_preserveCase;
		Type m_type;
		FileDependencies m_fileDependencies;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Page access
	//
	public:
		bool IsEmpty()
			{Check_Object(this); return m_pages.IsEmpty();}

		bool DoesPageExist(const char *pagename)
			{Check_Object(this); return FindPage(pagename) != NULL;}
		Page* FindPage(const char* pagename);
		Page* GetPage(const char* pagename);

		typedef ChainIteratorOf<Page*> PageIterator;
		PageIterator* MakePageIterator()
			{Check_Object(this); return new(g_Heap) PageIterator(&m_pages);}

		Page* AddPage(const char *pagename);
		Page* SetPage(const char *pagename);

		void DeletePage(const char *pagename);
		void DeleteAllPages();

	protected:
		ChainOf<Page*> m_pages;
		void* m_pageMap;
	};

}
