/*********
*
* This file is part of BibleTime's source code, http://www.bibletime.info/.
*
* Copyright 1999-2006 by the BibleTime developers.
* The BibleTime source code is licensed under the GNU General Public License version 2.0.
*
**********/



#include "csearchdialogpages.h"

#include "csearchdialog.h"
#include "csearchanalysis.h"
#include "crangechooser.h"
#include "cmoduleresultview.h"
#include "csearchresultview.h"
#include "cmodulechooser.h"

#include "backend/cswordversekey.h"
#include "backend/cdisplayrendering.h"

#include "frontend/display/cdisplay.h"
#include "frontend/display/creaddisplay.h"

#include "util/cresmgr.h"
#include "util/ctoolclass.h"

//TQt includes
#include <tqlayout.h>
#include <tqpushbutton.h>
#include <tqlabel.h>
#include <tqregexp.h>
#include <tqeventloop.h>

//KDE includes
#include <tdelocale.h>
#include <kcombobox.h>
#include <kiconloader.h>
#include <tdemessagebox.h>
#include <kprogress.h>
#include <tdeapplication.h>

//Lucence includes
//#include "CLucene.h"
//#include "CLucene/util/Reader.h"
//#include "CLucene/util/Misc.h"
//#include "CLucene/util/dirent.h"

