

#define MAX_LINE	 1000
#define MAX_CHAR	50000
#define MAX_LINESEP    20

template <class CharType> class BufPart;

template <class CharType> class Buffer
{
protected:
	CharType LineSeparator[MAX_LINESEP];
	unsigned int LineSeparatorLen;
	BufPart<CharType> **ppBufferParts;
	unsigned int BufferPartCount;
	bool ReaderInitialized;

	unsigned int LineCount;
	unsigned int CharCount;

	BufPart<CharType> *pCurrentWriteBufPart;

	unsigned int *pLineMax;
	unsigned int *pCharMax;
	unsigned int LastReadLineIndex;
	unsigned int LastReadCharIndex;
	unsigned int LastReadLine;
	unsigned int LastReadChar;

	CharType *m_sDefaultOutputFilename;

	CharType *sCutAddBufferChars;
	unsigned int nCutAddBufferCharLen;

	unsigned int GetDelimiterStringLen (const CharType *, unsigned int len);
	unsigned int StrLen (const CharType *);

	void AddBufPart (BufPart<CharType> *);
	void InitializeReader (void);
	void Init();
public:
	Buffer ();
	virtual ~Buffer ();
	void SetLineSeparator (const CharType *sep, unsigned int seplen);

	void AddLine (const CharType *line, unsigned int len);
	void AddLine (const CharType *line);
	void AddBuffer (const CharType *line, unsigned int len); 
	const CharType *GetLine (unsigned int lineindex, unsigned int &len);

	CharType *GetLines (unsigned int lineindex, unsigned int linecount, unsigned int *pBufLen);
	void GetLinesDelete (CharType *);

	unsigned int GetBuffer (unsigned int offset, CharType *buffer, unsigned int buflen);

	void SetDefaultOutputFilename (const CharType *);

	inline const CharType *GetLineSeparator (void) const { return LineSeparator; }
	inline unsigned int GetLineSeparatorLen (void) const { return LineSeparatorLen; }
	
	inline unsigned int GetLineCount (void) const { return LineCount; }
	inline unsigned int GetCharCount (void) const { return CharCount; }

	inline const CharType *GetDefaultOutputFilename (void) const { return m_sDefaultOutputFilename; }
} ;

template <class CharType> class BufPart
{
protected:
	unsigned int LineCount;
	unsigned int CharCount;
	CharType Buf[MAX_CHAR];
	unsigned int LineOffset[MAX_LINE];
	const Buffer<CharType> *pBuffer;
public:
	
	BufPart (const Buffer<CharType> *);
	virtual ~BufPart ();
	
	BufPart *AddLine (const CharType *line, unsigned int len);
	const CharType *GetLine (unsigned int lineindex, unsigned int &len) const;

	const CharType *GetBuffer (unsigned int offset, unsigned int &len);

	inline unsigned int GetLineCount() const { return LineCount; }
	inline unsigned int GetCharCount() const { return CharCount; }

} ;


template <class CharType>
Buffer<CharType>::Buffer ()
{
	Init ();
}

template <class CharType>
Buffer<CharType>::~Buffer ()
{
	if (ppBufferParts) {
		unsigned int i;
		for (i = 0; i < BufferPartCount; i++) delete ppBufferParts[i];
		delete ppBufferParts;
	}
	if (pLineMax) delete pLineMax;
	if (pCharMax) delete pCharMax;

	if (m_sDefaultOutputFilename) delete m_sDefaultOutputFilename;

	if (sCutAddBufferChars) delete sCutAddBufferChars;
}

template <class CharType>
void Buffer<CharType>::Init ()
{
	BufferPartCount = 0;
	ppBufferParts = 0;
	ReaderInitialized = false;
	pCurrentWriteBufPart = 0;
	LineSeparator[0] = 0;
	LineSeparatorLen = 0;

	LineCount = 0;
	CharCount = 0;

	pLineMax = 0;
	pCharMax = 0;

	m_sDefaultOutputFilename = 0;

	sCutAddBufferChars = 0;
}


template <class CharType>
unsigned int Buffer<CharType>::StrLen (const CharType *s)
{
	switch (sizeof(CharType)) {
		case 1:
			return strlen ((const char *) s);
		case 2:
			return wcslen ((const wchar_t *) s);
		default:
			return 0;
	}
}

template <class CharType>
unsigned int Buffer<CharType>::GetDelimiterStringLen (const CharType *s, unsigned int len)
{

	unsigned int p = 0;

	while (p < len) 
	{
		if (!s[p]) return p;
		++p;
	}

	return len;
}


template <class CharType>
void Buffer<CharType>::AddBufPart (BufPart<CharType> *pNewBufPart)
{
	BufPart<CharType> **ppOld = ppBufferParts;
	ppBufferParts = new BufPart<CharType> *[BufferPartCount + 1];
	if (ppOld) {
		unsigned int i;
		for (i = 0; i < BufferPartCount; i++) ppBufferParts[i] = ppOld[i];
		delete ppOld;
	}
	ppBufferParts[BufferPartCount] = pNewBufPart;
	pCurrentWriteBufPart = pNewBufPart;
	++BufferPartCount;
}

