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



#include "cbookkeychooser.h"
#include "backend/cswordtreekey.h"
#include "backend/cswordbookmoduleinfo.h"
#include "frontend/cbtconfig.h"

//TQt includes
#include <tqlayout.h>
#include <tqmap.h>

TQMap<TQObject*, int> boxes;

CBookKeyChooser::CBookKeyChooser(ListCSwordModuleInfo modules, CSwordKey *key, TQWidget *parent, const char *name)
: CKeyChooser(modules, key, parent,name), m_layout(0) {

	setModules(modules, false);
	m_key = dynamic_cast<CSwordTreeKey*>(key);
	if (!m_modules.count()) {
		m_key = 0;
	}

	setModules(modules, true);
	setKey(key);

	adjustFont();
}

CBookKeyChooser::~CBookKeyChooser() {}

void CBookKeyChooser::setKey(CSwordKey* newKey) {
	setKey(newKey, true);
}

/** Sets a new key to this keychooser */
void CBookKeyChooser::setKey(CSwordKey* newKey, const bool emitSignal) {
	//tqDebug("CBookKeyChooser::setKey");
	if (m_key != newKey) {
		m_key = dynamic_cast<CSwordTreeKey*>(newKey);
	}

	/*const */TQString oldKey = m_key->key();

	if (oldKey.isEmpty()) { //don't set keys equal to "/", always use a key which may have content
		m_key->firstChild();
		oldKey = m_key->key();
	}
	const int oldOffset = m_key->getOffset();

	TQStringList siblings;
	if (m_key && !oldKey.isEmpty()) {
		siblings = TQStringList::split("/", oldKey, false);
	}

	int depth = 0;
	int index = 0;

	m_key->root();

	while( m_key->firstChild() && (depth <= int(siblings.count())) ) {
		const TQString key = m_key->key();
		index = (depth == 0) ? -1 : 0;
		const TQString sibling = siblings[depth];

		if (!sibling.isEmpty()) { //found it
			bool found = false;

			do {
				++index;
				//tqDebug("set 'found'");
				//found = (TQString::fromLocal8Bit(m_key->getLocalName()) == sibling);
				found = (m_key->getLocalNameUnicode() == sibling);
			}
			while (!found && m_key->nextSibling());

			if (!found) {
				m_key->key( key );
			}
		}

		setupCombo(key, depth, index);
		depth++;
	}

	//clear the combos which were not filled
	for (; depth < m_modules.first()->depth(); ++depth)  {
		CKeyChooserWidget* chooser = m_chooserWidgets.at(depth);
		if (chooser) {
			chooser->reset(0,0,false);
		}
	}

	if (oldKey.isEmpty()) {
		m_key->root();
	}
	else {
		//m_key->key(oldKey);
		m_key->setOffset(oldOffset);
	}

	if (emitSignal) {
		emit keyChanged(m_key);
	}
}

/** Returns the key of this kechooser. */
CSwordKey* const CBookKeyChooser::key() {
	return m_key;
}

