#include "formatter.h"
#include "net/dict.h"

#include <KConfig>
#include <KConfigGroup>

#include <QRegExp>


namespace Dict {

QString escape(const QString &text)
{
	QString html = text;
	html.replace('&', "&amp;");
	html.replace('<', "&lt;");
	html.replace('>', "&gt;");
	html.replace('"', "&quot;");
	return html;
}

QString links(const QString &text)
{
	QString html = text;

	int start = 0;
	while ((start = html.indexOf('{', start + 1)) >= 0) {
		int end = html.indexOf('}', start);
		// missing matching brace
		if (end < 0) break;

		int len = end - start;
		// too long for a link
		if (len > 240) continue;

		QString link = html.mid(start + 1, len - 1);
		// multiple lines inside braces, likely source code
		if (link.count('\n') > 1) continue;

		int pos;
		// skip external links
		if ((pos = link.indexOf('(')) >= 0 && link.indexOf(')') > pos
			&& len - pos > 5) {
				html.replace(start, len + 1, link);
				continue;
		}
		// format link
		html.replace(start, len + 1, QString("<a href=\"%1\">%2</a>")
			.arg(link.left(pos).simplified(), link));
	}
	return html;
}

bool isHtml(const QString &text)
{
	return text.startsWith("<html>") && text.endsWith("</html>");
}

bool isXdxf(const QString &text)
{
	return (text.startsWith("<ar>") && text.endsWith("</ar>"))
		|| (text.contains("<k>") && text.contains("</k>"));
}

QString resourcePath(const QString &resfile);

Formatter::Formatter()
{
	maxLen = 12000;
	readConf();
}

void Formatter::readConf()
{
	QString path = resourcePath("format.conf");
	KConfig config(path, KConfig::SimpleConfig);
	fmap.clear();
	foreach (QString entry, config.groupList()) {
		KConfigGroup group(&config, entry);
		foreach(QString key, group.keyList()) {
			QStringList val = group.readEntry(key, QStringList());
			if (val.size() >= 2)
				fmap[entry].append(qMakePair(val[0], val[1]));
		}
	}
	fcache.clear();
}

QString Formatter::format(const DefineResponse &response)
{
	QString html, func;

	if (fmap.contains(response.database))
		func = response.database;
	else if (fcache.contains(response.database))
		func = fcache.value(response.database);
	else {
		foreach (QString key, fmap.keys())
			if (response.database.contains(key)
			|| response.description.contains(key, Qt::CaseInsensitive)) {
				func = key;
				break;
			}
		if (func.isEmpty()) {
			if (isHtml(response.list.first()))
				func = "html";
			if (isXdxf(response.list.first()))
				func = "xdxf";
		}
		fcache[response.database] = func;
	}
	if (func.isEmpty())
		return words(response.list);

	html = (QString("<div class=\"%1\">").arg(response.database));
	foreach (QString text, response.list) {
		text.truncate(maxLen);
		if (func != "html" && func != "xdxf")
			text = escape(text);
		html += "<dl class=\"descr\">";
		foreach (FormatPair fmt, fmap[func])
			if (fmt.first == "link")
				text = links(text);
			else {
				QRegExp exp(fmt.first);
				text.replace(exp, fmt.second);
			}
		html += text;
		html += "</dl>";
	}
	html += "</div>";
	return html;
}

QString Formatter::words(const QStringList &list)
{
	QString html;
	foreach (QString text, list) {
		text.truncate(maxLen);
		html += words(text);
	}
	return html;
}

QString Formatter::words(const QString &text)
{
	QString html;
	html += "<div class=\"define\">";
	html += links(escape(text));
	html += "</div>";
	return html;
}

}
