/**
 * \file QCitation.C
 * This file is part of LyX, the document processor.
 * Licence details can be found in the file COPYING.
 *
 * \author Angus Leeming
 * \author Kalle Dalheimer
 *
 * Full author contact details are available in file CREDITS.
 */

#include <config.h>

#include "QCitation.h"
#include "QCitationDialog.h"
#include "ui/QCitationFindDialogBase.h"
#include "Qt2BC.h"
#include "qt_helpers.h"

#include "bufferparams.h"

#include "controllers/ButtonController.h"
#include "controllers/ControlCitation.h"

#include "support/lstrings.h"

#include <qcheckbox.h>
#include <qcombobox.h>
#include <qlineedit.h>
#include <qlistbox.h>
#include <qmultilineedit.h>
#include <qpushbutton.h>
#include <qlabel.h>

using std::find;
using std::string;
using std::vector;

namespace lyx {

using support::getStringFromVector;
using support::getVectorFromString;
using support::trim;

namespace frontend {

typedef QController<ControlCitation, QView<QCitationDialog> > base_class;

QCitation::QCitation(Dialog & parent)
	: base_class(parent, _("Citation"))
{}


void QCitation::apply()
{
	vector<biblio::CiteStyle> const & styles =
		ControlCitation::getCiteStyles();

	int const choice = dialog_->citationStyleCO->currentItem();
	bool const full  = dialog_->fulllistCB->isChecked();
	bool const force = dialog_->forceuppercaseCB->isChecked();

	string const command =
		biblio::CitationStyle(styles[choice], full, force)
		.asLatexStr();

	controller().params().setCmdName(command);
	controller().params().setContents(getStringFromVector(citekeys));

	string const before = fromqstr(dialog_->textBeforeED->text());
	controller().params().setSecOptions(before);

	string const after = fromqstr(dialog_->textAfterED->text());
	controller().params().setOptions(after);

	style_ = choice;
	open_find_ = false;
}


void QCitation::hide()
{
	citekeys.clear();
	bibkeys.clear();
	open_find_ = true;

	QDialogView::hide();
}


void QCitation::build_dialog()
{
	dialog_.reset(new QCitationDialog(this));

	// Manage the ok, apply, restore and cancel/close buttons
	bcview().setOK(dialog_->okPB);
	bcview().setApply(dialog_->applyPB);
	bcview().setCancel(dialog_->closePB);
	bcview().setRestore(dialog_->restorePB);

	bcview().addReadOnly(dialog_->addPB);
	bcview().addReadOnly(dialog_->deletePB);
	bcview().addReadOnly(dialog_->upPB);
	bcview().addReadOnly(dialog_->downPB);
	bcview().addReadOnly(dialog_->citationStyleCO);
	bcview().addReadOnly(dialog_->forceuppercaseCB);
	bcview().addReadOnly(dialog_->fulllistCB);
	bcview().addReadOnly(dialog_->textBeforeED);
	bcview().addReadOnly(dialog_->textAfterED);

	open_find_ = true;
}


void QCitation::fillStyles()
{
	if (citekeys.empty()) {
		dialog_->citationStyleCO->setEnabled(false);
		dialog_->citationStyleLA->setEnabled(false);
		return;
	}

	int const orig = dialog_->citationStyleCO->currentItem();

	dialog_->citationStyleCO->clear();

	int curr = dialog_->selectedLB->currentItem();
	if (curr < 0)
		curr = 0;

	string key = citekeys[curr];

	vector<string> const & sty = controller().getCiteStrings(key);

	biblio::CiteEngine const engine = controller().getEngine();
	bool const basic_engine = engine == biblio::ENGINE_BASIC;

	dialog_->citationStyleCO->setEnabled(!sty.empty() && !basic_engine);
	dialog_->citationStyleLA->setEnabled(!sty.empty() && !basic_engine);

	for (vector<string>::const_iterator it = sty.begin();
		it != sty.end(); ++it) {
		dialog_->citationStyleCO->insertItem(toqstr(*it));
	}

	if (orig != -1 && orig < dialog_->citationStyleCO->count())
		dialog_->citationStyleCO->setCurrentItem(orig);
}


void QCitation::updateStyle()
{
	biblio::CiteEngine const engine = controller().getEngine();
	bool const natbib_engine =
		engine == biblio::ENGINE_NATBIB_AUTHORYEAR ||
		engine == biblio::ENGINE_NATBIB_NUMERICAL;
	bool const basic_engine = engine == biblio::ENGINE_BASIC;

	dialog_->fulllistCB->setEnabled(natbib_engine);
	dialog_->forceuppercaseCB->setEnabled(natbib_engine);
	dialog_->textBeforeED->setEnabled(!basic_engine);

	string const & command = controller().params().getCmdName();

	// Find the style of the citekeys
	vector<biblio::CiteStyle> const & styles =
		ControlCitation::getCiteStyles();
	biblio::CitationStyle const cs(command);

	vector<biblio::CiteStyle>::const_iterator cit =
		find(styles.begin(), styles.end(), cs.style);

	// restore the latest natbib style
	if (style_ >= 0 && style_ < dialog_->citationStyleCO->count())
		dialog_->citationStyleCO->setCurrentItem(style_);
	else
		dialog_->citationStyleCO->setCurrentItem(0);
	dialog_->fulllistCB->setChecked(false);
	dialog_->forceuppercaseCB->setChecked(false);

	if (cit != styles.end()) {
		int const i = int(cit - styles.begin());
		dialog_->citationStyleCO->setCurrentItem(i);
		dialog_->fulllistCB->setChecked(cs.full);
		dialog_->forceuppercaseCB->setChecked(cs.forceUCase);
	}
}


void QCitation::update_contents()
{
	// Make the list of all available bibliography keys
	bibkeys = biblio::getKeys(controller().bibkeysInfo());
	updateBrowser(dialog_->add_->availableLB, bibkeys);

	// Ditto for the keys cited in this inset
	citekeys = getVectorFromString(controller().params().getContents());
	updateBrowser(dialog_->selectedLB, citekeys);

	// No keys have been selected yet, so...
	dialog_->infoML->clear();
	dialog_->setButtons();

	dialog_->textBeforeED->setText(
		toqstr(controller().params().getSecOptions()));
	dialog_->textAfterED->setText(
		toqstr(controller().params().getOptions()));

	fillStyles();
	updateStyle();

	// open the find dialog if nothing has been selected (yet)
	// the bool prevents that this is also done after "apply"
	if (open_find_)
		dialog_->openFind();

	bc().valid(isValid());
}


void QCitation::updateBrowser(QListBox * browser,
			      vector<string> const & keys) const
{
	browser->clear();

	for (vector<string>::const_iterator it = keys.begin();
		it < keys.end(); ++it) {
		string const key = trim(*it);
		// FIXME: why the .empty() test ?
		if (!key.empty())
			browser->insertItem(toqstr(key));
	}
}


bool QCitation::isValid()
{
	return dialog_->selectedLB->count() > 0;
}


} // namespace frontend
} // namespace lyx
