//
// SyntaxState.h
//
// written by Michael Riedel <Michael.Riedel@gmx.de>
//

#ifndef INCLUDED_SyntaxState_h
#define INCLUDED_SyntaxState_h

#include <qstring.h>
#include <qcolor.h>
#include <qlist.h>
#include <qdict.h>
#include <qfont.h>
#include <qregexp.h>



//////////////////////////////////////////////////////////////////
class FontInfo
{
	Q_OBJECT;

public:
    FontInfo(const QColor color = black, int weight = QFont::Normal, 
    	     bool italic = false)
    { 
    	Color  = color; 
    	Weight = weight;
    	Italic = italic;
		CachedFont = 0;
		FontDirty = true;
    }
    FontInfo(const FontInfo& fi)
    { 
    	Color  = fi.Color; 
    	Weight = fi.Weight;
    	Italic = fi.Italic;
    	if(fi.CachedFont)
			CachedFont = new QFont(*fi.CachedFont);
		else
			CachedFont = 0;
		FontDirty = fi.FontDirty;
    }
	~FontInfo()
	{
		if(CachedFont)
			delete CachedFont;
	}

	void setDrawingAttrs(QPainter& p, const QFont& baseFont) const;
	
    const QColor& color() const	{ return Color; }
    bool italic() const   		{ return Italic; }
    int weight() const 	   		{ return Weight; }
    void setColor(QColor c) 	{ Color = c; }
    void setItalic(bool i)		{ Italic = i; FontDirty = true; }
    void setWeight(int w)		{ Weight = w; FontDirty = true; }


protected:
    QColor Color;		// color in which element is drawn
    int    Weight;  	// weight of font in which element is drawn
    bool   Italic;  	// element is drawn italic
    QFont* CachedFont;	// used to cache a QFont object; prevents these objects from being
    					// regenerated very often (as often as a certain syntax state applies)
    bool   FontDirty;	// true, whenever CachedFont doesn´t match the actual attrs
    					
	inline QFont* cachedFont(const QFont& baseFont) const;
};
//////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////
class SyntaxState : public FontInfo
{
	Q_OBJECT;
	
public:
	SyntaxState(const QString& initStr);
	SyntaxState(const SyntaxState& ss);
	SyntaxState(const QString& name, const QString& id, const QColor color, 
				int weight = QFont::Normal, bool italic = false)
		: FontInfo(color, weight, italic)
	{ 
		Name = name; 
		Id = id;
	}
	
	const QString& name() const { return Name; }
	const QString& id() const { return Id; }

	
protected:
	QString Name;		// Name for use in Color settings dialog
	QString Id;			// unique id
	QString ColName;	// Name of the color
};
//////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////
typedef QVectorT<SyntaxState> StateList;
int findState(StateList& states, const QString& stateId);
//////////////////////////////////////////////////////////////////



	// Error definitions for class SyntaxUnit:
#define RE_ERR_NONE					 0
#define RE_ERR_RESEPARATORS 		-1
#define RE_ERR_INVALIDLINE			-2



//////////////////////////////////////////////////////////////////
class SyntaxUnit
{
public:
	SyntaxUnit(int prev, int inner, int after)
	{ ValidPrevState = prev; InnerState = inner; StateAfterwards = after; Error = RE_ERR_NONE; }

	int Match(const QString& string, int start, int& len, int prevState) const;
	virtual int StartMatch(const QString& string, int start, int& len) const = 0;
	
	int validPrevState() const  { return ValidPrevState; }
	int innerState() const      { return InnerState; }
	int stateAfterwards() const { return StateAfterwards; }
	
	int error() const { return Error; }
	bool hasError() const { return error() == RE_ERR_NONE; }


protected:
	int Error;				// indicates an error
	int ValidPrevState;		// index of state that must occur before this is used
	int InnerState;			// index of state of the text that matches 
	int StateAfterwards;	// index of state after this unit

	virtual int match(const QString& string, int start, int& len) const = 0;
};
//////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////
class RegExpSyntaxUnit : public SyntaxUnit
{
public:
    RegExpSyntaxUnit(const QString& initStr, QVectorT<SyntaxState>& states);
    RegExpSyntaxUnit(const QString& re, int prev, int inner, int next)
    	: SyntaxUnit(prev, inner, next),
    	  RE(re)
    { }

	int StartMatch(const QString& string, int start, int& len) const;

  
protected:
	QRegExp  RE;		// regular expression
	QRegExp  REStart;	// first `char` of RE

	virtual int match(const QString& string, int start, int& len) const
	{ return RE.match(string, start, &len); }    
	void setSplittedREs(const char* hlp);
	int searchREEntity(const char* str, bool& isValid);	
};
//////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////
class FSyntaxUnit : public SyntaxUnit
{
public:
    FSyntaxUnit(int prev, int inner, int next)
    	: SyntaxUnit(prev, inner, next)
    { }

	int StartMatch(const QString& /*string*/, int /*start*/, int& /*len*/) const
	{ return -1; }


protected:
	virtual int match(const QString& string, int start, int& len) const;
};
//////////////////////////////////////////////////////////////////


#endif INCLUDED_SyntaxState_h

