/***************************************************************************
 *   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 "qalculatevariablesdialog.h"
#include "qalculate_tde_utils.h"
#include "qalculateeditvariabledialog.h"
#include "qalculateeditmatrixvectordialog.h"
#include "qalculateeditunknownvariabledialog.h"
#include "qalculateexportcsvdialog.h"
#include <vector>
#include <string>
#include <kpushbutton.h>
#include <tqsplitter.h>
#include <tqvbox.h>
#include <tqhbox.h>
#include <tdelistview.h>
#include <tdemessagebox.h>
#include <tdelocale.h>
#include <tqlayout.h>
#include <tdeapplication.h>
#include <kstdguiitem.h>

extern tree_struct variable_cats;
extern std::vector<void*> ia_variables;

QalculateVariablesDialog::QalculateVariablesDialog(TQWidget *parent, const char *name) : KDialog(parent, name, false) {

	export_csv_dialog = NULL;
	variable_edit_dialog = NULL;
	matrix_edit_dialog = NULL;
	unknown_edit_dialog = NULL;
	selected_category = "";
	selected_variable = NULL;

	TQHBoxLayout *layout = new TQHBoxLayout(this, marginHint(), spacingHint());
	
	setCaption(i18n("Variables"));

	TQSplitter *splitter = new TQSplitter(TQt::Horizontal, this);
	layout->addWidget(splitter);

	categoryView = new TDEListView(splitter);
	categoryView->addColumn(i18n("Category"));

	variableView = new TDEListView(splitter);
	variableView->addColumn(i18n("Variable Name"));
	variableView->addColumn(i18n("Value"));
	variableView->setRootIsDecorated(false);

	TQVBoxLayout *buttonLayout = new TQVBoxLayout(layout, spacingHint());
	
	newButton = new TQPushButton(i18n("New"), this);
	buttonLayout->addWidget(newButton);
	editButton = new TQPushButton(i18n("Edit"), this);
	editButton->setEnabled(false);
	buttonLayout->addWidget(editButton);
	deleteButton = new TQPushButton(i18n("Delete"), this);
	deleteButton->setEnabled(false);
	buttonLayout->addWidget(deleteButton);
	deactivateButton = new TQPushButton(i18n("Deactivate"), this);
	deactivateButton->setEnabled(false);
	buttonLayout->addWidget(deactivateButton);
	insertButton = new TQPushButton(i18n("Insert"), this);
	insertButton->setEnabled(false);
	buttonLayout->addWidget(insertButton);
	exportButton = new TQPushButton(i18n("Export"), this);
	exportButton->setEnabled(false);
	buttonLayout->addWidget(exportButton);
	buttonLayout->addItem(new TQSpacerItem(0, 0, TQSizePolicy::Minimum, TQSizePolicy::Expanding));
	helpButton = new KPushButton(KStdGuiItem::help(), this);
	buttonLayout->addWidget(helpButton);
	buttonClose = new KPushButton(KStdGuiItem::close(), this);
	buttonClose->setFocus();
	buttonLayout->addWidget(buttonClose);

	resize(TQSize(675, 375).expandedTo(size()));

	connect(buttonClose, SIGNAL(clicked()), this, SLOT(close()));
	connect(newButton, SIGNAL(clicked()), this, SLOT(newVariable()));
	connect(editButton, SIGNAL(clicked()), this, SLOT(editVariable()));
	connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteVariable()));
	connect(deactivateButton, SIGNAL(clicked()), this, SLOT(deactivateVariable()));
	connect(insertButton, SIGNAL(clicked()), this, SLOT(insertVariable()));
	connect(exportButton, SIGNAL(clicked()), this, SLOT(exportVariable()));
	connect(variableView, SIGNAL(selectionChanged()), this, SLOT(variableSelected()));
	connect(variableView, SIGNAL(doubleClicked(TQListViewItem*)), this, SLOT(variableDoubleClicked(TQListViewItem*)));
	connect(categoryView, SIGNAL(selectionChanged()), this, SLOT(categorySelected()));
	connect(helpButton, SIGNAL(clicked()), this, SLOT(slotHelp()));

}

QalculateVariablesDialog::~QalculateVariablesDialog() {}

void QalculateVariablesDialog::slotHelp() {
	TDEApplication::kApplication()->invokeHelp("qalculate-managers");
}

void QalculateVariablesDialog::updateVariableTree() {
	variableItems.clear();
	categoryItems.clear();
	categoryView->clear();
	TQListViewItem *i = new TDEListViewItem(categoryView, i18n("All")), *i2;
	categoryItems[i] = i18n("All");
	i->setOpen(true);
	TQString str;
	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;
	}
	str = "";
	i2 = i;
	while(item) {
		str += "/";
		str += item->item.c_str();
		i = new TDEListViewItem(i2, item->item.c_str());
		i->setOpen(false);
		categoryItems[i] = str;
		if(str == selected_category) {
			categoryView->ensureItemVisible(i);
			categoryView->setSelected(i, true);
		}

		while(item && item->it == item->items.end()) {
			int str_i = str.findRev("/");
			if(str_i < 0) {
				str = "";
			} else {
				str.truncate(str_i);
			}
			item = item->parent;
			i = i->parent();
			i2 = i;
		}
		if(item) {
			item2 = &*item->it;
			if(item->it == item->items.begin())
				i2 = i;
			++item->it;
			item = item2;
			item->it = item->items.begin();
		}
	}

	if(!variable_cats.objects.empty()) {
		//add "Uncategorized" category if there are variables without category
		i = new TDEListViewItem(categoryView, i18n("Uncategorized"));
		categoryItems[i] = i18n("Uncategorized");
		if(selected_category == i18n("Uncategorized")) {
			categoryView->ensureItemVisible(i);
			categoryView->setSelected(i, true);
		}
	}
	if(!ia_variables.empty()) {
		//add "Inactive" category if there are inactive variables
		i = new TDEListViewItem(categoryView, i18n("Inactive"));
		categoryItems[i] = i18n("Inactive");
		if(selected_category == i18n("Inactive")) {
			categoryView->ensureItemVisible(i);
			categoryView->setSelected(i, true);
		}
	}
	if(!categoryView->selectedItem()) {
		//if no category has been selected (previously selected has been renamed/deleted), select "All"
		selected_category = i18n("All");
		TQListViewItemIterator it(categoryView);
		if(it.current())
			categoryView->setSelected(it.current(), true);
	}
}

#define UPDATE_SELECTED_VARIABLE		TQListViewItem *i = variableView->selectedItem(); if(!i) return;	selected_variable = variableItems[i]; if(!selected_variable) return;
#define CHECK_IF_VARIABLE_STILL_THERE			if(!CALCULATOR->stillHasVariable(selected_variable)) {KMessageBox::error(this, i18n("Variable does not exist anymore.")); emit variablesChanged(); return;}

void QalculateVariablesDialog::exportVariable() {
	UPDATE_SELECTED_VARIABLE
	CHECK_IF_VARIABLE_STILL_THERE
	if(selected_variable->isKnown()) {
		if(!export_csv_dialog) {
			export_csv_dialog = new QalculateExportCSVDialog(this);
		}
		export_csv_dialog->exportCSVFile((KnownVariable*) selected_variable);
	}
}


void QalculateVariablesDialog::insertVariable() {
	UPDATE_SELECTED_VARIABLE
	CHECK_IF_VARIABLE_STILL_THERE
	emit insertRequest(selected_variable);
}


void QalculateVariablesDialog::deactivateVariable() {
	UPDATE_SELECTED_VARIABLE
	CHECK_IF_VARIABLE_STILL_THERE
	selected_variable->setActive(!selected_variable->isActive());
	emit variablesChanged();
}

void QalculateVariablesDialog::deleteVariable() {
	UPDATE_SELECTED_VARIABLE
	CHECK_IF_VARIABLE_STILL_THERE
	if(selected_variable->isLocal()) {
		//ensure that all references are removed in Calculator
		selected_variable->destroy();
		//update menus and trees
		emit variablesChanged();
	}
}


void QalculateVariablesDialog::editVariable() {
	UPDATE_SELECTED_VARIABLE
	CHECK_IF_VARIABLE_STILL_THERE
	Variable *v = NULL;
	if(selected_variable->isKnown()) {
		if(((KnownVariable*) selected_variable)->get().isVector()) {
			if(!matrix_edit_dialog) {
				matrix_edit_dialog = new QalculateEditMatrixVectorDialog(this);
			}
			v = matrix_edit_dialog->editVariable(TQString::null, (KnownVariable*) selected_variable);
		} else {
			if(!variable_edit_dialog) {
				variable_edit_dialog = new QalculateEditVariableDialog(this);
			}
			v = variable_edit_dialog->editVariable(TQString::null, (KnownVariable*) selected_variable);
		}
	} else {
		if(!unknown_edit_dialog) {
			unknown_edit_dialog = new QalculateEditUnknownVariableDialog(this);
		}
		v = unknown_edit_dialog->editVariable(TQString::null, (UnknownVariable*) selected_variable);
	}
	if(v) {
		selected_variable = v;
		if(!v->isActive()) {
			selected_category = i18n("Inactive");
		} else if(v->category().empty()) {
			selected_category = i18n("Uncategorized");
		} else {
			selected_category = "/";
			selected_category += v->category().c_str();
		}
		emit variablesChanged();
	}
}

void QalculateVariablesDialog::newVariable() {
	if(!variable_edit_dialog) {
		variable_edit_dialog = new QalculateEditVariableDialog(this);
	}
	Variable *v = NULL;
	if(selected_category.isEmpty() || selected_category[0] != '/') {
		v = variable_edit_dialog->editVariable("");
	} else {
		TQString str = selected_category;
		str.remove(0, 1);
		v = variable_edit_dialog->editVariable(str);
	}
	if(v) {
		selected_variable = v;
		if(!v->isActive()) {
			selected_category = i18n("Inactive");
		} else if(v->category().empty()) {
			selected_category = i18n("Uncategorized");
		} else {
			selected_category = "/";
			selected_category += v->category().c_str();
		}
		emit variablesChanged();
	}
}

void QalculateVariablesDialog::variableDoubleClicked(TQListViewItem*i) {
	selected_variable = variableItems[i];
	if(!selected_variable)
		return;
	CHECK_IF_VARIABLE_STILL_THERE
	Variable *v = NULL;
	if(selected_variable->isKnown()) {
		if(((KnownVariable*) selected_variable)->get().isVector()) {
			if(!matrix_edit_dialog) {
				matrix_edit_dialog = new QalculateEditMatrixVectorDialog(this);
			}
			v = matrix_edit_dialog->editVariable(TQString::null, (KnownVariable*) selected_variable);
		} else {
			if(!variable_edit_dialog) {
				variable_edit_dialog = new QalculateEditVariableDialog(this);
			}
			v = variable_edit_dialog->editVariable(TQString::null, (KnownVariable*) selected_variable);
		}
	} else {
		if(!unknown_edit_dialog) {
			unknown_edit_dialog = new QalculateEditUnknownVariableDialog(this);
		}
		v = unknown_edit_dialog->editVariable(TQString::null, (UnknownVariable*) selected_variable);
	}
	if(v) {
		selected_variable = v;
		if(!v->isActive()) {
			selected_category = i18n("Inactive");
		} else if(v->category().empty()) {
			selected_category = i18n("Uncategorized");
		} else {
			selected_category = "/";
			selected_category += v->category().c_str();
		}
		emit variablesChanged();
	}
}


void QalculateVariablesDialog::variableSelected() {
	TQListViewItem *selected = variableView->selectedItem();
	if(selected) {
		Variable *v = variableItems[selected];
		if(!CALCULATOR->stillHasVariable(v)) {
			KMessageBox::error(this, i18n("Variable does not exist anymore."));
			selected_variable = NULL;
			emit variablesChanged();
			return;
		}
		//remember selection
		selected_variable = v;
		editButton->setEnabled(!is_answer_variable(v));
		insertButton->setEnabled(v->isActive());
		deleteButton->setEnabled(v->isLocal() && !is_answer_variable(v) && v != CALCULATOR->v_x && v != CALCULATOR->v_y && v != CALCULATOR->v_z);
		deactivateButton->setEnabled(!is_answer_variable(v));
		if(v->isActive())
			deactivateButton->setText(i18n("Deactivate"));
		else
			deactivateButton->setText(i18n("Activate"));
		exportButton->setEnabled(v->isKnown());
	} else {
		editButton->setEnabled(false);
		insertButton->setEnabled(false);
		deleteButton->setEnabled(false);
		deactivateButton->setEnabled(false);
		exportButton->setEnabled(false);
		selected_variable = NULL;
	}
}

void QalculateVariablesDialog::addVariableTreeItem(Variable *v) {
	TQString value;
	if(is_answer_variable(v)) {
		value = i18n("a previous result");
	} else if(v->isKnown()) {
		if(((KnownVariable*) v)->isExpression()) {
			value = CALCULATOR->localizeExpression(((KnownVariable*) v)->expression()).c_str();
			if(value.length() > 20) {
				value.truncate(17);
				value += "...";
			}
		} else {
			if(((KnownVariable*) v)->get().isMatrix()) {
				value = i18n("matrix");
			} else if(((KnownVariable*) v)->get().isVector()) {
				value = i18n("vector");
			} else {
				value = CALCULATOR->printMathStructureTimeOut(((KnownVariable*) v)->get(), 30).c_str();
			}
		}
	} else {
		if(((UnknownVariable*) v)->assumptions()) {
			switch(((UnknownVariable*) v)->assumptions()->sign()) {
				case ASSUMPTION_SIGN_POSITIVE: {
						value = i18n("positive");
						break;
					}
				case ASSUMPTION_SIGN_NONPOSITIVE: {
						value = i18n("non-positive");
						break;
					}
				case ASSUMPTION_SIGN_NEGATIVE: {
						value = i18n("negative");
						break;
					}
				case ASSUMPTION_SIGN_NONNEGATIVE: {
						value = i18n("non-negative");
						break;
					}
				case ASSUMPTION_SIGN_NONZERO: {
						value = i18n("non-zero");
						break;
					}
				default: {}
			}
			if(!value.isEmpty() && !((UnknownVariable*) v)->assumptions()->type() == ASSUMPTION_TYPE_NONE)
				value += " ";
			switch(((UnknownVariable*) v)->assumptions()->type()) {
				case ASSUMPTION_TYPE_INTEGER: {
					value += i18n("integer");
					break;
				}
				case ASSUMPTION_TYPE_RATIONAL: {
					value += i18n("rational");
					break;
				}
				case ASSUMPTION_TYPE_REAL: {
					value += i18n("real");
					break;
				}
				case ASSUMPTION_TYPE_COMPLEX: {
					value += i18n("complex");
					break;
				}
				case ASSUMPTION_TYPE_NUMBER: {
					value += i18n("number");
					break;
				}
				case ASSUMPTION_TYPE_NONMATRIX: {
					value += i18n("(not matrix)");
					break;
				}
				default: {}
			}
			if(value.isEmpty())
				value = i18n("unknown");
		} else {
			value = i18n("default assumptions");
		}
	}
	TQListViewItem *i = new TDEListViewItem(variableView, v->title(true).c_str(), value);
	variableItems[i] = v;
	if(v == selected_variable) {
		variableView->setSelected(i, true);
	}
}


void QalculateVariablesDialog::categorySelected() {
	TQListViewItem *selected = categoryView->selectedItem();
	bool no_cat = false, b_all = false, b_inactive = false;
	variableView->clear();
	variableItems.clear();
	if(!selected) {
		selected_category = "";
		variableSelected();
		return;
	}
	selected_category = categoryItems[selected];
	if(selected_category == i18n("All")) {
		b_all = true;
	} else if(selected_category == i18n("Uncategorized")) {
		no_cat = true;
	} else if(selected_category == i18n("Inactive")) {
		b_inactive = true;
	}
	if(!b_all && !no_cat && !b_inactive && selected_category[0] == '/') {
		std::string str = selected_category.ascii();
		str.erase(str.begin());
		for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
			if(CALCULATOR->variables[i]->isActive() && CALCULATOR->variables[i]->category().substr(0, selected_category.length() - 1) == str) {
				addVariableTreeItem(CALCULATOR->variables[i]);
			}
		}
	} else {
		std::string str = selected_category.ascii();
		for(size_t i = 0; i < CALCULATOR->variables.size(); i++) {
			if((b_inactive && !CALCULATOR->variables[i]->isActive()) || (CALCULATOR->variables[i]->isActive() && (b_all || (no_cat && CALCULATOR->variables[i]->category().empty()) || (!b_inactive && CALCULATOR->variables[i]->category() == str)))) {
				addVariableTreeItem(CALCULATOR->variables[i]);
			}
		}
	}
	if(!selected_variable || !variableView->selectedItem()) {
		TQListViewItemIterator it(variableView);
		if(it.current())
			variableView->setSelected(it.current(), true);
	}
}


#include "qalculatevariablesdialog.moc"