template <class CharType>
void Buffer<CharType>::SetLineSeparator (const CharType *sep, unsigned int seplen)
{
	if (seplen > MAX_LINESEP) seplen = MAX_LINESEP;
	memcpy (LineSeparator, sep, seplen);
	LineSeparatorLen = seplen;
}

template <class CharType>
void Buffer<CharType>::AddBuffer (const CharType *line, unsigned int len)
{
	unsigned int startpos, endpos;

	if (sCutAddBufferChars) 
	{
		endpos = GetDelimiterStringLen (line, len);
		CharType *pBuf = new CharType [endpos + nCutAddBufferCharLen];
		memcpy (pBuf, sCutAddBufferChars, sizeof(CharType) * nCutAddBufferCharLen);
		memcpy (pBuf + nCutAddBufferCharLen, line, sizeof(CharType) * endpos);
		
		delete sCutAddBufferChars;
		sCutAddBufferChars = 0;
		
		if (endpos < len) {
			AddLine (pBuf, nCutAddBufferCharLen + endpos);
			delete pBuf;
		}
		else {
			nCutAddBufferCharLen += endpos;
			sCutAddBufferChars = pBuf;
		}
		startpos = endpos;
	}
	else startpos = 0;

	while (startpos < len) 
	{
		endpos = GetDelimiterStringLen (line + startpos, len - startpos);
		if (endpos < len - startpos) {
			AddLine (line + startpos, endpos);
		}
		else {
			nCutAddBufferCharLen = endpos;
			sCutAddBufferChars = new CharType [endpos];
			memcpy (sCutAddBufferChars, line + startpos, endpos);
		}
		startpos += endpos;
	}
}

template <class CharType>
void Buffer<CharType>::AddLine (const CharType *line)
{
	AddLine (line, (unsigned int) StrLen(line));
}

template <class CharType>
void Buffer<CharType>::AddLine (const CharType *line, unsigned int len)
{
	BufPart<CharType> *pNewBufPart;
	
	ReaderInitialized = false;
	
	if (!pCurrentWriteBufPart) {
		pNewBufPart = new BufPart<CharType> (this);
		pNewBufPart->AddLine (line, len);
	}
	else pNewBufPart = pCurrentWriteBufPart->AddLine (line, len);

	if (pNewBufPart != 0) AddBufPart (pNewBufPart);
	LineCount++;
	CharCount += len + LineSeparatorLen;
}

template <class CharType>
const CharType *Buffer<CharType>::GetLine (unsigned int lineindex, unsigned int &len)
{
	if (lineindex >= LineCount) return 0;

	if (!ReaderInitialized) InitializeReader();

	if (lineindex < LastReadLine) LastReadLineIndex = 0;
	while (lineindex >= pLineMax[LastReadLineIndex]) ++LastReadLineIndex;

	LastReadLine = lineindex;
	if (LastReadLineIndex > 0) return ppBufferParts[LastReadLineIndex]->GetLine (LastReadLine - pLineMax[LastReadLineIndex-1], len);
	else return ppBufferParts[LastReadLineIndex]->GetLine (LastReadLine, len);

}

template <class CharType>
unsigned int Buffer<CharType>::GetBuffer (unsigned int offset, CharType *buffer, unsigned int buflen)
{
	if (offset >= CharCount) {
		buflen = 0;
		return 0;
	}

	if (!ReaderInitialized) InitializeReader();

	if (offset < LastReadChar) LastReadCharIndex = 0;
	while (offset >= pCharMax[LastReadCharIndex]) ++LastReadCharIndex;

	const CharType *srcbuf;
	unsigned int localoffset, localbuflen;
	BufPart<CharType> *pBufPart;
	
	pBufPart = ppBufferParts[LastReadCharIndex];
	if (LastReadCharIndex > 0) localoffset = offset - pCharMax[LastReadCharIndex-1];
	else localoffset = offset;

	localbuflen = pBufPart->GetCharCount() - localoffset;
	if (localbuflen >= buflen || LastReadCharIndex + 1 == BufferPartCount) {
		srcbuf = pBufPart->GetBuffer (localoffset, buflen);
		memcpy (buffer, srcbuf, buflen);
		LastReadChar = offset + buflen;
		return buflen;
	}
	else {
		unsigned int restbuflen, bufoffset;

		srcbuf = pBufPart->GetBuffer (localoffset, localbuflen);
		memcpy (buffer, srcbuf, localbuflen);
		restbuflen = buflen - localbuflen;
		bufoffset = localbuflen;
		while (restbuflen > 0 && ++LastReadCharIndex < BufferPartCount) {
			pBufPart = ppBufferParts[LastReadCharIndex];
			srcbuf = pBufPart->GetBuffer (0, restbuflen);
			memcpy (buffer + bufoffset, srcbuf, restbuflen);
			bufoffset += restbuflen;
			restbuflen = buflen - bufoffset;
		}
		return bufoffset;
	}
}

