/***************************************************************************
 * parser.h is part of Math Graphic Library
 * Copyright (C) 2007-2016 Alexey Balakin <mathgl.abalakin@gmail.ru>       *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 3 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program 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 Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef _MGL_PARSER_H_
#define _MGL_PARSER_H_

#ifdef __cplusplus
#include "mgl2/mgl.h"
#if MGL_HAVE_LTDL
#include <ltdl.h>
#endif
//-----------------------------------------------------------------------------
/// Structure for the command argument.
struct mglArg
{
	int type;		///< Type of argument {0-data,1-string,2-number}
	mglDataA *d;	///< Pointer to data (used if type==0)
	std::wstring w;	///< String with parameters
	std::string s;	///< String with parameters
	mreal v;		///< Numerical value (used if type==2)
	dual c;			///< Numerical complex value (used if type==2)
	mglArg():type(-1),d(0),v(0),c(0.)	{}
};
//-----------------------------------------------------------------------------
/// Structure for MGL command
struct mglCommand
{
	const char *name;	///< Name of command
	const char *desc;	///< Short command description (can be NULL)
	const char *form;	///< Format of command arguments (can be NULL)
	/// Function for executing (plotting)
	int (*exec)(mglGraph *gr, long n, mglArg *a, const char *k, const char *opt);
	/// Type of command: 0 - data plot, 1 - other plot,
	///	2 - setup, 3 - data handle, 4 - data create, 5 - subplot, 6 - program
	///	7 - 1d plot, 8 - 2d plot, 9 - 3d plot, 10 - dd plot, 11 - vector plot
	///	12 - axis, 13 - primitives, 14 - axis setup, 15 - text/legend, 16 - data transform
	int type;
};
extern mglCommand mgls_base_cmd[];
//-----------------------------------------------------------------------------
/// Structure for the number handling (see mglParse class).
struct mglNum
{
	mreal d;		///< Number itself
	dual c;
	std::wstring s;	///< Number name
	mglNum(mreal val=0):d(val),c(val)	{}
};
//-----------------------------------------------------------------------------
/// Structure for function name and position.
struct mglFunc
{
	long pos;
	int narg;
	std::wstring func;
	mglFunc(long p, const wchar_t *f);
	mglFunc(const mglFunc &f):pos(f.pos),narg(f.narg),func(f.func)	{}
	mglFunc():pos(-1),narg(-1)	{}
};
//-----------------------------------------------------------------------------
/// Structure for stack of functions and its arguments.
struct mglFnStack
{
	long pos;
	std::wstring par[10];
	mglFnStack():pos(0)	{}
};
//-----------------------------------------------------------------------------
/// Function for asking question in console mode
void MGL_EXPORT mgl_ask_gets(const wchar_t *quest, wchar_t *res);
//-----------------------------------------------------------------------------
/// Structure for the command argument (see mglGraph::Exec()).
class mglParser
{
friend void mgl_export(wchar_t *out, const wchar_t *in, int type);
public:
#if MGL_HAVE_LTDL
	std::vector<lt_dlhandle> DllOpened;	///< Opened external DLL (keep )
#endif
	std::vector<mglDataA*> DataList;	///< List with data and its names
	std::vector<mglNum*> NumList;	///< List with numbers and its names
	bool AllowDllCall;	///< Allow calls from external dynamic libraries
	bool AllowSetSize;	///< Allow using setsize command
	bool AllowFileIO;	///< Allow reading/saving files
	volatile bool Stop;	///< Stop command was. Flag prevent further execution
	mglCommand *Cmd;	///< Table of MGL commands (can be changed by user). It MUST be sorted by 'name'!!!
	long InUse;			///< Smart pointer (number of users)
	const mglBase *curGr;	///< Current grapher

	mglParser(bool setsize=false);
	virtual ~mglParser();
	/// Find the command by the keyword name
	const mglCommand *FindCommand(const char *name) const MGL_FUNC_PURE;
	const mglCommand *FindCommand(const wchar_t *name) const MGL_FUNC_PURE;
	/// Parse and execute the string of MGL script
	inline int Parse(HMGL gr, const char *str, long pos=0)
	{	mglGraph GR(gr);	return Parse(&GR,str,pos);	}
	int Parse(mglGraph *gr, const char *str, long pos=0);
	/// Parse and execute the unicode string of MGL script
	inline int Parse(HMGL gr, const wchar_t *str, long pos=0)
	{	mglGraph GR(gr);	return Parse(&GR,str,pos);	}
	int Parse(mglGraph *gr, std::wstring str, long pos=0);
	/// Execute MGL script file fname
	inline void Execute(HMGL gr, FILE *fp, bool print=false)
	{	mglGraph GR(gr);	Execute(&GR,fp,print);	}
	void Execute(mglGraph *gr, FILE *fp, bool print=false);
	/// Execute MGL script from array of lines
	inline void Execute(HMGL gr, int num, const wchar_t **text)
	{	mglGraph GR(gr);	Execute(&GR,num,text);	}
	void Execute(mglGraph *gr, int num, const wchar_t **text);
	/// Execute MGL script text with '\n' separated lines
	inline void Execute(HMGL gr, const wchar_t *text)
	{	mglGraph GR(gr);	Execute(&GR,text);	}
	void Execute(mglGraph *gr, const wchar_t *text);
	/// Execute MGL script text with '\n' separated lines
	inline void Execute(HMGL gr, const char *text)
	{	mglGraph GR(gr);	Execute(&GR,text);	}
	void Execute(mglGraph *gr, const char *text);
	/// Scan for functions (use NULL for reset)
	void ScanFunc(const wchar_t *line);
	/// Check if name is function and return its address (or 0 if no)
	long IsFunc(const std::wstring &name, int *narg=0);
	/// Find variable or return 0 if absent
	mglDataA *FindVar(const char *name) MGL_FUNC_PURE;
	mglDataA *FindVar(const wchar_t *name) MGL_FUNC_PURE;
	/// Find variable or create it if absent
	mglDataA *AddVar(const char *name);
	mglDataA *AddVar(const wchar_t *name);
	/// Find number or return 0 if absent
	mglNum *FindNum(const char *name) MGL_FUNC_PURE;
	mglNum *FindNum(const wchar_t *name) MGL_FUNC_PURE;
	/// Find number or create it if absent
	mglNum *AddNum(const char *name);
	mglNum *AddNum(const wchar_t *name);
	/// Add string for parameter $1, ..., $9
	void AddParam(int n, const char *str);
	void AddParam(int n, const wchar_t *str);
	/// Add new MGL command(s) (last command MUST HAVE name[0]=0 !!!)
	void AddCommand(mglCommand *cmd, int num=0);
	/// Restore Once flag
	inline void RestoreOnce()	{	Once = true;	}
	/// Delete variable by its name
	void DeleteVar(const char *name);
	void DeleteVar(const wchar_t *name);
	/// Delete all data variables
	void DeleteAll();
	/// Set variant of argument(s) separated by '?' to be used
	inline void SetVariant(int var=0)	{	Variant = var<=0?0:var;	}
private:
//	long parlen;		///< Length of parameter strings
	std::wstring par[40];	///< Parameter for substituting instead of $1, ..., $9
	bool Once;			///< Flag for command which should be executed only once
	bool Skip;			///< Flag that commands should be skiped (inside 'once' block)
	int if_stack[40];	///< Stack for if-else-endif commands
	int if_pos;			///< position in if_stack
	std::vector<mglFunc> func;	///< function names and position
	std::vector<mglFnStack> fn_stack;	///< function calls stack
//	int fn_pos;			///< position in function stack
	int if_for[40];		///< position in if_stack for for-cycle start
	mglData *fval;		///< Values for for-cycle. Note that nx - number of elements, ny - next element, nz - address (or string number) of first cycle command
	int for_stack[40];	///< The order of for-variables
	int for_addr;		///< Flag for saving address in variable (for_addr-1)
	bool for_br;		///< Break is switched on (skip all comands until 'next')
	unsigned Variant;	///< Select variant of argument(s) separated by '?'

	/// Parse command
	int Exec(mglGraph *gr, const wchar_t *com, long n, mglArg *a, const std::wstring &var, const wchar_t *opt);
	/// Fill arguments a from strings
	void FillArg(mglGraph *gr, int n, std::wstring *arg, mglArg *a);
	/// PreExecute stage -- parse some commands and create variables
	int PreExec(mglGraph *gr, long n, std::wstring *arg, mglArg *a);
	/// Execute program-flow control commands
	int FlowExec(mglGraph *gr, const std::wstring &com, long n, mglArg *a);
	/// Parse and execute the unicode string of MGL script
	int ParseDat(mglGraph *gr, std::wstring str, mglData &res);
	/// Define '$' parameters or start for loop
	int ParseDef(std::wstring &str);
	/// Parse $N arguments
	void PutArg(std::wstring &str, bool def);
	/// In skip mode
	bool inline ifskip()	{	return (if_pos>0 && !(if_stack[if_pos-1]&1));	}
	bool inline skip()		{	return (Skip || ifskip() || for_br);	}
	bool CheckForName(const std::wstring &s);	// check if name is valid for new data
};
//-----------------------------------------------------------------------------
#endif
#endif
