/***************************************************************************
 *   Copyright (C) 2005 by Niklas Knutsson                                 *
 *   nq@altern.org                                                         *
 *                                                                         *
 *   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.             *
 ***************************************************************************/
#include "qalculateeditunknownvariabledialog.h"
#include "qalculate_kde_utils.h"
#include "qalculateeditnamesdialog.h"

#include <qgrid.h>
#include <klineedit.h>
#include <qpushbutton.h>
#include <kcombobox.h>
#include <qlabel.h>
#include <klocale.h>
#include <qvbox.h>
#include <qhbox.h>
#include <qcheckbox.h>
#include <kmessagebox.h>
#include <qlayout.h>
#include <kapplication.h>

extern PrintOptions printops;
extern tree_struct variable_cats;

QalculateEditUnknownVariableDialog::QalculateEditUnknownVariableDialog(QWidget *parent, const char *name) : KDialogBase(parent, name, true, i18n("Edit Variable"), Ok | Cancel | Help, Ok, true) {

	names_edit_dialog = NULL;
	edited_unknown = NULL;

	setMainWidget(new QWidget(this));
	QGridLayout *grid = new QGridLayout(mainWidget(), 1, 1, 0, spacingHint());
	grid->addWidget(new QLabel(i18n("Name:"), mainWidget()), 0, 0);
	nameEdit = new KLineEdit(mainWidget());
	grid->addWidget(nameEdit, 0, 1);
	QHBoxLayout *hbox = new QHBoxLayout(0, 0, spacingHint());
	grid->addMultiCellLayout(hbox, 1, 1, 0, 1);
	namesLabel = new QLabel(mainWidget());
	namesLabel->setAlignment(Qt::AlignRight);
	namesLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
	hbox->addWidget(namesLabel);
	namesButton = new QPushButton(i18n("Names Details"), mainWidget());
	hbox->addWidget(namesButton);
	assumptionsBox = new QCheckBox(i18n("Custom assumptions:"), mainWidget());
	grid->addMultiCellWidget(assumptionsBox, 2, 2, 0, 1);
	typeLabel = new QLabel(i18n("Type"), mainWidget());
	grid->addWidget(typeLabel, 3, 0);
	typeCombo = new KComboBox(mainWidget());
	typeCombo->setMaximumWidth(250);
	typeCombo->setEditable(false);
	typeCombo->insertItem(i18n("Unknown"));
	typeCombo->insertItem(i18n("Not Matrix"));
	typeCombo->insertItem(i18n("Number"));
	typeCombo->insertItem(i18n("Complex Number"));
	typeCombo->insertItem(i18n("Real Number"));
	typeCombo->insertItem(i18n("Rational Number"));
	typeCombo->insertItem(i18n("Integer"));
	grid->addWidget(typeCombo, 3, 1);
	signLabel = new QLabel(i18n("Sign"), mainWidget());
	grid->addWidget(signLabel, 4, 0);
	signCombo = new KComboBox(mainWidget());
	signCombo->setMaximumWidth(250);
	signCombo->setEditable(false);
	signCombo->insertItem(i18n("Unknown"));
	signCombo->insertItem(i18n("Positive"));
	signCombo->insertItem(i18n("Non-Negative"));
	signCombo->insertItem(i18n("Negative"));
	signCombo->insertItem(i18n("Non-Positive"));
	signCombo->insertItem(i18n("Non-Zero"));
	grid->addWidget(signCombo, 4, 1);
	grid->addWidget(new QLabel(i18n("Category:"), mainWidget()), 5, 0);
	categoryCombo = new KComboBox(mainWidget());
	categoryCombo->setMaximumWidth(250);
	categoryCombo->setEditable(true);
	grid->addWidget(categoryCombo, 5, 1);
	grid->addWidget(new QLabel(i18n("Descriptive name:"), mainWidget()), 6, 0);
	titleEdit = new KLineEdit(mainWidget());
	grid->addWidget(titleEdit, 6, 1);

	connect(assumptionsBox, SIGNAL(toggled(bool)), typeCombo, SLOT(setEnabled(bool)));
	connect(assumptionsBox, SIGNAL(toggled(bool)), signCombo, SLOT(setEnabled(bool)));
	connect(assumptionsBox, SIGNAL(toggled(bool)), typeLabel, SLOT(setEnabled(bool)));
	connect(assumptionsBox, SIGNAL(toggled(bool)), signLabel, SLOT(setEnabled(bool)));
	connect(typeCombo, SIGNAL(activated(int)), this, SLOT(typeComboActivated(int)));
	connect(signCombo, SIGNAL(activated(int)), this, SLOT(signComboActivated(int)));
	connect(namesButton, SIGNAL(clicked()), this, SLOT(editNames()));
	connect(nameEdit, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&)));
	
}