namespace Search {
	namespace Result {

/********************************************
************  StrongsResulClass *************
********************************************/
void StrongsResultClass::initStrongsResults(void) {
	using namespace Rendering;
	
	CDisplayRendering render;
	ListCSwordModuleInfo modules;
	CTextRendering::KeyTreeItem::Settings settings;
	TQString rText, lText, key;
	bool found;
	int sIndex;
	int count;
	int index;
	TQString text;

	modules.append(srModule);
	sword::ListKey& result = srModule->searchResult();

	count = result.Count();
	if (!count)
		return;
	TDEApplication::kApplication()->processEvents( 1 ); //1 ms only
	srList.clear();
	// for whatever reason the text "Parsing...translations." does not appear.
	// this is not critical but the text is necessary to get the dialog box
	// to be wide enough.
	KProgressDialog* progress = new KProgressDialog(0, "progressDialog", i18n("Parsing Stong's Numbers"), i18n("Parsing Stong's numbers for translations."), true);
	progress->setAllowCancel(false);
	progress->setMinimumDuration(0);
	progress->show();
	progress->raise();
	for (index = 0; index < count; index++){
		progress->progressBar()->setProgress( int( (index*100) / count ) );
 		TDEApplication::kApplication()->processEvents( 1 ); //1 ms only

		key = TQString::fromUtf8(result.GetElement(index)->getText());
		text = render.renderSingleKey(key, modules, settings);
		sIndex = 0;
		while ((rText = getStrongsNumberText(text, &sIndex)) != "")
			{
			StrongsResultList::iterator it;
			found = FALSE;
			for ( it = srList.begin(); it != srList.end(); ++it )
				{
				lText = (*it).keyText();
				if (lText == rText)
					{
					found = TRUE;
					(*it).addKeyName(key);
					break;
					}
				}
			if (found == FALSE)
				srList.append( StrongsResult(rText, key) );
			}
		}
	  delete progress;
	  progress = 0;
	//qHeapSort(srList);
	}

TQString StrongsResultClass::getStrongsNumberText(const TQString& verseContent, int *startIndex) {
	// get the strongs text
	int idx1, idx2, index;
	TQString sNumber, strongsText;
	//const bool cs = CSwordModuleSearch::caseSensitive;
	const bool cs = false;
	
	if (*startIndex == 0) {
		index = verseContent.find("<body", 0);
	}
	else {
		index = *startIndex;
	}
   
	// find all the "lemma=" inside the the content
	while((index = verseContent.find("lemma=", index, cs)) != -1) {
		// get the strongs number after the lemma and compare it with the
		// strongs number we are looking for
		idx1 = verseContent.find("\"", index) + 1;
		idx2 = verseContent.find("\"", idx1 + 1);
		sNumber = verseContent.mid(idx1, idx2 - idx1);
		if (sNumber == lemmaText) {
			// strongs number is found now we need to get the text of this node
			// search right until the ">" is found.  Get the text from here to
			// the next "<".
			index = verseContent.find(">", index, cs) + 1;
			idx2  = verseContent.find("<", index, cs);
			strongsText = verseContent.mid(index, idx2 - index);
			index = idx2;
			*startIndex = index;
 
			return(strongsText);
		}
		else {
			index += 6; // 6 is the length of "lemma="
		}
   }
   return TQString();
}

/********************************************
**********  CSearchDialogResultPage *********
********************************************/

CSearchResultPage::CSearchResultPage(TQWidget *parent, const char *name ) : 
		SearchResultsForm(parent, name) {
	initView();
	initConnections();
}

CSearchResultPage::~CSearchResultPage() {}

/** Initializes the view of this widget. */
void CSearchResultPage::initView() {
	TQVBoxLayout* frameLayout = new TQVBoxLayout(m_displayFrame, 0, 6, "frameLayout");
	m_previewDisplay = CDisplay::createReadInstance(0, m_displayFrame);
	frameLayout->addWidget(m_previewDisplay->view());
}

/** Sets the modules which contain the result of each. */
void CSearchResultPage::setSearchResult(ListCSwordModuleInfo modules) {
   const TQString searchedText = CSearchDialog::getSearchDialog()->searchText();
	reset(); //clear current modules

	m_modules = modules;
	m_moduleListBox->setupTree(modules, searchedText);

	//have a Bible or commentary in the modules?
	bool enable = false;
	//   for (modules.first(); !enable && modules.current(); modules.next()) {
	ListCSwordModuleInfo::iterator end_it = modules.end();
	for (ListCSwordModuleInfo::iterator it(modules.begin()); it != end_it; ++it) {
		if ((*it)->type() == CSwordModuleInfo::Bible ) {
			enable = true;
			break;
		};
	};
	m_analyseButton->setEnabled(enable);
}


/** Resets the current list of modules and the displayed list of found entries. */
void CSearchResultPage::reset() {
	m_moduleListBox->clear();
	m_resultListBox->clear();
	m_previewDisplay->setText(TQString());
	m_analyseButton->setEnabled(false);
	//   m_modules.setAutoDelete(false); //make sure we don't delete modules accidentally
	m_modules.clear();
}


/** Update the preview of the selected key. */
void CSearchResultPage::updatePreview(const TQString& key) {
	using namespace Rendering;

	CSwordModuleInfo* module = m_moduleListBox->activeModule();
	if ( module ) {
		const TQString searchedText = CSearchDialog::getSearchDialog()->searchText();
		//const int searchFlags = CSearchDialog::getSearchDialog()->searchFlags();

		TQString text;
		CDisplayRendering render;

		ListCSwordModuleInfo modules;
		modules.append(module);

		CTextRendering::KeyTreeItem::Settings settings;

		//for bibles render 5 context verses
		if (module->type() == CSwordModuleInfo::Bible) {
			CSwordVerseKey vk(module);
			vk.Headings(1);
			vk.key(key);

			((VerseKey*)(module->module()->getKey()))->Headings(1); //HACK: enable headings for VerseKeys

			//first go back and then go forward the keys to be in context
			vk.previous(CSwordVerseKey::UseVerse);
			vk.previous(CSwordVerseKey::UseVerse);
			
			//include Headings in display, they are indexed and searched too
			if (vk.Verse() == 1){
				if (vk.Chapter() == 1){
					vk.Chapter(0);
				}
				vk.Verse(0);
			}
			
			const TQString startKey = vk.key();

			vk.key(key);

			vk.next(CSwordVerseKey::UseVerse);
			vk.next(CSwordVerseKey::UseVerse);
			const TQString endKey = vk.key();

			settings.keyRenderingFace = CTextRendering::KeyTreeItem::Settings::CompleteShort;
			text = render.renderKeyRange(startKey, endKey, modules, key, settings);
		}
		//for commentaries only one verse, but with heading
		else if (module->type() == CSwordModuleInfo::Commentary) {
			CSwordVerseKey vk(module);
			vk.Headings(1);
			vk.key(key);
			
			((VerseKey*)(module->module()->getKey()))->Headings(1); //HACK: enable headings for VerseKeys

			//include Headings in display, they are indexed and searched too
			if (vk.Verse() == 1){
				if (vk.Chapter() == 1){
					vk.Chapter(0);
				}
				vk.Verse(0);
			}
			const TQString startKey = vk.key();

			vk.key(key);
			const TQString endKey = vk.key();

			settings.keyRenderingFace = CTextRendering::KeyTreeItem::Settings::NoKey;
			text = render.renderKeyRange(startKey, endKey, modules, key, settings);
		}
		else {
			text = render.renderSingleKey(key, modules, settings);
		}

		m_previewDisplay->setText( highlightSearchedText(text, searchedText/*, searchFlags*/) );
		m_previewDisplay->moveToAnchor( CDisplayRendering::keyToHTMLAnchor(key) );
	}
}

TQStringList CSearchResultPage::QueryParser(const TQString& queryString) {
	TQString token;
	TQStringList tokenList;
	int cnt, pos;

	token = "";
	cnt = 0;
	while(cnt < queryString.length()) {
		// add to token
		if ((queryString[cnt]).isLetterOrNumber() || (queryString[cnt] == '*')) {
			token = token + queryString[cnt];
			cnt++;
		}
		// token break
		else if (queryString[cnt] == ' ') {
			token = token.stripWhiteSpace();
			if ((token != "*") && (token != ""))
				tokenList.append(token);
			token = "";
			cnt++;
		}
		// clucene appears to ignore quoted strings in the sence
		// that it treats all the words within quoted strings as
		// regular tokens and not as a single token.
		else if (queryString[cnt] == '"') {
			cnt++;
		}
		// wild card - treat as a special token break
		//else if (queryString[cnt] == '*') {
		//	token = token + queryString[cnt];
		//	token = token.stripWhiteSpace();
		//	if ((token != "*") && (token != ""))
		//		tokenList.append(token);
		//	// start next token with wildcard (kin*m -> kin* *m)
		//	token = "*";
		//	cnt++;
		//}
		// the ! token is also a token break
		else if (queryString[cnt] == '!') {
			// store away current token
			token = token.stripWhiteSpace();
			if ((token != "*") && (token != ""))
				tokenList.append(token);
			// add the ! token
			tokenList.append("!");
			token = "";
			cnt++;
		}
		// the - token is also a token break
		else if (queryString[cnt] == '-') {
			// store away current token
			token = token.stripWhiteSpace();
			if ((token != "*") && (token != ""))
				tokenList.append(token);
			// add the ! token
			tokenList.append("-");
			token = "";
			cnt++;
		}
		// the + token is also a token break
		else if (queryString[cnt] == '+') {
			// store away current token
			token = token.stripWhiteSpace();
			if ((token != "*") && (token != ""))
				tokenList.append(token);
			// add the + token
			tokenList.append("+");
			token = "";
			cnt++;
		}
		// the || token is also a token break
		else if ((queryString[cnt] == '|') && (queryString[cnt+1] == '|')) {
			// store away current token
			token = token.stripWhiteSpace();
			if ((token != "*") && (token != ""))
				tokenList.append(token);
			// add the || token
			tokenList.append("||");
			token = "";
			cnt += 2;
		}
		// the && token is also a token break
		else if ((queryString[cnt] == '&') && (queryString[cnt+1] == '&')) {
			// store away current token
			token = token.stripWhiteSpace();
			if ((token != "*") && (token != ""))
				tokenList.append(token);
			// add the || token
			tokenList.append("&&");
			token = "";
			cnt += 2;
		}
		else cnt++;
	}
	token = token.stripWhiteSpace();
	if ((token != "*") && (token != ""))
		tokenList.append(token);
	
	cnt = 0;
	TQStringList::iterator it;
	for ( it = tokenList.begin(); it != tokenList.end(); it++ ) {
		//-----------------------------------------------------------
		// remove all the NOT(!) tokens - these do not need to be
		// highlighted in the highlighter
		//-----------------------------------------------------------
		if (((*it) == "!") || ((*it) == "NOT") || ((*it) == "-")) {
			it = tokenList.remove(it);
			if (it == tokenList.end())
				break;
			it = tokenList.remove(it);
			if (it == tokenList.end())
				break;
			it--;
		}
		//-----------------------------------------------------------
		// remove all the operator tokens - these do not need to be
		// highlighted in the highlighter
		//-----------------------------------------------------------
		else if ( ((*it) == "||")  || ((*it) == "OR") || ((*it) == "+") ||
		     ((*it) == "AND") || ((*it) == "&&") )
		{
			it = tokenList.remove(it);
			if (it == tokenList.end())
				break;
			it--;
		}
		// if the token contains a ^ then trim the remainder of the
		// token from the ^
		else if ( (pos = (*it).contains("^")) >= 0 ) {
			(*it) = (*it).left(pos - 1); 
		}
		// if the token contains a ~ then trim the remainder of the
		// token from the ~
		else if ( (pos = (*it).contains("~")) >= 0 ) {
			(*it) = (*it).left(pos - 2) + "*"; 
		}
	}	
	return(tokenList);
}

const TQString CSearchResultPage::highlightSearchedText(const TQString& content, const TQString& searchedText/*, const int searchFlags*/) {
	TQString ret = content;

	//const bool cs = (searchFlags & CSwordModuleSearch::caseSensitive);
	const bool cs = false;
	
	//   int index = 0;
	int index = ret.find("<body", 0);
	int matchLen = 0;
	int length = searchedText.length();

	const TQString rep1("<span style=\"background-color:#FFFF66;\">");
	const TQString rep2("</span>");
	const unsigned int repLength = rep1.length() + rep1.length();
	int sstIndex; // strong search text index for finding "strong:"
	bool inQuote;
	TQString newSearchText;

	newSearchText = searchedText;
	//---------------------------------------------------------------------
	// find the strongs search lemma and highlight it
	//---------------------------------------------------------------------
	// search the searched text for "strong:" until it is not found anymore
	sstIndex = 0;
	while ((sstIndex = newSearchText.find("strong:", sstIndex)) != -1) {
		int idx1, idx2, sTokenIndex, sTokenIndex2;
		TQString sNumber, lemmaText;
		const TQString rep3("style=\"background-color:#FFFF66;\" ");
		const unsigned int rep3Length = rep3.length();
		int strongIndex = index;
		//--------------------------------------------------
		// get the strongs number from the search text
		//--------------------------------------------------
		// first find the first space after "strong:"
		//	 this should indicate a change in search token
		sstIndex = sstIndex + 7;
		sTokenIndex  = newSearchText.find(" ", sstIndex);
		sTokenIndex2 = newSearchText.find("|", sstIndex);
		if ((sTokenIndex2 != -1) && (sTokenIndex2 < sTokenIndex)) {
			sNumber = newSearchText.mid(sstIndex, sTokenIndex2 - sstIndex);
		}
		else {
			sNumber = newSearchText.mid(sstIndex, sTokenIndex - sstIndex);
		}
		// remove this strong entry
		sstIndex -= 7;
		newSearchText.replace(sstIndex, sTokenIndex - sstIndex, "");
		// find all the "lemma=" inside the the content
		while((strongIndex = ret.find("lemma=", strongIndex, cs)) != -1) {
			// get the strongs number after the lemma and compare it with the
			// strongs number we are looking for
			idx1 = ret.find("\"", strongIndex) + 1;
			idx2 = ret.find("\"", idx1 + 1);
			lemmaText = ret.mid(idx1, idx2 - idx1);
			if (lemmaText == sNumber) {
				// strongs number is found now we need to highlight it
				// I believe the easiest way is to insert rep3 just before "lemma="
				ret = ret.insert(strongIndex, rep3);
				strongIndex += rep3Length;
				}
			strongIndex += 6; // 6 is the length of "lemma="
			}
		}
	//---------------------------------------------------------------------
	// now that the strong: stuff is out of the way continue with
	// other search options
	//---------------------------------------------------------------------
	//-----------------------------------------------------------
	// try to figure out how to use the lucene query parser
	//-----------------------------------------------------------
	//using namespace lucene::queryParser;
	//using namespace lucene::search;
	//using namespace lucene::analysis;
	//using namespace lucene::util;

	//wchar_t *buf;
	//char buf8[1000];
	//standard::WhitespaceAnalyzer analyzer;
	//lucene_utf8towcs(m_wcharBuffer, searchedText.utf8(), MAX_CONV_SIZE);
	//util::scoped_ptr<Query> q( QueryParser::parse(m_wcharBuffer, _T("content"), &analyzer) );
	//StringReader reader(m_wcharBuffer);
	//TokenStream* tokenStream = analyzer.tokenStream( _T("field"), &reader);
	//Token token;
	//while(tokenStream->next(&token) != 0) {
	//	lucene_wcstoutf8(buf8, token.termText(), 1000);
	//	printf("%s\n", buf8);
	//}

	//===========================================================
	// since I could not figure out the lucene query parser, I
	// made a simple parser.
	//===========================================================
	TQStringList words = QueryParser(newSearchText);
	for ( int wi = 0; (unsigned int)wi < words.count(); ++wi ) { //search for every word in the list
		TQRegExp findExp;
		TQString word = words[ wi ];
		if (word.contains("*")) {
			length = word.length() - 1;
			word.replace('*', "\\S*"); //match within a word
			findExp = TQRegExp(word);
			findExp.setMinimal(TRUE);
		}
		else {
			length = word.length();
			findExp = TQRegExp("\\b" + word + "\\b");
		}

		//       index = 0; //for every word start at the beginning
		index = ret.find("<body", 0);
		findExp.setCaseSensitive(cs);
		//while ( (index = ret.find(findExp, index)) != -1 ) { //while we found the word
		while ( (index = findExp.search(ret, index)) != -1 ) { //while we found the word
			matchLen = findExp.matchedLength();
			if (!CToolClass::inHTMLTag(index, ret)) {
				length = matchLen;
				ret = ret.insert( index+length, rep2 );
				ret = ret.insert( index, rep1 );
				index += repLength;
			}
			index += length;
		}
	}
	//tqWarning("\n\n\n%s", ret.latin1());
	return ret;
};

/** Initializes the signal slot conections of the child widgets, */
void CSearchResultPage::initConnections() {
	connect(m_resultListBox, TQT_SIGNAL(keySelected(const TQString&)),
			this, TQT_SLOT(updatePreview(const TQString&)));
	connect(m_moduleListBox, TQT_SIGNAL(moduleSelected(CSwordModuleInfo*)),
			m_resultListBox, TQT_SLOT(setupTree(CSwordModuleInfo*)));
	connect(m_moduleListBox, TQT_SIGNAL(moduleChanged()),
			m_previewDisplay->connectionsProxy(), TQT_SLOT(clear()));
	connect(m_analyseButton, TQT_SIGNAL(clicked()), TQT_SLOT(showAnalysis()));
   // connect the strongs list
   connect(m_moduleListBox, TQT_SIGNAL(strongsSelected(CSwordModuleInfo*, TQStringList*)),
         m_resultListBox, TQT_SLOT(setupStrongsTree(CSwordModuleInfo*, TQStringList*)));
}

/** Shows a dialog with the search analysis of the current search. */
void CSearchResultPage::showAnalysis() {
	Analysis::CSearchAnalysisDialog dlg(m_modules, this);
	dlg.exec();
}

	} //end of namespace Search.Result

