#ifndef __FORMATTER_H__
#define __FORMATTER_H__

#include "Common.h"

namespace AScript {

//-----------------------------------------------------------------------------
// FormatterBase
//-----------------------------------------------------------------------------
class FormatterBase {
private:
	bool _nilVisibleFlag;
	const TCHAR *_lineSep;
	enum PlusMode { PLUSMODE_None, PLUSMODE_Space, PLUSMODE_Plus, };
	struct Flags {
		bool leftAlignFlag;
		bool sharpFlag;
		int fieldMinWidth;
		int precision;
		PlusMode plusMode;
		TCHAR charPadding;
	};
public:
	inline FormatterBase(bool nilVisibleFlag = true) :
					_nilVisibleFlag(nilVisibleFlag), _lineSep(_T("\n")) {}
	bool DoFormat(Signal sig, const TCHAR *format, const ValueList &valList);
	void PutString(const Flags &flags, const TCHAR *p, int cntMax = -1);
	void PutInvalid(const Flags &flags);
	virtual void PutChar(TCHAR ch) = 0;
private:
	inline static void SetError_WrongFormat(Signal &sig) {
		sig.SetError(ERR_ValueError, _T("wrong format for formatter"));
	}
	inline static void SetError_NotEnoughArguments(Signal &sig) {
		sig.SetError(ERR_TypeError, _T("not enough arguments for formatter"));
	}
	inline static void SetError_NumberIsExpected(Signal &sig, const TCHAR ch) {
		sig.SetError(ERR_ValueError, _T("number is expected for %%%c qualifier"), ch);
	}
	inline static void SetError_NumberOrComplexIsExpected(Signal &sig, const TCHAR ch) {
		sig.SetError(ERR_ValueError, _T("number or complex is expected for %%%c qualifier"), ch);
	}
	inline static void SetError_NumberIsExpected(Signal &sig, const TCHAR *qualifier) {
		sig.SetError(ERR_ValueError, _T("number is expected for %s"), qualifier);
	}
	static const TCHAR *Conv_d(const Flags &flags, int value,
							TCHAR *buff, size_t size);
	static const TCHAR *Conv_u(const Flags &flags, unsigned int value,
							TCHAR *buff, size_t size);
	static const TCHAR *Conv_o(const Flags &flags, unsigned int value,
							TCHAR *buff, size_t size);
	static const TCHAR *Conv_x(const Flags &flags, unsigned int value,
							TCHAR *buff, size_t size, bool upperFlag);
	static const TCHAR *Conv_e(const Flags &flags, double value,
							TCHAR *buff, size_t size, bool upperFlag);
	static const TCHAR *Conv_f(const Flags &flags, double value,
							TCHAR *buff, size_t size, bool upperFlag);
	static const TCHAR *Conv_g(const Flags &flags, double value,
							TCHAR *buff, size_t size, bool upperFlag);
	static TCHAR *FillZeroDigit(TCHAR *dstp, TCHAR *dstpEnd, int cnt);
	static TCHAR *CopyDigits(TCHAR *dstp, TCHAR *dstpEnd, const char *srcp);
	static TCHAR *CopyDigits(TCHAR *dstp, TCHAR *dstpEnd, const char *srcp, int cnt);
	static TCHAR *CopyUpperDigits(TCHAR *dstp, TCHAR *dstpEnd, const char *srcp);
};

//-----------------------------------------------------------------------------
// Formatter
//-----------------------------------------------------------------------------
class Formatter : public FormatterBase {
private:
	String _str;
public:
	static String Format(Signal sig,
							const TCHAR *format, const ValueList &valList);
	virtual void PutChar(TCHAR ch);
};

}

#endif