/** Sets another module to this keychooser */
void CBookKeyChooser::setModules(const ListCSwordModuleInfo& modules, const bool refresh) {
	m_modules.clear();

	//   for (modules.first(); modules.current(); modules.next()) {
	ListCSwordModuleInfo::const_iterator end_it = modules.end();
	for (ListCSwordModuleInfo::const_iterator it(modules.begin()); it != end_it; ++it) {
		if ( (*it)->type() == CSwordModuleInfo::GenericBook ) {
			if (CSwordBookModuleInfo* book = dynamic_cast<CSwordBookModuleInfo*>(*it)) {
				m_modules.append(book);
			}
		}
	}

	//refresh the number of combos
	if (refresh && m_modules.count() && m_key) {
		if (!m_layout) {
			m_layout = new TQHBoxLayout(this);
		}

		//delete old widgets
		m_chooserWidgets.setAutoDelete(true);
		m_chooserWidgets.clear();
		m_chooserWidgets.setAutoDelete(false);

		for (int i = 0; i < m_modules.first()->depth(); ++i) {
			// Create an empty keychooser, don't handle next/prev signals
			CKeyChooserWidget* w = new CKeyChooserWidget(0, false, this);
			m_chooserWidgets.append( w );

			//don't allow a too high width, try to keep as narrow as possible
			//to aid users with smaller screen resolutions
			int totalWidth = 200; //only 1 level
			if (m_modules.first()->depth() > 1) {
				if (m_modules.first()->depth() > 3)
					totalWidth = 400; //4+ levels
				else
					totalWidth = 300; //2-3 levels
			}

			int maxWidth = (int) ((float) totalWidth / (float) m_modules.first()->depth());

			w->comboBox()->setMaximumWidth(maxWidth);
			w->comboBox()->setCurrentItem(0);

			connect(w, TQ_SIGNAL(changed(int)), TQ_SLOT(keyChooserChanged(int)));
			connect(w, TQ_SIGNAL(focusOut(int)), TQ_SLOT(keyChooserChanged(int)));

			m_layout->addWidget(w);
			boxes[w] = i;

			w->show();
		}

		//set the tab order of the key chooser widgets

		CKeyChooserWidget* chooser = 0;
		CKeyChooserWidget* chooser_prev = 0;
		const int count = m_chooserWidgets.count();
		for (int i = 0; i < count; ++i) {
			chooser = m_chooserWidgets.at(i);
			Q_ASSERT(chooser);

			if (chooser && chooser_prev) {
				TQWidget::setTabOrder(chooser_prev, chooser);
			}

			chooser_prev = chooser;
		}
		TQWidget::setTabOrder(chooser, 0);

		updateKey(m_key);
		adjustFont(); // only when refresh is set.
	}
}

/** No descriptions */
void CBookKeyChooser::adjustFont() {

	//Make sure the entries are displayed correctly.
	for ( CKeyChooserWidget* idx = m_chooserWidgets.first(); idx; idx = m_chooserWidgets.next() ) {
		idx->comboBox()->setFont( CBTConfig::get
									  ( m_modules.first()->language() ).second );
	}
}

/** Refreshes the content. */
void CBookKeyChooser::refreshContent() {
	if (m_key) {
		updateKey( m_key ); //refresh with current key
	}
}

void CBookKeyChooser::setupCombo(const TQString key, const int depth, const int currentItem) {
	CKeyChooserWidget* chooserWidget = m_chooserWidgets.at(depth);

	const unsigned long oldOffset = m_key->getOffset();
	m_key->key(key);

	if ((depth == 0) && chooserWidget && chooserWidget->comboBox()->count()) { //has already items
		//set now the right item
		if (CKeyChooserWidget* chooserWidget = m_chooserWidgets.at(depth)) {
			chooserWidget->setItem( chooserWidget->comboBox()->text(currentItem) );
		}

		m_key->setOffset(oldOffset);
		return;
	}


	//insert an empty item at the top
	TQStringList items;
	if (depth > 0) {
		items << TQString();
	}

	do {
		//items << TQString::fromLocal8Bit(m_key->getLocalName());
		items << m_key->getLocalNameUnicode();
	}
	while (m_key->nextSibling());

	if (chooserWidget) {
		chooserWidget->reset(items,currentItem,false);
	}

	//restore old key
	//  m_key->key(oldKey);
	m_key->setOffset( oldOffset );
}

/** A keychooser changed. Update and emit a signal if necessary. */
void CBookKeyChooser::keyChooserChanged(int /*newIndex*/) {
	const int activeID = boxes[const_cast<TQObject*>(sender())]; //no so good code!

	TQStringList items;
	CKeyChooserWidget* chooser;
	const int count = m_chooserWidgets.count();

	for (int i = 0; i < count; ++i) {
		chooser = m_chooserWidgets.at(i);
		const TQString currentText =
			(chooser && chooser->comboBox())
			? chooser->comboBox()->currentText()
			: TQString();

		if (currentText.isEmpty() || i > activeID) {
			break;
		}

		items << currentText;
	}

	TQString newKey("/");
	newKey.append(items.join("/"));
	if (newKey.length() > 1) {
		newKey.remove(newKey.length(),1); //remove the traling slash
	}

	//  tqWarning("key changed: setting to %s", newKey.latin1());
	m_key->key(newKey);
	setKey(m_key);
}

/** Updates the keychoosers for the given key but emit no signal. */
void CBookKeyChooser::updateKey(CSwordKey* key) {
	setKey(key, false);
}

#include "cbookkeychooser.moc"
