/* Hapy is a public domain software. See Hapy README file for the details. */

#ifndef HAPY_RULE_BASE__H
#define HAPY_RULE_BASE__H

#include <Hapy/Top.h>
#include <Hapy/Result.h>
#include <Hapy/String.h>
#include <Hapy/IosFwd.h>
#include <Hapy/RuleId.h>
#include <Hapy/RuleCompFlags.h>
#include <Hapy/First.h>
#include <Hapy/RulePtr.h>

namespace Hapy {

class Buffer;
class Pree;
class Algorithm;
class Action;
class Rule;

// grammar rule implementation: parsing alg + ID + flags and logic
// see Rule for user-level grammar rule interface
class RuleBase {
	public:
		typedef Result::StatusCode StatusCode;
		typedef RuleCompFlags CFlags;

		// announce parsing rule rejection due to the given reason
		static void DebugReject(const RuleBase *rule, const char *reason);

	public:
		RuleBase();

		void id(const RuleId &anId);

		const RuleId &id() const { return theId; }

		bool build(const CFlags &flags); // called by parser
		bool compile(const CFlags &flags); // called by algorithms
		void calcFullFirst();
		bool calcPartialFirst(First &first, Pree &pree);

		void committed(bool be);

		bool terminal() const;
		bool trimming() const;
		void trim(const RulePtr &aTrimmer);
		void verbatim(bool be);
		void leaf(bool be);
		void action(const Action *anAction);

		StatusCode firstMatch(Buffer &buf, Pree &pree) const;
		StatusCode nextMatch(Buffer &buf, Pree &pree) const;
		StatusCode resume(Buffer &buf, Pree &pree) const;
		void cancel(Buffer &buf, Pree &pree) const;

		ostream &print(ostream &os) const;

		bool hasAlg() const { return theAlg != 0; }
		const Algorithm &alg() const;
		void alg(Algorithm *anAlg);
		void updateAlg(const RuleBase &src);

		void implicit(bool be);

		bool temporary() const;

	protected:
		bool shouldTrim(CFlags &flags) const;
		bool compileTrim(const CFlags &flags);

		bool mayMatch(Buffer &buf) const;

		typedef StatusCode (Algorithm::*AlgMethod)(Buffer &buf, Pree &pree) const;
		StatusCode call(Buffer &buf, Pree &pree, AlgMethod m, const char *mLabel) const;
		StatusCode applyAction(Buffer &buf, Pree &pree) const;
		
		static ostream &DebugPfx(int callId);
		void debugBuffer(const Buffer &buf) const;
		void debugTry(const Buffer &buf, const Pree &pree, const char *mLabel, int callId) const;
		void debugResult(const Buffer &buf, const Pree &pree, const char *mLabel, int callId, StatusCode result) const;

	protected:
		Algorithm *theAlg;
		const Action *theAction;
		RuleId theId;

		RulePtr theTrimmer;

		First theFirst;
		enum { emsUnknown, emsComputing, emsYes, emsNo } theEmptyMatchState;
		enum { fssUnknown, fssComputing, fssKnown, fssError } theFirstSetState;

		enum { cmDefault, cmDont, cmCommit } theCommitMode;
		enum { tmDefault, tmVerbatim, tmImplicit, tmExplicit } theTrimMode;
		bool isImplicit;
		bool isLeaf;
		bool mustReachEnd;

		bool isCompiling;

	private:
		static int TheLastCallId;
		static int TheCallLevel;
};

} // namespace

#endif