	/*************************/

	namespace Options {

CSearchOptionsPage::CSearchOptionsPage(TQWidget *parent, const char *name ) :
	SearchOptionsForm(parent,name) {
	initView();
	readSettings();
}

CSearchOptionsPage::~CSearchOptionsPage() {
	saveSettings();
}

/** Returns the search text set in this page. */
const TQString CSearchOptionsPage::searchText() {
	return m_searchTextCombo->currentText();
}

/** Sets the search text used in the page. */
void CSearchOptionsPage::setSearchText(const TQString& text) {
	bool found = false;
	int i = 0;
	for (i = 0; !found && i < m_searchTextCombo->count(); ++i) {
		if (m_searchTextCombo->text(i) == text) {
			found = true;
		}
	}
   // This is needed because in the for loop i is incremented before the comparison (++i)
   // As a result the index i is actually one greater than expected.
   i--;
	if (!found) {
		i = 0;
		m_searchTextCombo->insertItem( text,0 );
	}

	m_searchTextCombo->setCurrentItem(i);
	m_searchTextCombo->reset();
	m_searchTextCombo->setFocus();
}

/** Initializes this page. */
void CSearchOptionsPage::initView() {
	connect( m_searchTextCombo, TQT_SIGNAL(activated( const TQString& )),
				m_searchTextCombo, TQT_SLOT( addToHistory( const TQString& ))
			);
	connect( m_searchTextCombo, TQT_SIGNAL(returnPressed ( const TQString& )),
				m_searchTextCombo, TQT_SLOT(addToHistory(const TQString&))
			);
	TQToolTip::add(m_searchTextCombo, CResMgr::searchdialog::options::searchedText::tooltip);

	m_syntaxButton->setIconSet(SmallIconSet("contexthelp"));
	connect( m_syntaxButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(syntaxHelp()));

	m_chooseModulesButton->setIconSet(SmallIconSet("wizard"));
	connect(m_chooseModulesButton, TQT_SIGNAL(clicked()),
			this, TQT_SLOT(chooseModules()));
	TQToolTip::add
		(m_chooseModulesButton, CResMgr::searchdialog::options::moduleChooserButton::tooltip);
		
	TQToolTip::add
		(m_rangeChooserCombo, CResMgr::searchdialog::options::chooseScope::tooltip);
	refreshRanges();

	m_chooseRangeButton->setIconSet(SmallIconSet("configure"));
	connect(m_chooseRangeButton, TQT_SIGNAL(clicked()),
			this, TQT_SLOT(setupRanges()));

	//set the initial focus
	m_searchTextCombo->setFocus();
}

/** Sets the modules used by the search. */
void CSearchOptionsPage::setModules( ListCSwordModuleInfo modules ) {
	TQString t = i18n("Searching in: ");

	m_modules.clear(); //remove old modules
	ListCSwordModuleInfo::iterator end_it = modules.end();

	for (ListCSwordModuleInfo::iterator it(modules.begin()); it != end_it; ++it) {
		//ToDo:  Check for containsRef compat
		if (*it == 0) { //don't operate on null modules.
			continue;
		}
		
		if ( !m_modules.contains(*it) ) {
			m_modules.append( *it );
			t.append( (*it)->name() );
			if (*it != modules.last()) {
				t += TQString::fromLatin1(", "); // so that it will become a readable list (WLC, LXX, GerLut...)
			}
		}
	};
	m_modulesLabel->setText(t);
	emit( sigSetSearchButtonStatus( (modules.count() != 0) ) );
}

/** Opens the modules chooser dialog. */
void CSearchOptionsPage::chooseModules() {
	CModuleChooserDialog* dlg = new CModuleChooserDialog(this, modules());
	connect(dlg, TQT_SIGNAL(modulesChanged(ListCSwordModuleInfo)),
			this, TQT_SLOT(setModules(ListCSwordModuleInfo)));
	dlg->exec();
}

/** Returns the list of used modules. */
const ListCSwordModuleInfo CSearchOptionsPage::modules() {
	return m_modules;
}

/** Sets all options back to the default. */
void CSearchOptionsPage::reset() {
	m_rangeChooserCombo->setCurrentItem(0); //no scope
	m_searchTextCombo->clearEdit();
}

/** Reads the settings for the searchdialog from disk. */
void CSearchOptionsPage::saveSettings() {
	CBTConfig::set
		(CBTConfig::searchCompletionTexts, m_searchTextCombo->completionObject()->items());
	CBTConfig::set
		(CBTConfig::searchTexts, m_searchTextCombo->historyItems());
}

/** Reads the settings of the last searchdialog session. */
void CSearchOptionsPage::readSettings() {
	m_searchTextCombo->completionObject()->setItems( CBTConfig::get
				(CBTConfig::searchCompletionTexts) );
	m_searchTextCombo->setHistoryItems( CBTConfig::get
											(CBTConfig::searchTexts) );
}

void CSearchOptionsPage::aboutToShow() {
	m_searchTextCombo->setFocus();
}

/** No descriptions */
void CSearchOptionsPage::setupRanges() {
	CRangeChooserDialog* chooser = new CRangeChooserDialog(this);
	chooser->exec();

	refreshRanges();
}

/** No descriptions */
void CSearchOptionsPage::syntaxHelp() {
	TQString syntax = i18n (
			"<p>Enter search terms separated by spaces.  By default the search "
			"function will return results that match any of the search terms (OR). "
			"To search for all the terms separate the terms by AND.</p>") + i18n(
			"<p>You can use wildcards: '*' matches any sequence of characters, "
			"while '?' matches any single character. The use of brackets allows you to "
			"group your search terms, e.g. '(Jesus OR spirit) AND God'.</p>") + i18n(
			"<p>To search text other than the main text, enter the text type followed "
			"by \":\", and then the search term.  For example, to search for the Strong's "
			"number H8077, use 'strong:H8077'.</p>") + i18n(
			"<p>Available text types:<br><table>"
			"<tr><td>heading:</td><td>searches headings</td></tr>"
			"<tr><td>footnote:</td><td>searches footnotes</td></tr>"
			"<tr><td>strong:</td><td>searches Strong's Numbers</td></tr>"
			"<tr><td>morph:</td><td>searches morphology codes</td></tr></table></p>") + i18n(
			"<p>BibleTime uses the Lucene search engine to perform your searches. "
			"It has many advanced features, and you can read more about it here: "
			"<a href=\"http://lucene.apache.org/java/docs/queryparsersyntax.html\">"
			"http://lucene.apache.org/java/docs/queryparsersyntax.html</a></p>");

	KMessageBox::about( this, syntax, i18n("Basic Search Syntax Introduction"));
}


/** refreshes the listof ranges and the range combobox. */
void CSearchOptionsPage::refreshRanges() {
	//the first two options are fixed, the others can be edited using the "Setup ranges" button.
	m_rangeChooserCombo->clear();
	m_rangeChooserCombo->insertItem(i18n("No search scope"));
	//m_rangeChooserCombo->insertItem(i18n("Last search result"));

	//insert the user-defined ranges
	CBTConfig::StringMap map = CBTConfig::get
								   (CBTConfig::searchScopes);
	CBTConfig::StringMap::Iterator it;
	for (it = map.begin(); it != map.end(); ++it) {
		m_rangeChooserCombo->insertItem(it.key());
	};
}

/** Returns the selected search scope if a search scope was selected. */
sword::ListKey CSearchOptionsPage::searchScope() {
	if (m_rangeChooserCombo->currentItem() > 0) { //is not "no scope"
		CBTConfig::StringMap map = CBTConfig::get(CBTConfig::searchScopes);
		
		TQString scope = map[ m_rangeChooserCombo->currentText() ];
		if (!scope.isEmpty()) {
			return sword::VerseKey().ParseVerseList( (const char*)scope.utf8(), "Genesis 1:1", true);
		}
	}
	
	return sword::ListKey();
}

/*!
    \fn CSearchOptionsPage::hasSearchScope()
 */
bool CSearchOptionsPage::hasSearchScope() {
	return (searchScope().Count() > 0);
}

	} //end of namespace Options
} //end of namespace Search

#include "csearchdialogpages.moc"
