//	Copyright (C) 1999-2002 Paul O. Lewis
//
//	This file is part of NCL (Nexus Class Library).
//
//	NCL 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; either version 2 of the License, or
//	(at your option) any later version.
//
//	NCL 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 NCL; if not, write to the Free Software Foundation, Inc.,
//	59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//

#ifndef NCL_BASICCMDLINE_H
#define NCL_BASICCMDLINE_H
#include <iostream>
#define COMMAND_MAXLEN  255

/*----------------------------------------------------------------------------------------------------------------------
|	BASICCMDLINE provides a template for creating a program that reads NEXUS data files and provides a basic command
|	line. After compiling BASICCMDLINE, you will already have a program that understands the following commands, either
|	typed in at the console or provided in a BASICCMDLINE block in a NEXUS data file (exception is the execute command,
|	which can only be entered at the console). Keywords in the descriptions below are given in uppercase, however the
|	commands themselves are case-insensitive. Lower-case indicates a parameter supplied by the user (e.g., "filename"
|	would be replaced by the actual name of the file). Square brackets indicate optional keywords or subcommands.
|>
|	EXECUTE filename;
|
|	LOG [options];
|
|	  Option         Action
|	  ------------------------------------------------------
|	  FILE=filename  specifies name of log file to start
|	  START          indicates logging is to be started
|	  STOP           indicates logging is to be stopped
|	  APPEND         append to log file if it already exists
|	  REPLACE        replace log file without asking
|
|	QUIT;
|>
|	See the Read function for details and to add other commands.
|
|	To change the name of the program (which is also the prompt name and the name of the program's private NEXUS
|	block), replace all occurrences of BASICCMDLINE with the name of your program (also search for the string
|	"basiccmdline" and replace with an appropriate string at each occurrence).
|
|	This class handles reading and storage for the NxsReader block BASICCMDLINE. It also serves as the main class for
|	the program BASICCMDLINE, acting as both a NxsReader object (in order to be capable of parsing data files) as well
|	as a NxsBlock object (in order to be able to process commands in a BASICCMDLINE block).
|
|	Acting as a NxsBlock, it overrides the member functions Read and Reset, which are virtual functions in the base
|	class NxsBlock. Acting as a NxsReader object, it overrides the member functions EnteringBlock, SkippingBlock, and
|	NexusError.
|
|	Adding a new data member? Don't forget to:
|~
|	o Describe it in the class header comment at the top of "basiccmdline.h"
|	o Initialize it (unless it is self-initializing) in the constructor and reinitialize it in the Reset function
|	o Describe the initial state in the constructor documentation
|	o Delete memory allocated to it in both the destructor and Reset function
|	o Report it in some way in the Report function
|~
*/
class BASICCMDLINE
  : public NxsBlock,
  public NxsReader
	{
	public:

		enum UserQueryEnum		/* enumeration used with UserQuery member function to specify which choices to provide the user */
			{
			uq_cancel = 0x01,	/* provide opportunity to cancel */
			uq_ok	  = 0x02,	/* provide opportunity to answer ok */
			uq_yes	  = 0x04,	/* provide opportunity to answer yes */
			uq_no 	  = 0x08	/* provide opportunity to answer no */
			};

								BASICCMDLINE();
		virtual					~BASICCMDLINE();

		bool					EnteringBlock(NxsString blockName);
		void					ExitingBlock(NxsString blockName);
		void					ExecuteStarting();
		void					ExecuteStopping();
		void					OutputComment(const NxsString &msg);
		void					HandleNextCommand();
		void					NexusError(NxsString msg, file_pos pos, long line, long col);
		void					PreprocessNextCommand();
		void					PrintMessage(bool linefeed = true) const ;
		virtual void			Report(std::ostream & out) NCL_COULD_BE_CONST ;
		void					Run(char *infile_name);
		void					SkippingBlock(NxsString blockName);
		void					SkippingCommand(NxsString commandName);
		void					SkippingDisabledBlock(NxsString blockName);
		virtual bool			UserQuery(NxsString mb_message, NxsString mb_title, BASICCMDLINE::UserQueryEnum mb_choices = BASICCMDLINE::uq_ok);
		virtual unsigned		CharLabelToNumber(NxsString s) NCL_COULD_BE_CONST;

	protected:

		bool					inf_open;			/* true if `inf' is currently open */
		bool					logf_open;			/* true if `logf' is currently open */
		bool					quit_now;			/* set to false at beginning of Run and turns true only when QUIT command processed */
		mutable std::ofstream		logf;				/* the log file output stream */
		mutable NxsString		message;			/* workspace for composing output strings */
		NxsTreesBlock *			trees;				/* pointer to NxsTreesBlock object */
		NxsTaxaBlock *			taxa;				/* pointer to NxsTaxaBlock object */
		NxsAssumptionsBlock *	assumptions;		/* pointer to NxsAssumptionsBlock object */
		NxsDistancesBlock *		distances;			/* pointer to NxsDistancesBlock object */
		NxsCharactersBlock *	characters;			/* pointer to NxsCharactersBlock object */
		NxsDataBlock *			data;				/* pointer to NxsDataBlock object */
		NxsUnalignedBlock *		unaligned;			/* pointer to NxsUnalignedBlock object */
		char *					next_command;		/* workspace for processing next command entered interactively by user */

		bool					FileExists(const char* fn);
		NxsString				GetFileName(NxsToken& token);
		void					FactoryDefaults();
		void					HandleEndblock(NxsToken& token);
		void					HandleShow(NxsToken& token);
		void					HandleHelp(NxsToken& token);
		void					HandleLog(NxsToken& token);
		void					HandleExecute(NxsToken& token);
		void					PurgeBlocks();
		virtual void			Read(NxsToken& token);
		virtual void			Reset();
		unsigned				TaxonLabelToNumber(NxsString s) const;
	};

/*----------------------------------------------------------------------------------------------------------------------
|	The MyNexusToken class provides a NxsToken-derived object that can display output comments as it encounters them.
|	The virtual function NxsToken::OutputComment is overridden in this class for this purpose.
*/
class MyNexusToken
  : public NxsToken
	{
	public:
				MyNexusToken(std::istream &i);

		void	OutputComment(const NxsString &msg);
	};

/*----------------------------------------------------------------------------------------------------------------------
|	Will be called by NxsReader::Execute after the initial "#NEXUS" keyword is found in a NEXUS file but before other
|	tokens are read. Add code here if you need to do any initializations prior to encountering any NEXUS blocks in a
|	NEXUS data file.
*/
inline void BASICCMDLINE::ExecuteStarting()
	{
	}

/*----------------------------------------------------------------------------------------------------------------------
|	Will be called by NxsReader::Execute just before it exits after reading to the end of a NEXUS data file (or until
|	encountering a LEAVE command between NEXUS blocks. Add code here if you need to clean up any memory allocated in
|	ExecuteStarting.
*/
inline void BASICCMDLINE::ExecuteStopping()
	{
	}

/*----------------------------------------------------------------------------------------------------------------------
|	Called if an "output comment" is encountered in a NEXUS data file. An output comment is a comment [text enclosed in
|	square brackets] that begins with an exclamation point. [!This is an example of a NEXUS output comment]. Output
|	comments are supposed to be displayed when encountered. Modify this function's body to display output comments,
|	which are made available as they are encountered via the `msg' argument.
*/
inline void	BASICCMDLINE::OutputComment(const NxsString &)
	{
	}

#endif

