/***************************************************************************
 *   Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf             *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License                  *
 *   (version 3 or above) as published by the Free Software Foundation.    *
 *                                                                         *
 *   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 GPL                        *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA               *
 ***************************************************************************/
#include <QtDebug>

#include "RichboxWidget.hpp"
#include "Setup.hpp"

RichBoxWidget::RichBoxWidget(QWidget*)
{
	this->setFixedHeight(richBoxWidgetHeight);
	this->setAcceptRichText(true);
	this->setReadOnly(true);
	this->document()->setDefaultStyleSheet("body { white-space: pre }");
	this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	this->setFocusPolicy(Qt::NoFocus);
}

void RichBoxWidget::startTyping(const QString& text, const QString& author)
{
	this->mistakeIndexes.clear();
	this->currentPosition = 0;
	this->text = text;
	this->author = author;
	this->setEnabled(true);
	QTextEdit::setHtml(renderHtml());
	Q_ASSERT(!text.isEmpty());
	emit markSymbol(text[0]);
}

void RichBoxWidget::endTyping()
{
	this->setEnabled(false);
}

static QString quoteText(const QString& text)
{
	QString result = text;
	result.replace(QString("&"), QString("&amp;"));
	result.replace(QString("\""), QString("&quot;"));
	result.replace(QString("<"), QString("&lt;"));
	result.replace(QString(">"), QString("&gt;"));

	return result;
}

QString RichBoxWidget::renderHtml() const
{
	QString result = "<html><body>";
	for (size_t i = 0; i < mistakeIndexes.size(); ++i)
	{
		const uint& mistakeIndex = mistakeIndexes[i];
		uint leftIndex = ( (i == 0) ? 0 : (mistakeIndexes[i-1] + 1) );
		// adding non-mistake part
		result += quoteText(text.mid(leftIndex, mistakeIndex-leftIndex));
		// adding mistake byte
		result += QString("<font color='red'><u>%1</u></font>").arg(quoteText(text[mistakeIndex]));
	}
	int lastMistakeIndex = (mistakeIndexes.empty()) ? -1 : mistakeIndexes[mistakeIndexes.size() - 1];
	result += quoteText(text.mid(lastMistakeIndex+1, currentPosition-lastMistakeIndex-1));
	if (this->isEnabled())
	{
		result += QString("<font color='blue'><u>%1</u></font>").arg(quoteText(text[currentPosition]));
		if (static_cast<int>(currentPosition) < text.size() - 1)
		{
			result += quoteText(text.mid(currentPosition+1));
		}
	}
	// adding author entry
	result += QString("<p align='right'><font color='gray'>%1</font></p>").arg(quoteText(author));
	result += "</body></html>";

	// <br>-ing - dividing text into lines
	this->insertWraps(result);

	//qDebug() << "Richbox contains:" << qPrintable(result);
	return result;
}

void RichBoxWidget::insertWraps(QString& result) const
{
	bool inTag = false;
	bool inSpecialSymbol = false;
	size_t symbolCounter = 0;
	int probableRawInsertPosition = 0;
	int probableTextInsertPosition = 0;
	int lastTextInsertPosition = 0;
	QString br = "<br>";
	for (int i = 0; i < result.size(); ++i)
	{
		if (result[i] == '<')
		{
			inTag = true;
		}
		else if (result[i] == '>')
		{
			inTag = false;
		}
		else if (!inTag)
		{
			// checking for '&...;"-like symbols
			if (result[i] == ';')
			{
				inSpecialSymbol = false;
			}
			else if (result[i] == '&')
			{
				inSpecialSymbol = true;
			}

			if (!inSpecialSymbol)
			{
				++symbolCounter;

				if (result[i] == spaceChar)
				{
					probableRawInsertPosition = i+1;
					probableTextInsertPosition = symbolCounter;
				}
				if (symbolCounter - lastTextInsertPosition == lineLength)
				{
					int lastRawInsertPosition = (probableRawInsertPosition ? probableRawInsertPosition : i+1);
					result.insert(lastRawInsertPosition, br);
					i += br.size();
					probableRawInsertPosition = 0;
					lastTextInsertPosition = probableTextInsertPosition;
				}

				if (static_cast<int>(symbolCounter) == text.size())
				{
					// main text is end... exiting is our only way
					break;
				}
			}
		}
	}
}

void RichBoxWidget::keyPressed(QChar symbol)
{
	if (this->isEnabled() && symbol.isPrint())
	{
		//* debug */ qDebug() << "keyPressed:" << qPrintable(QString(symbol));
		if (symbol == text[currentPosition])
		{
			// all's ok!
			emit typedSymbol();
		}
		else
		{
			// mistake :(
			mistakeIndexes.push_back(currentPosition);
			emit errorOnSymbol();
		}

		currentPosition += 1;
		if (static_cast<int>(currentPosition) == text.size())
		{
			// text is finished
			this->setEnabled(false);
			//emit finished();
			// now Logic recognizes 'finished' event itself
		}
		else
		{
			//qDebug("RichBoxWidget::currentPosition = %d", (int)currentPosition);
			emit markSymbol(text[currentPosition]);
		}
		QTextEdit::setHtml(renderHtml());
	}
}

