/***************************************************************************
    File:         renderer.cpp
    Project:      Kio-Sword -- An ioslave for SWORD and KDE
    Copyright:    Copyright (C) 2004-2005 Luke Plant
 ***************************************************************************/

/***************************************************************************
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   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 General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

// Mine
#include "renderer.h"
#include "swordoptions.h"
#include "ks_osishtml.h"
#include "ks_gbfhtml.h"
#include "ks_thmlhtml.h"
#include "utils.h"
#include "swordutils.h"
#include "template.h"

// Sword
#include <swmgr.h>
#include <swkey.h>
#include <versekey.h>
#include <treekey.h>
#include <treekeyidx.h>
#include <plainhtml.h>
#include <rtfhtml.h>
#include <encfiltmgr.h>
#include <localemgr.h>
#include <regex.h>


// TDE
#include <tdelocale.h>

// TQt
#include <tqstring.h>
#include <tqstringlist.h>

// Standard C/C++
#include <vector>
#include <cstring>
#include <string>
#include <set>


using std::string;
using std::vector;
using std::set;
using std::list;

using namespace sword;

namespace KioSword
{
	static const TQString prev(" <li><a href=\"%2\" accesskey=\"p\">&laquo %1</a>");
	static TQString makePrevLink(const TQString& caption, const TQString& url)
	{
		return prev.arg(caption).arg(url);
	}
	
	static const TQString next(" <li><a href=\"%2\" accesskey=\"n\">%1 &raquo</a>");
	static TQString makeNextLink(const TQString& caption, const TQString& url)
	{
		return next.arg(caption).arg(url);
	}
	
	static const TQString treeup(" <li><a href=\"%3\" accesskey=\"u\">%1 %2</a>");
	static TQString makeTreeUpLink(const TQString& caption1, const TQString& caption2, const TQString& url)
	{
		return treeup.arg(caption1).arg(caption2).arg(url);
	}

	static const TQString bibleup(" <li><a href=\"%2\" accesskey=\"u\">%1</a>");
	static TQString makeBibleUpLink(const TQString& caption, const TQString& url)
	{
		return bibleup.arg(caption).arg(url);
	}

	static const TQString genlink(" <li><a href=\"%2\">%1</a>");
	static TQString makeGeneralLink(const TQString& caption, const TQString& url)
	{
		return genlink.arg(caption).arg(url);
	}
	
	Renderer::Renderer() : 
		sword::SWMgr(0, 0, true, new sword::EncodingFilterMgr(sword::ENC_UTF8)),
		m_osisfilter(0),
		m_gbffilter(0),
		m_thmlfilter(0),
		m_plainfilter(0),
		m_rtffilter(0)
	{
		for (int i = 0; i < NUM_MODULE_TYPES; i++) {
			m_moduleTypes.push_back("");
			m_moduleTypeNames.push_back(TQString(""));
		}
		
		m_moduleTypes[BIBLE]      = "Biblical Texts";
		m_moduleTypes[COMMENTARY] = "Commentaries";
		m_moduleTypes[LEXDICT]    = "Lexicons / Dictionaries";
		m_moduleTypes[GENERIC]    = "Generic Books";
		
		m_moduleTypeNames[BIBLE]      = i18n("Bibles");
		m_moduleTypeNames[COMMENTARY] = i18n("Commentaries");
		m_moduleTypeNames[LEXDICT]    = i18n("Lexicons & Dictionaries");
		m_moduleTypeNames[GENERIC]    = i18n("Other Books");
	}
	
	
	Renderer::~Renderer() {
		delete m_osisfilter;
		delete m_gbffilter;
		delete m_thmlfilter;
		delete m_plainfilter;
		delete m_rtffilter;
	}
	
	
 	void Renderer::setOptions(const SwordOptions& options) {
		setGlobalOption("Footnotes",		(options.footnotes() ? "On" : "Off"));
		setGlobalOption("Headings",		(options.headings() ? "On" : "Off"));
		setGlobalOption("Strong's Numbers",	(options.strongs() ? "On" : "Off"));
		setGlobalOption("Morphological Tags",	(options.morph() ? "On" : "Off"));
		setGlobalOption("Hebrew Cantillation",	(options.cantillation() ? "On" : "Off"));
		setGlobalOption("Hebrew Vowel Points",	(options.hebrewVowelPoints() ? "On" : "Off"));
		setGlobalOption("Greek Accents",	(options.greekAccents() ? "On" : "Off"));
		setGlobalOption("Lemmas",		(options.lemmas() ? "On" : "Off"));
		setGlobalOption("Cross-references",	(options.crossRefs() ? "On" : "Off"));
		setGlobalOption("Words of Christ in Red",(options.redWords() ? "On" : "Off"));
		
	
		if (options.variants() == -1)
			setGlobalOption("Variants", "All Readings");
		else if (options.variants() == 1)
			setGlobalOption("Variants", "Secondary Readings");
		else
			setGlobalOption("Variants", "Primary Readings");
			
		LocaleMgr::getSystemLocaleMgr()->setDefaultLocaleName(options.locale().latin1());
	}
	
	/** Return an HTML hyperlinked list of all modules,
	 * categorised, and including descriptions
	 */
	TQString Renderer::listModules(const SwordOptions &options) {
		TQString output;
		TQString temp;
		ModMap::iterator it;
		vector<const char *>::size_type i;
		SWModule *curMod;
		
		setOptions(options);
		
		if (Modules.empty()) {
			output += ("<p>" + i18n("No modules installed!") + "</p>\n");
			return output;
		}
		
		output += TQString("<div class='moduleslist'><h1>%1</h1>")
				.arg(i18n("Modules"));
			
		for  (i = 0; i < m_moduleTypes.size(); i++) {
			output += TQString("<h2 class='moduletype'>%1</h2>\n"
					"<ul>\n").arg(m_moduleTypeNames[i]);
			for (it = Modules.begin(); it != Modules.end(); it++) {
				curMod = (*it).second;
				if (!strcmp(curMod->Type(), m_moduleTypes[i])) {
					output += TQString("<li class='module'><a class='module' href=\"%3\">%1</a> : %2\n")
						.arg(curMod->Name())
						.arg(curMod->Description())
						.arg(swordUrl(curMod->Name(), options));
				}
			}
			output += "</ul>";
		}
		output += "</div>";
		return output;
	}
	
	/** Return a sorted list of all module names 
	*
	*/
	TQStringList Renderer::moduleList() {
		TQStringList output;
		ModMap::iterator it;
		SWModule *curMod;
		
		for (it = Modules.begin(); it != Modules.end(); it++) {
			curMod = (*it).second;
			output += TQString(curMod->Name());
		}
		output.sort();
		return output;
	}
	
	Renderer::ModuleType Renderer::getModuleType(sword::SWModule *module) {
		ModuleType modtype;
		vector<const char *>::size_type i;
		
		modtype = GENERIC; // default
		for  (i = 0; i < m_moduleTypes.size(); i++) {
			if (!strcmp(module->Type(), m_moduleTypes[i])) {
				modtype = (ModuleType)i;
				break;
			}
		}
		return modtype;
	}
	
	
	/** Add the relevant filter to a module
	*
	* This method checks to see whether we've already added
	* the Render filter to a module.  If so, then don't
	* create or attach another, but ensure the options used
	*
	*/
	void Renderer::setModuleFilter(SWModule *module, const SwordOptions* options) {
		SectionMap::iterator sit;
		ConfigEntMap::iterator eit;
		SWTextMarkup modformat = FMT_UNKNOWN;
		SWBuf encoding;
		SWFilter *filter = 0;
		
		if (m_modset.find(module) != m_modset.end())
			// already added
			return;
		
		
		// From corediatheke.cpp
		if ((sit = config->Sections.find(module->Name())) != config->Sections.end()) {
			if ((eit = (*sit).second.find("SourceType")) != (*sit).second.end()) {
				if (!strcasecmp((char *)(*eit).second.c_str(), "GBF"))
					modformat = FMT_GBF;
				else if (!strcasecmp((char *)(*eit).second.c_str(), "ThML"))
					modformat = FMT_THML;
				else if (!strcasecmp((char *)(*eit).second.c_str(), "OSIS"))
					modformat = FMT_OSIS;
			}
			// FIXME -  do something with this
			if  ((eit = (*sit).second.find("Encoding")) != (*sit).second.end()) 
				encoding = (*eit).second;
			else
				encoding = (SWBuf)"";
		}
	
		
		switch (modformat)
		{
			// TODO - all filters used should subclass
			// FilterBase and know how to write
			// KioSword urls correctly using SwordOptions
			case FMT_UNKNOWN :
			case FMT_PLAIN :
				if (!m_plainfilter)
					m_plainfilter = new PLAINHTML();
				filter = m_plainfilter;	
				break;
				
			case FMT_THML :
				if (!m_thmlfilter)
					m_thmlfilter = new ThMLHTML();
				m_thmlfilter->setSwordOptions(options);
				filter = m_thmlfilter;
				break;
				
			case FMT_GBF:
				if (!m_gbffilter)
					m_gbffilter = new GBFHTML();
				m_gbffilter->setSwordOptions(options);
				filter = m_gbffilter;
				break;
				
			case FMT_HTML:
				break;
				
			case FMT_HTMLHREF:
				break;
			
			case FMT_RTF:
				if (!m_rtffilter)
					m_rtffilter = new RTFHTML();
				filter = m_rtffilter;
				break;
				
			case FMT_OSIS:
				if (!m_osisfilter)
					m_osisfilter = new OSISHTML();
				m_osisfilter->setSwordOptions(options);
				filter = m_osisfilter;
				break;
			
			case FMT_WEBIF:
				break;
				
			default:
				break;
		}
		
		if (filter) {
			module->AddRenderFilter(filter);
			m_modset.insert(m_modset.begin(), module);
		}
	
	}
	
	void Renderer::moduleQuery(const TQString &modname, const TQString &ref, const SwordOptions &options, Template* tmplt) {
		TQString nav;
		SWModule *module = 0;
		SWKey *skey = 0;
		KeyType keyt = SWKEY;
		VerseKey *vk;
		TreeKey *tk;
		
		ModuleType modtype;	
	
		// Set the sword::Mgr options
		setOptions(options);
	
		// Find the module	
		module = getModule(modname.latin1());
		
		if (module == 0) {
			TQString output;
			output += "<p><span class='error'>" 
				+ i18n("The module '%1' could not be found.").arg(modname) 
				+ "</span></p><hr/>";
			output += listModules(options);
			tmplt->setContent(output);
			tmplt->setTitle(i18n("Module not found - Kio-Sword"));
		}
		else
		{
			setModuleFilter(module, &options);
			
			// Determine key type.
			skey = module->getKey();
			if (!(vk = dynamic_cast<VerseKey*>(skey))) {
				if (!(tk = dynamic_cast<TreeKey*>(skey))) {
					keyt = SWKEY;
				} else {
					keyt = TREEKEY;
				}
			} else {
				keyt = VERSEKEY;
			}
			modtype = getModuleType(module);
			
			nav += TQString("<li class='first'>%1 <a href=\"%3\">%2</a></li>")
				.arg(i18n("Module:"))
				.arg(modname)
				.arg(swordUrl(modname, options));
			
			if (keyt == VERSEKEY) {  // Should be just bibles and commentaries
				verseQuery(module, ref, options, modtype, tmplt, nav);
			} else if (keyt == TREEKEY) {
				treeQuery(module, ref, options, modtype, tmplt, nav);
			} else if (keyt == SWKEY) {
				normalQuery(module, ref, options, modtype, tmplt, nav);
			}			
			tmplt->setNav("<ul>" + nav + "</ul>");
			tmplt->setShowToggles(true);
		}
		return;
	}
	
	TQString Renderer::search(const TQString &modname, const TQString &query, const SearchType searchType, const SwordOptions &options) {
		SWModule *module = 0;
		TQString output;
		ListKey lk;
		int stype = SEARCH_WORDS;
		TQString stypename;
		ModuleType modtype;
		
		setOptions(options);
		
		// Find the module
		module = getModule(modname.latin1());
		
		if (module == 0) { 
			output += "<p><span class='error'>" 
				+ i18n("The module '%1' could not be found.").arg(modname) 
				+ "</span></p>";
			output += listModules(options);
			return output;
		}
		
		modtype = getModuleType(module);
		
		if (searchType == SEARCH_WORDS) {
			stype = -2;
			stypename = i18n("Word");
		} else if (searchType == SEARCH_PHRASE) {
			stype = -1;
			stypename = i18n("Phrase");
		} else if (searchType == SEARCH_REGEX) {
			stype = 0;
			stypename = i18n("Regular expression");
		}
		
		output += "<div  class='searchresults'><h1>" + i18n("Search results:") + "</h1>";
		output += TQString("<table><tr><td>%1</td><td><b>%2</b></td></tr><tr><td>%3</td><td><b>%4</b></td></tr><tr><td>%5</td><td><b>%6</b></td></tr></table>")
				.arg(i18n("Module:"))
				.arg(modname)
				.arg(i18n("Query:"))
				.arg(query)
				.arg(i18n("Search type:"))
				.arg(stypename);
				
		
		lk = module->search(query.utf8(), stype, REG_ICASE);
		if (lk.Count() == 0) {
			output += "<p>" +i18n("No matches returned.");
		} else {
			output += "<p>" + i18n("1 match returned:", "%1 matches returned:", lk.Count()).arg(lk.Count());
			output += "<ul>";
			for (int i = 0; i < lk.Count(); ++i) {
				TQString ref;
				ref = TQString::fromUtf8(lk.getElement(i)->getText());
				if (modtype == BIBLE) {
					module->setKey(lk.getElement(i));
					output += TQString("<li><a href=\"%3\">%1</a>: %2</li>")
							.arg(ref)
							.arg(renderText(module))
							.arg(swordUrl(modname, ref, options));
					
				} else {
					output += TQString("<li><a href=\"%2\">%1</a></li>")
							.arg(ref)
							.arg(swordUrl(modname, ref, options));
				}
			}
			output += "</ul>";
		}
		output += "</div>";
		return output;
	}
	
	TQString Renderer::renderText(SWModule *module) {
		return TQString::fromUtf8(module->RenderText());
	}
	
	/** Fill in template with formatted text for the query of a verse based module
	 * Links are appended to navlinks.
	 */
	void Renderer::verseQuery(SWModule *module, const TQString &ref, const SwordOptions &options, 
								ModuleType modtype, Template* tmplt, TQString &navlinks) {
		TQString modname(module->Name());
		TQString text;
		bool doindex = false;
		const char* modtextdir; // text direction of the module
		
		ListKey lk;
		VerseKey *vk = dynamic_cast<VerseKey*>(module->getKey());
		
		if (!vk) 
			return;
		
		// FIXME - why do I need this call to setLocale()?
		vk->setLocale(LocaleMgr::getSystemLocaleMgr()->getDefaultLocaleName());
		
		modtextdir = textDirection(module);
			
		vk->AutoNormalize(0);
		do { // dummy loop
			if (ref.isEmpty()) {
				doindex = true;
				break;
			}
			lk = vk->ParseVerseList(ref.utf8(), "Genesis 1:1", true);
			if (lk.Count() == 0) {
				text += "<p class=\"error\">" + i18n("Couldn't find reference '%1'.").arg(ref) + "</p>";
				doindex = true;
				break;
			}
			char book = 0;
			char testament = 0;
			int chapter = 0;
			bool upToBookListShown = false;
			for (int i = 0; i < lk.Count(); ++i) {
				VerseKey *element = dynamic_cast<VerseKey*>(lk.GetElement(i));
				if (element) {
					// Multiple verses
					char err = 0;
					
					// Check whether we have an entire book selected
					// (but treat single chapter books as if they were just
					// one chapter from a book)
					if (element->UpperBound().Chapter() > 1 &&
						isEntireBook(element) && !options.wholeBook()) {
						// List books and link for viewing entire book
						SwordOptions options_wholebook(options);
						options_wholebook.wholeBook.set(true); // set just for creating the URL
						text += TQString("<h2>%1</h2>"
								"<p>%2</p>"
								"<p class='chapterlist'>%3</p>")
								.arg(element->getBookName())
								.arg(i18n("Chapters:"))
								.arg(chapterList(modname, element, options))
							+ TQString("<p><a href=\"%2\">%1</a></p>")
								.arg(i18n("View entire book."))
								.arg(swordUrl(module->Name(), element->getBookName(), options_wholebook));
						if (!upToBookListShown)
						{
							navlinks += makeBibleUpLink(i18n("Books"),
										    swordUrl(modname, options));
							upToBookListShown = true;
						}
					} else {
						// chapter or verse range selected
						module->Key(element->LowerBound());
						if (lk.Count() == 1) {
							// add some navigation links 
							if (isSingleChapter(element)) {
								// get link to previous chapter
								module->decrement();
								if (!module->Error()) {
									navlinks += makePrevLink(bookChapter(module->getKey()), 
											     chapterLink(modname, module->getKey(), options));
								}
								// get link to book
								module->Key(element->LowerBound());
								navlinks += makeBibleUpLink(bookName(element),
											    bookLink(modname, element, options));
							} else {
								// less than a single chapter
								// get link to book
								navlinks += makeGeneralLink(bookName(element),
										bookLink(modname, element, options));
								// get link to chapter
								navlinks += makeBibleUpLink(bookChapter(element),
											    chapterLink(modname, element, options));
							}
						}
						
						// Headings plus text itself
						bool inDirectionedDiv = false;
						do  {
							VerseKey *curvk = dynamic_cast<VerseKey*>(module->getKey());
							if (curvk->Book() != book || curvk->Testament() != testament) {
								if (inDirectionedDiv)
								{
									// close it before carrying on
									text += "</div>";
									inDirectionedDiv = false;
								}
								text += "<h2>" + TQString(curvk->getBookName()) + "</h2>";
								chapter = 0;
							}
							if (curvk->Chapter() != chapter) {
								if (inDirectionedDiv)
								{
									// close it before carrying on
									text += "</div>";
									inDirectionedDiv = false;
								}
								text += "<h3>" + i18n("Chapter %1").arg(curvk->Chapter()) + "</h3>";
							}
							
							if (!inDirectionedDiv) {
								text += TQString("<div dir='%1'>").arg(modtextdir);
								inDirectionedDiv = true;
							}
								
							if (options.verseNumbers() && modtype == BIBLE) {
								text += TQString("<a class=\"versenumber\" href=\"%2\">%1</a> ")
									  .arg(curvk->Verse())
									  .arg(swordUrl(module->Name(), module->KeyText(), options));
							}
							text += renderText(module);
							text += " ";
							if (options.verseLineBreaks())
								text += "<br />";
							book = curvk->Book();
							testament = curvk->Testament();
							chapter = curvk->Chapter();
							
							module->increment(1);
						} while (module->Key() <= element->UpperBound() && !(err = module->Error()));
						
						// Close the final div
						if (inDirectionedDiv)
						{
							text += "</div>";
							inDirectionedDiv = false;
						}
						
						if (lk.Count() == 1) {
							if (isSingleChapter(element)) {
							// add some navigation links 
								if (!err) {
									navlinks += makeNextLink(bookChapter(module->getKey()),
												 chapterLink(modname, module->getKey(), options));
								}
							}
						}
					}
				} else {
					// Reset flags used by the multiple verse path
					book = 0;
					testament = 0;
					chapter = 0;
					// Single verse
					module->Key(*lk.GetElement(i));
					element = dynamic_cast<VerseKey*>(module->getKey());
					text += TQString("<h3>%1</h3>").arg(module->KeyText());
					text += TQString("<div dir='%1'>").arg(modtextdir);
					text += renderText(module);
					text += "</div>";
					if (lk.Count() == 1)
						navlinks += makeBibleUpLink(bookChapter(element),
									    chapterLink(modname, element, options));
				}
				if (i+1 != lk.Count())
					text += "<br />";
			}
		} while (false);
		
		// Title: depends on what got printed above
		TQString title;
		if (doindex) {
			if (!text.isEmpty()) { // an error message was printed
				text = TQString("<h1 class=\"moduletitle\">%1</h1>").arg(module->Description()).arg(ref) 
					+ text;
				title = "Error - Kio-Sword";
			} 
			else
			{
				title = TQString("%1 - Kio-Sword").arg(module->Name());
			}
		} else {
			if (modtype == COMMENTARY) {
				text = TQString("<h1 class=\"moduletitle\">%1</h1>").arg(module->Description())
					+ text;
				title = TQString("%1 - %2 - Kio-Sword")
						.arg(lk.getShortText())
						.arg(module->Name());
			} else if (modtype == BIBLE) {
				text += TQString("<div class=\"biblename\">(%1)</div>").arg(module->Description());
				title = TQString("%1 - %2 - Kio-Sword")
						.arg(lk.getShortText())
						.arg(module->Name());
			}
		}
		tmplt->setTitle(title);
		
		if (doindex) {
			if (!text.isEmpty())
				text += "<hr/>\n";
			if (options.doBibleIndex()) {
				text += "<h2>" + i18n("Books:") + "</h2>";
				text += indexBible(module, options);
			} else {
				SwordOptions options_doindex(options);
				options_doindex.doBibleIndex.set(true);
				text += TQString("<p><a href=\"%2\">%1</a></p>")
						.arg(i18n("Index of books"))
						.arg(swordUrl(modname, options_doindex));
			}
		}
		tmplt->setContent(text);
	}
	
	void Renderer::treeQuery(SWModule *module, const TQString &ref, const SwordOptions &options, 
				ModuleType modtype, Template* tmplt, TQString &navlinks) {
		TQString output;
		TQString modname(module->Name());
		bool doindex;
		TreeKey *tk = dynamic_cast<TreeKey*>(module->getKey());
		
		if (!tk)
			return;
		
		output += TQString("<h1 class=\"moduletitle\">%1</h1>").arg(module->Description());
		if (ref.isEmpty()) {
			doindex = true;
		} else {
			tk->Error(); // clear
			tk->setText(ref.utf8());
			doindex = false;
			if (tk->Error()) {
				output += "<p class=\"error\">" + i18n("Couldn't find section '%1'.").arg(ref) + "</p>";
				output += "<hr/>";
				doindex = true;
			} else {
				TQString link;
				output += renderText(module);
				if (tk->previousSibling()) {
					link = TQString::fromUtf8(module->KeyText()); // FIXME ? local8Bit or utf8
					navlinks += makePrevLink(shorten(link.section('/', -1, -1), 20),
								 swordUrl(modname, link, options));
					tk->nextSibling();
				}
				SWKey *saved = tk->clone();
				if (tk->parent()) {
					link = TQString::fromUtf8(module->KeyText());
					navlinks += makeTreeUpLink(i18n("Up:"),
							shorten(link.section('/', -1, -1), 20),
							swordUrl(modname, link, options));
					tk->copyFrom(*saved);
				}
				delete saved;
				if (tk->nextSibling()) {
					link = TQString::fromUtf8(module->KeyText());
					navlinks += makeNextLink(shorten(link.section('/', -1, -1), 20),
								 swordUrl(modname, link, options));
					tk->previousSibling();
				}
				if (tk->hasChildren()) {
					if (tk->firstChild());
					output += "<hr/>";
					output += indexTree(module, options, false, 1);
				}
			}
		}
		
		if (doindex) {
			output += "<h2>" + i18n("Contents:") + "</h2>";
			SwordOptions options_doindex(options);
			if (options.doFullTreeIndex()) {
				options_doindex.doFullTreeIndex.set(false);
				output += indexTree(module, options, true, -1);
				output += TQString("<p><a href=\"%2\">%1</a></p>")
						.arg(i18n("View simple index"))
						.arg(swordUrl(modname, options_doindex));
			} else {
				options_doindex.doFullTreeIndex.set(true);			
				output += indexTree(module, options, true, 1);
				output += TQString("<p><a href=\"%2\">%1</a></p>")
						.arg(i18n("View full index"))
						.arg(swordUrl(modname, options_doindex));
			}
			tmplt->setTitle(TQString("%1 - %2 - Kio-Sword").arg(tk->getShortText()).arg(module->Name()));
		}
		else
		{
			tmplt->setTitle(TQString("%1 - Kio-Sword").arg(module->Name()));
		}
		tmplt->setContent(output);
		
		
	}
	
	void Renderer::normalQuery(SWModule *module, const TQString &ref, const SwordOptions &options, 
								ModuleType modtype, Template* tmplt, TQString &navlinks) {
		TQString output;
		TQString modname(module->Name());
		bool doindex;
		SWKey *skey = module->getKey();
		
		output += TQString("<h1 class=\"moduletitle\">%1</h1>").arg(module->Description());
		
		if (ref.isEmpty()) {
			doindex = true;
		} else {
			skey->Error(); // clear
			skey->setText(ref.utf8());
			doindex = false;
			if (skey->Error()) {
				output += "<p class=\"error\">" + TQString(i18n("Couldn't find reference '%1'.")).arg(ref) + "</p>";
				output += "<hr>";
				doindex = true;
			} else {
				output += TQString("<h3>%1</h3>").arg(module->KeyText());
				output += renderText(module);
				module->decrement();
				TQString link;
				if (!module->Error()) {
					link = module->KeyText();
					navlinks += makePrevLink(link, swordUrl(modname, link, options));
					module->increment();
				}
				module->increment();
				if (!module->Error()) {
					link = module->KeyText();
					navlinks += makeNextLink(link, swordUrl(modname, link, options));
					module->decrement();
				}
			}
		}
		
		if (doindex) {
			if (((modtype == LEXDICT) && options.doDictIndex()) ||
			((modtype == GENERIC) && options.doOtherIndex())) {
				output += "<h2>" + i18n("Index:") + "</h2>";
				output += indexBook(module, options);
			} else {
				
				output += TQString("<form action='%2' method='get'>"
							"%1 <input type='text' name='query'>"
							"</form>")
							.arg(i18n("Enter query term: "))
							.arg(swordUrl(modname, options));
				
				SwordOptions options_doindex(options);
				options_doindex.doDictIndex.set(true);
				options_doindex.doOtherIndex.set(true);
				output += TQString("<p><a href=\"%2\">%1</a></p>")
						.arg(i18n("View complete index"))
						.arg(swordUrl(modname, options_doindex));
			}
			tmplt->setTitle(TQString("%1 - Kio-Sword").arg(module->Name()));
		}
		else
		{
			tmplt->setTitle(TQString("%1 - %2 - Kio-Sword").arg(skey->getShortText()).arg(module->Name()));
		}	
		tmplt->setContent(output);
	}
	
	/** Retrieves an HTML list of all the books in the module
	* 
	* @param module The module to retrieve. Must be a Bible/commentary
	*/
	
	TQString Renderer::indexBible(SWModule *module, const SwordOptions& options) {
		TQString output;
		char book;
		char testament;
		VerseKey *vk = dynamic_cast<VerseKey*>(module->getKey());
		
		if (!vk)
			return output;
		vk->setLocale(LocaleMgr::getSystemLocaleMgr()->getDefaultLocaleName());
			
		module->setSkipConsecutiveLinks(true);
		vk->AutoNormalize(1);
		module->setPosition(sword::TOP);
		
		book = vk->Book();
		testament = vk->Testament();
		
		output += "<ul>\n";
		while (vk->Testament() == testament) {
			while (vk->Book() == book && !module->Error()) {
				output += TQString("<li><a href=\"%2\">%1</a>\n")
					.arg(vk->getBookName())
					.arg(swordUrl(module->Name(), vk->getBookName(), options));
				vk->Book(++book);
			};
			// Move to new testament, if not there already.
			++testament;
			module->setPosition(sword::BOTTOM);
			book = 1;
			vk->Book(book);
		};
		output += "</ul>\n";
		module->setSkipConsecutiveLinks(false);
		return output;
	}
	
	
	/** Retrieves an HTML list of all the keys in a module
	* 
	* @param module The module to retrieve. Must have key type SWKey
	*/
	
	TQString Renderer::indexBook(SWModule *module, const SwordOptions& options) {
		TQString output;
		TQString ref;
		
		module->setPosition(sword::TOP);
		output += "<ul>\n";
		do {
			ref = TQString::fromUtf8(module->KeyText());
			output += TQString("<li><a href=\"%2\">%1</a></li>")
					.arg(ref)
					.arg(swordUrl(module->Name(), ref, options));
			(*module)++;
		} while(!module->Error()) ;
		output += "</ul>\n";
		return output;
	}
	
	/** Return the index of a tree-key based module
	*
	* @param module  The module to scan
	* @param fromTop If true, get the index from the top level
	* @param depth   How many levels to scan, -1 for all
	*/
	TQString Renderer::indexTree(SWModule *module, const SwordOptions& options, bool fromTop, const int depth) {
		TQString output;
		TQString ref;
		bool gonext;
		bool cont;
		
		TreeKey *tk = dynamic_cast<TreeKey*>(module->getKey());
		int mydepth = 1;
		
		if (!tk) 
			return output;
			
		if (fromTop) {
			tk->root();
			tk->firstChild();
		}
		
		output += "<ul>";
		cont = true;
		gonext = false;
		do {
			if (!gonext) {
				ref = TQString::fromUtf8(module->KeyText());
				output += TQString("<li><a href=\"%2\">%1</a>\n")
						.arg(ref.section('/', -1))
						.arg(swordUrl(module->Name(), ref, options));
			}
			if (!gonext && tk->hasChildren() && (mydepth < depth || depth == -1) ) {
				if (tk->firstChild()) {
					mydepth++;
					output += "<ul>";
					cont = true;
				} else {
					cont = false;
				}
			} else {
				if (tk->nextSibling()) {
					gonext = false;
					cont = true;
				} else {
					// try to go up a level
					cont = false;
					if (mydepth > 1) {
						if (tk->parent()) {
							mydepth--;
							output += "</ul>";
							cont = true;
							gonext = true;
						}
					}
				}
			}
		} while (cont);
		
		output += "</ul>";
		return output;
		
	}
	
	TQString Renderer::chapterList(const TQString &modname, const VerseKey *vk, const SwordOptions& options) {
		VerseKey cp(vk->LowerBound());
		TQString output;
		do {
			cp.Verse(0);
			if (!output.isNull()) output += " | ";
			output += TQString("<a href=\"%2\">%1</a>")
					.arg(cp.Chapter())
					.arg(chapterLink(modname, &cp, options));
			cp.Chapter(cp.Chapter()+1);
		} while (cp.Chapter() <= vk->UpperBound().Chapter()) ;
		return output;
	}
	
	TQString Renderer::chapterLink(const TQString &modname, const VerseKey *vk, const SwordOptions& options) {
		return swordUrl(modname, bookChapter(vk), options);
	}
	
	TQString Renderer::chapterLink(const TQString &modname, const SWKey *sk, const SwordOptions& options) {
		const VerseKey *vk = dynamic_cast<const VerseKey*>(sk);
		if (vk)
			return chapterLink(modname, vk, options);
		else
			return TQString::null;
	}
	
	TQString Renderer::bookLink(const TQString &modname, const VerseKey *vk, const SwordOptions& options) {
		return swordUrl(modname, bookName(vk), options);
	}
	
	TQString Renderer::bookLink(const TQString &modname, const SWKey *sk, const SwordOptions& options) {
		const VerseKey *vk = dynamic_cast<const VerseKey*>(sk);
		if (vk)
			return bookLink(modname, vk, options);
		else
			return TQString::null;
	}
	
	TQString Renderer::bookChapter(const VerseKey *vk)  {
		return TQString("%1 %2").arg(vk->getBookName()).arg(vk->Chapter());
	}
	
	TQString Renderer::bookChapter(const SWKey *sk)  {
		const VerseKey *vk = dynamic_cast<const VerseKey*>(sk);
		if (vk)
			return bookChapter(vk);
		else
			return TQString::null;
	}
	
	TQString Renderer::bookName(const VerseKey *vk)  {
		return TQString(vk->getBookName());
	}
	
	TQString Renderer::bookName(const SWKey *sk)  {
		const VerseKey *vk = dynamic_cast<const VerseKey*>(sk);
		if (vk)
			return bookName(vk);
		else
			return TQString::null;
	}
	
	TQStringList Renderer::availableLocales()
	{
		list<SWBuf> locales = LocaleMgr::getSystemLocaleMgr()->getAvailableLocales();
		list<SWBuf>::const_iterator it;
		list<SWBuf>::const_iterator it_end = locales.end();
		TQStringList output;
		for (it = locales.begin(); it != it_end; it++)
		{
			output.append(TQString((*it).c_str()));
		}
		return output;
	}
}