QalculateEditUnknownVariableDialog::~QalculateEditUnknownVariableDialog() {}

void QalculateEditUnknownVariableDialog::typeComboActivated(int i) {
	if((AssumptionType) i <= ASSUMPTION_TYPE_COMPLEX && (AssumptionSign) signCombo->currentItem() != ASSUMPTION_SIGN_NONZERO) {
		signCombo->blockSignals(true);
		signCombo->setCurrentItem(ASSUMPTION_SIGN_UNKNOWN);
		signCombo->blockSignals(false);
	}
}
void QalculateEditUnknownVariableDialog::signComboActivated(int i) {
	if((AssumptionSign) i != ASSUMPTION_SIGN_NONZERO && (AssumptionSign) i != ASSUMPTION_SIGN_UNKNOWN && (AssumptionType) typeCombo->currentItem() <= ASSUMPTION_TYPE_COMPLEX) {
		typeCombo->blockSignals(true);
		typeCombo->setCurrentItem(ASSUMPTION_TYPE_REAL);
		typeCombo->blockSignals(false);
	}
}

void QalculateEditUnknownVariableDialog::slotHelp() {
	KApplication::kApplication()->invokeHelp("qalculate-variable-creation");
}
void QalculateEditUnknownVariableDialog::slotOk() {

	string str = nameEdit->text().ascii();
	remove_blank_ends(str);
	if(str.empty() && (!names_edit_dialog || names_edit_dialog->isEmpty())) {
		//no name -- open dialog again
		nameEdit->setFocus();
		KMessageBox::error(this, i18n("Empty name field"));
		return;
	}
	//variable with the same name exists -- overwrite or open dialog again
	if((!edited_unknown || !edited_unknown->hasName(str)) && (!names_edit_dialog || names_edit_dialog->isEmpty()) && CALCULATOR->variableNameTaken(str, edited_unknown) && KMessageBox::questionYesNo(this, i18n("An unit or variable with the same name already exists.\nDo you want to overwrite it?")) == KMessageBox::No) {
		nameEdit->setFocus();
		return;
	}
	
	UnknownVariable *v = edited_unknown;
	if(!v) {
		//no need to create a new variable when a variable with the same name exists
		Variable *var = CALCULATOR->getActiveVariable(str);
		if(var && var->isLocal() && !var->isKnown()) v = (UnknownVariable*) var;
	}
	bool add_var = false;
	if(v) {
		//update existing variable
		v->setLocal(true);
	} else {
		//new unknown variable
		v = new UnknownVariable("", "", "", true);
		add_var = true;
	}
	if(!v->isBuiltin()) {
		if(assumptionsBox->isChecked()) {
			if(!v->assumptions()) v->setAssumptions(new Assumptions());
			v->assumptions()->setType((AssumptionType) typeCombo->currentItem());
			v->assumptions()->setSign((AssumptionSign) signCombo->currentItem());
		} else {
			v->setAssumptions(NULL);
		}
	}
	v->setCategory(categoryCombo->lineEdit()->text().ascii());
	v->setTitle(titleEdit->text().ascii());
	if(!v->isBuiltin()) {
		if(names_edit_dialog) {
			names_edit_dialog->saveNames(v, str.c_str());
		} else {
			if(v->countNames() == 0) {
				ExpressionName ename(str);
				ename.reference = true;
				v->setName(ename, 1);
			} else {
				v->setName(str, 1);
			}
		}
	}
	if(add_var) {
		CALCULATOR->addVariable(v);
	}
	edited_unknown = v;
	accept();
}


