/***************************************************************************
 *   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 "qalculateeditvariabledialog.h"
#include "qalculate_tde_utils.h"
#include "qalculateeditnamesdialog.h"

#include <string>
#include <tqgrid.h>
#include <klineedit.h>
#include <tqpushbutton.h>
#include <kcombobox.h>
#include <tqlabel.h>
#include <tdelocale.h>
#include <tqvbox.h>
#include <tqhbox.h>
#include <tqcheckbox.h>
#include <tdemessagebox.h>
#include <tqlayout.h>
#include <tdeapplication.h>

extern PrintOptions printops;
extern EvaluationOptions evalops;
extern tree_struct variable_cats;

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

	names_edit_dialog = NULL;
	edited_variable = NULL;

	setMainWidget(new TQWidget(this));	
	TQGridLayout *grid = new TQGridLayout(mainWidget(), 6, 2, 0, spacingHint());
	
	nameLabel = new TQLabel(i18n("Name:"), mainWidget());
	grid->addWidget(nameLabel, 0, 0);	
	nameEdit = new KLineEdit(mainWidget());
	grid->addWidget(nameEdit, 0, 1);
	
	TQHBoxLayout *hbox = new TQHBoxLayout(0, 0, spacingHint());
	grid->addMultiCellLayout(hbox, 1, 1, 0, 1);
	namesLabel = new TQLabel(mainWidget());
	namesLabel->setAlignment(TQt::AlignRight);
	namesLabel->setSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Preferred);
	hbox->addWidget(namesLabel);
	namesButton = new TQPushButton(i18n("Names Details"), mainWidget());
	hbox->addWidget(namesButton);
	
	valueLabel = new TQLabel(i18n("Value:"), mainWidget());
	grid->addWidget(valueLabel, 2, 0);
	valueEdit = new KLineEdit(mainWidget());
	grid->addWidget(valueEdit, 2, 1);
	
	hbox = new TQHBoxLayout(0, 0, spacingHint());
	grid->addMultiCellLayout(hbox, 3, 3, 0, 1);
	hbox->addItem(new TQSpacerItem(0, 0, TQSizePolicy::Expanding, TQSizePolicy::Minimum));
	valueExactButton = new TQCheckBox(i18n("Value is exact"), mainWidget());
	hbox->addWidget(valueExactButton);
	
	grid->addWidget(new TQLabel(i18n("Category:"), mainWidget()), 4, 0);
	categoryCombo = new KComboBox(mainWidget());
	grid->addWidget(categoryCombo, 4, 1);
	categoryCombo->setMaximumWidth(250);
	categoryCombo->setEditable(true);
	
	titleLabel = new TQLabel(i18n("Descriptive name:"), mainWidget());
	grid->addWidget(titleLabel, 5, 0);
	titleEdit = new KLineEdit(mainWidget());
	grid->addWidget(titleEdit, 5, 1);

	connect(namesButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(editNames()));
	connect(nameEdit, TQ_SIGNAL(textChanged(const TQString&)), this, TQ_SLOT(nameChanged(const TQString&)));
	
}

QalculateEditVariableDialog::~QalculateEditVariableDialog() {}

void QalculateEditVariableDialog::slotHelp() {
	TDEApplication::kApplication()->invokeHelp("qalculate-variable-creation");
}

void QalculateEditVariableDialog::slotOk() {
	std::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;
	}
	std::string str2 = valueEdit->text().ascii();
	remove_blank_ends(str2);
	if(!(init_value && force_init_value) && str2.empty()) {
		//no value -- open dialog again
		valueEdit->setFocus();
		KMessageBox::error(this, i18n("Empty value field"));
		return;
	}
	//variable with the same name exists -- overwrite or open dialog again
	if((!edited_variable || !edited_variable->hasName(str)) && (!names_edit_dialog || names_edit_dialog->isEmpty()) && CALCULATOR->variableNameTaken(str, edited_variable) && 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;
	}
	KnownVariable *v = edited_variable;
	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 = (KnownVariable*) var;
	}
	bool add_var = false;
	if(v) {
		//update existing variable
		v->setLocal(true);
		if(!v->isBuiltin()) {
			if(force_init_value && init_value) {
				v->set(*init_value);
			} else {
				v->set(CALCULATOR->unlocalizeExpression(valueEdit->text().ascii(), evalops.parse_options));
				v->setApproximate(!valueExactButton->isChecked());
			}
		}
	} else {
		//new variable
		if(force_init_value && init_value) {
			//forced value
			v = new KnownVariable("", "", *init_value, "", true);
		} else {
			v = new KnownVariable("", "", CALCULATOR->unlocalizeExpression(valueEdit->text().ascii(), evalops.parse_options), "", true);
			v->setApproximate(!valueExactButton->isChecked());
		}
		add_var = true;
	}
	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_variable = v;
	accept();
}

KnownVariable *QalculateEditVariableDialog::editVariable(TQString category, KnownVariable *v, MathStructure *initial_value, bool force_value) {

	nameEdit->setFocus();

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

	actionButton(Ok)->setEnabled(true);

	namesLabel->setText("");

	//TQStringList cats;
	TQString 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(initial_value && force_value) {
		valueEdit->hide();
		valueLabel->hide();
		namesButton->hide();
		namesLabel->hide();
		valueExactButton->hide();
	} else {
		valueEdit->show();
		valueLabel->show();
		namesButton->show();
		namesLabel->show();
		valueExactButton->show();
	}

	if(v) {
		//fill in original parameters
		set_name_label_and_entry(v, nameEdit, namesLabel);
		valueEdit->setText(get_value_string(v->get(), false, NULL));
		nameEdit->setReadOnly(v->isBuiltin());
		valueEdit->setReadOnly(v->isBuiltin());
		valueExactButton->setEnabled(!v->isBuiltin());
		categoryCombo->lineEdit()->setText(v->category().c_str());
		titleEdit->setText(v->title(false).c_str());
		valueExactButton->setChecked(!(*printops.is_approximate) && !v->isApproximate());
	} else {
		nameEdit->setReadOnly(false);
		valueEdit->setReadOnly(false);
		valueExactButton->setEnabled(true);

		//fill in default values
		nameEdit->setText(CALCULATOR->getName().c_str());
		namesLabel->setText("");
		if(initial_value && !force_value) valueEdit->setText(get_value_string(*initial_value));
		else valueEdit->setText("");
		categoryCombo->lineEdit()->setText(category);
		titleEdit->setText("");
		if(initial_value) valueExactButton->setChecked(!initial_value->isApproximate());
		else valueExactButton->setChecked(true);
		if(force_value) {
			valueEdit->setReadOnly(true);
			valueExactButton->setEnabled(false);
		}
	}

	init_value = initial_value;
	force_init_value = force_value;

	if(exec() == TQDialog::Accepted) {
		v = edited_variable;
		edited_variable = NULL;
		return v;
	}
	edited_variable = NULL;
	return NULL;
}

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

void QalculateEditVariableDialog::nameChanged(const TQString &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 "qalculateeditvariabledialog.moc"