#define EXPAND_LINE 50000

template <class CharType>
CharType *Buffer<CharType>::GetLines (unsigned int lineindex, unsigned int linecount, unsigned int *pBufLen)
{
	char *buf = new char[EXPAND_LINE];
	unsigned int charalloc = EXPAND_LINE;
	unsigned int charoffset = 0;
	const char *linebuf;
	unsigned int linelen, linemax;
	unsigned int i;

	if (lineindex + linecount >= LineCount) linemax = LineCount;
	else linemax = lineindex + linecount;

	for (i = lineindex; i < linemax; i++) {
		linebuf = GetLine (i, linelen);
		if (charoffset + linelen > charalloc) {
			if (linelen > EXPAND_LINE) charalloc += linelen;
			else charalloc += EXPAND_LINE;
			char *newbuf = new char [charalloc];
			memcpy (newbuf, buf, charoffset);
			delete buf;
			buf = newbuf;
		}
		memcpy (buf + charoffset, linebuf, linelen);
		charoffset += linelen;
	}

	if (pBufLen) *pBufLen = charoffset;
	return buf;
}


template <class CharType>
void Buffer<CharType>::GetLinesDelete (CharType *buf)
{
	delete buf;
}


template <class CharType>
void Buffer<CharType>::InitializeReader (void)
{
	unsigned int i;
	if (pLineMax) delete pLineMax;
	if (pCharMax) delete pCharMax;

	if (BufferPartCount > 0) {

		pLineMax = new unsigned int [BufferPartCount];
		pCharMax = new unsigned int [BufferPartCount];

		pLineMax[0] = ppBufferParts[0]->GetLineCount ();
		pCharMax[0] = ppBufferParts[0]->GetCharCount ();

		for (i = 1; i < BufferPartCount; i++) {
			pLineMax[i] = ppBufferParts[i]->GetLineCount() + pLineMax[i-1];
			pCharMax[i] = ppBufferParts[i]->GetCharCount() + pCharMax[i-1];
		}
	}
	LastReadLineIndex = 0;
	LastReadCharIndex = 0;
	LastReadLine = 0;
	LastReadChar = 0;
	ReaderInitialized = true;
}

template <class CharType>
void Buffer<CharType>::SetDefaultOutputFilename (const CharType *fn)
{
	if (m_sDefaultOutputFilename) delete m_sDefaultOutputFilename;
	if (!fn || !fn[0]) m_sDefaultOutputFilename = 0;
	else {
		m_sDefaultOutputFilename = new char [strlen(fn)+1];
		strcpy (m_sDefaultOutputFilename, fn);
	}
}


/* Implementation of class BufPart *********************************************************/

template <class CharType>
BufPart<CharType>::BufPart (const Buffer<CharType> *buf)
{ // Constructor
	LineCount = 0;
	CharCount = 0;
	pBuffer = buf;
}

template <class CharType>
BufPart<CharType>::~BufPart ()
{ // Destructor
}

template <class CharType>
BufPart<CharType> *BufPart<CharType>::AddLine (const CharType *line, unsigned int len)
{ // Adds a line to the object (or creates a new follow-up object to add the line)

	unsigned int lineseplen = pBuffer->GetLineSeparatorLen();
	
	if (MAX_LINE - LineCount < 1 || MAX_CHAR - CharCount < len + lineseplen) {
		BufPart *pNew = new BufPart (pBuffer);
		pNew->AddLine (line, len);
		return pNew;
	}
	else {
		LineOffset[LineCount] = CharCount;
		memcpy (Buf + CharCount, line, len);
		memcpy (Buf + CharCount + len, pBuffer->GetLineSeparator(), lineseplen);
		++LineCount;
		CharCount += len + lineseplen;
		return 0;
	}
}

template <class CharType>
const CharType *BufPart<CharType>::GetLine (unsigned int lineindex, unsigned int &len) const
{ // Reads the line from the object
	if (lineindex >= LineCount) return 0;
	else 
	{
		len = LineOffset[lineindex];
		return Buf + LineOffset[lineindex];
	}
}

template <class CharType>
const CharType *BufPart<CharType>::GetBuffer (unsigned int offset, unsigned int &len)
{ // Reads a part of the buffer from the object
	if (offset >= CharCount) return 0;
	else 
	{
		unsigned int local_len = CharCount - offset;
		if (local_len < len) len = local_len; 
		return Buf + offset;
	}
}

class BufferChar : public Buffer<char>
{} ;

class BufferWChar : public Buffer<wchar_t>
{} ;