UnknownVariable *QalculateEditUnknownVariableDialog::editVariable(QString category, UnknownVariable *v) {

	nameEdit->setFocus();

	if(names_edit_dialog) {
		delete names_edit_dialog;
		names_edit_dialog = NULL;
	}
	edited_unknown = v;
	if(v) {
		if(v->isLocal())
			setCaption(i18n("Edit Unknown Variable"));
		else
			setCaption(i18n("Edit Unknown Variable (global)"));
	} else {
		setCaption(i18n("New Unknown Variable"));
	}

	actionButton(Ok)->setEnabled(true);

	namesLabel->setText("");

	//QStringList cats;
	QString catstr;
	categoryCombo->clear();
	tree_struct *item, *item2;
	variable_cats.it = variable_cats.items.begin();
	if(variable_cats.it != variable_cats.items.end()) {
		item = &*variable_cats.it;
		++variable_cats.it;
		item->it = item->items.begin();
	} else {
		item = NULL;
	}

	catstr = "";
	while(item) {
		if(!catstr.isEmpty()) catstr += "/";
		catstr += item->item.c_str();
		categoryCombo->insertItem(catstr);
		while(item && item->it == item->items.end()) {
			int str_i = catstr.findRev("/");
			if(str_i < 0) {
				catstr = "";
			} else {
				catstr.truncate(str_i);
			}
			item = item->parent;
		}
		if(item) {
			item2 = &*item->it;
			++item->it;
			item = item2;
			item->it = item->items.begin();	
		}
	}

	if(v) {
		//fill in original parameters
		set_name_label_and_entry(v, nameEdit, namesLabel);
		nameEdit->setReadOnly(v->isBuiltin());
		assumptionsBox->setEnabled(!v->isBuiltin());
		categoryCombo->lineEdit()->setText(v->category().c_str());
		titleEdit->setText(v->title(false).c_str());
		if(v->assumptions()) {
			assumptionsBox->setChecked(true);
			typeCombo->setCurrentItem(v->assumptions()->type());
			signCombo->setCurrentItem(v->assumptions()->sign());
		} else {
			assumptionsBox->setChecked(false);
			typeCombo->setCurrentItem(CALCULATOR->defaultAssumptions()->type());
			signCombo->setCurrentItem(CALCULATOR->defaultAssumptions()->sign());
		}
	} else {
		nameEdit->setReadOnly(false);
		assumptionsBox->setChecked(true);

		//fill in default values
		nameEdit->setText(CALCULATOR->getName().c_str());
		namesLabel->setText("");
		categoryCombo->lineEdit()->setText(category);
		titleEdit->setText("");
		typeCombo->setCurrentItem(CALCULATOR->defaultAssumptions()->type());
		signCombo->setCurrentItem(CALCULATOR->defaultAssumptions()->sign());
	}
	signLabel->setEnabled(!v || (!v->isBuiltin() && v->assumptions()));
	typeLabel->setEnabled(!v || (!v->isBuiltin() && v->assumptions()));
	signCombo->setEnabled(!v || (!v->isBuiltin() && v->assumptions()));
	typeCombo->setEnabled(!v || (!v->isBuiltin() && v->assumptions()));

	if(exec() == QDialog::Accepted) {
		v = edited_unknown;
		edited_unknown = NULL;
		return v;
	}
	edited_unknown = NULL;
	return NULL;
}

void QalculateEditUnknownVariableDialog::editNames() {
	if(!names_edit_dialog) {
		names_edit_dialog = new QalculateEditNamesDialog(TYPE_VARIABLE, this);
		names_edit_dialog->setNames(edited_unknown, nameEdit->text(), false);
	} else {
		names_edit_dialog->setNames(edited_unknown, nameEdit->text(), true);
	}
	names_edit_dialog->exec();
	names_edit_dialog->setNamesLE(nameEdit, namesLabel);
}

void QalculateEditUnknownVariableDialog::nameChanged(const QString &name) {
	if(name.isNull()) return;
	if(!CALCULATOR->variableNameIsValid(name.ascii())) {
		nameEdit->blockSignals(true);
		nameEdit->setText(CALCULATOR->convertToValidVariableName(name.ascii()).c_str());
		nameEdit->blockSignals(false);
	}
}

#include "qalculateeditunknownvariabledialog.moc"

