/***************************************************************************
 *   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 "qalculatefunctionsdialog.h"
#include "qalculate_tde_utils.h"
#include "qalculateeditfunctiondialog.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 <ktextbrowser.h>
#include <tdeapplication.h>
#include <kstdguiitem.h>

extern tree_struct function_cats;
extern std::vector<void*> ia_functions;
extern PrintOptions printops;

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

	function_edit_dialog = NULL;
	selected_category = "";
	selected_function = NULL;

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

	TQVBoxLayout *leftLayout = new TQVBoxLayout(layout, spacingHint());

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

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

	functionView = new TDEListView(splitter);
	functionView->addColumn(i18n("Function Name"));
	functionView->setRootIsDecorated(false);

	descriptionBrowser = new KTextBrowser(this);
	leftLayout->addWidget(descriptionBrowser);

	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);
	applyButton = new TQPushButton(i18n("Apply"), this);
	applyButton->setEnabled(false);
	buttonLayout->addWidget(applyButton);
	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, 475).expandedTo(size()));

	connect(buttonClose, TQ_SIGNAL(clicked()), this, TQ_SLOT(close()));
	connect(newButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(newFunction()));
	connect(editButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(editFunction()));
	connect(deleteButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(deleteFunction()));
	connect(deactivateButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(deactivateFunction()));
	connect(insertButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(insertFunction()));
	connect(applyButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(applyFunction()));
	connect(functionView, TQ_SIGNAL(selectionChanged()), this, TQ_SLOT(functionSelected()));
	connect(functionView, TQ_SIGNAL(doubleClicked(TQListViewItem*)), this, TQ_SLOT(functionDoubleClicked(TQListViewItem*)));
	connect(categoryView, TQ_SIGNAL(selectionChanged()), this, TQ_SLOT(categorySelected()));
	connect(helpButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotHelp()));

}

QalculateFunctionsDialog::~QalculateFunctionsDialog() {
}

void QalculateFunctionsDialog::slotHelp() {
	tdeApp->invokeHelp("qalculate-managers");
}

void QalculateFunctionsDialog::updateFunctionTree() {
	functionItems.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;
	function_cats.it = function_cats.items.begin();
	if(function_cats.it != function_cats.items.end()) {
		item = &*function_cats.it;
		++function_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(!function_cats.objects.empty()) {
		//add "Uncategorized" category if there are functions 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_functions.empty()) {
		//add "Inactive" category if there are inactive functions
		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_FUNCTION		TQListViewItem *i = functionView->selectedItem(); if(!i) return;	selected_function = functionItems[i]; if(!selected_function) return;
#define CHECK_IF_FUNCTION_STILL_THERE			if(!CALCULATOR->stillHasFunction(selected_function)) {KMessageBox::error(this, i18n("Function does not exist anymore.")); emit functionsChanged(); return;}

void QalculateFunctionsDialog::insertFunction() {
	UPDATE_SELECTED_FUNCTION
	CHECK_IF_FUNCTION_STILL_THERE
	emit insertRequest(selected_function);
}

void QalculateFunctionsDialog::applyFunction() {
	UPDATE_SELECTED_FUNCTION
	CHECK_IF_FUNCTION_STILL_THERE
	emit applyRequest(selected_function);
}

void QalculateFunctionsDialog::deactivateFunction() {
	UPDATE_SELECTED_FUNCTION
	CHECK_IF_FUNCTION_STILL_THERE
	selected_function->setActive(!selected_function->isActive());
	emit functionsChanged();
}

void QalculateFunctionsDialog::deleteFunction() {
	UPDATE_SELECTED_FUNCTION
	CHECK_IF_FUNCTION_STILL_THERE
	if(selected_function->isLocal()) {
		//ensure that all references are removed in Calculator
		selected_function->destroy();
		//update menus and trees
		emit functionsChanged();
	}
}


void QalculateFunctionsDialog::editFunction() {
	UPDATE_SELECTED_FUNCTION
	CHECK_IF_FUNCTION_STILL_THERE
	if(!function_edit_dialog) {
		function_edit_dialog = new QalculateEditFunctionDialog(this);
	}
	MathFunction *f = function_edit_dialog->editFunction(TQString::null, selected_function);
	if(f) {
		selected_function = f;
		if(!f->isActive()) {
			selected_category = i18n("Inactive");
		} else if(f->category().empty()) {
			selected_category = i18n("Uncategorized");
		} else {
			selected_category = "/";
			selected_category += f->category().c_str();
		}
		emit functionsChanged();
	}
}

void QalculateFunctionsDialog::newFunction() {
	if(!function_edit_dialog) {
		function_edit_dialog = new QalculateEditFunctionDialog(this);
	}
	MathFunction *f = NULL;
	if(selected_category.isEmpty() || selected_category[0] != '/') {
		f = function_edit_dialog->editFunction();
	} else {
		TQString str = selected_category;
		str.remove(0, 1);
		f = function_edit_dialog->editFunction(str);
	}
	if(f) {
		selected_function = f;
		if(!f->isActive()) {
			selected_category = i18n("Inactive");
		} else if(f->category().empty()) {
			selected_category = i18n("Uncategorized");
		} else {
			selected_category = "/";
			selected_category += f->category().c_str();
		}
		emit functionsChanged();
	}
}

void QalculateFunctionsDialog::functionDoubleClicked(TQListViewItem*i) {
	selected_function = functionItems[i];
	if(!selected_function)
		return;
	CHECK_IF_FUNCTION_STILL_THERE
	if(!function_edit_dialog) {
		function_edit_dialog = new QalculateEditFunctionDialog(this);
	}
	MathFunction *f = function_edit_dialog->editFunction(TQString::null, selected_function);
	if(f) {
		selected_function = f;
		if(!f->isActive()) {
			selected_category = i18n("Inactive");
		} else if(f->category().empty()) {
			selected_category = i18n("Uncategorized");
		} else {
			selected_category = "/";
			selected_category += f->category().c_str();
		}
		emit functionsChanged();
	}
}


void QalculateFunctionsDialog::functionSelected() {
	TQListViewItem *selected = functionView->selectedItem();
	if(selected) {
		MathFunction *f = functionItems[selected];
		if(!CALCULATOR->stillHasFunction(f)) {
			KMessageBox::error(this, i18n("Function does not exist anymore."));
			selected_function = NULL;
			emit functionsChanged();
			return;
		}
		//remember selection
		selected_function = f;
		editButton->setEnabled(true);
		insertButton->setEnabled(f->isActive());
		applyButton->setEnabled(f->isActive() && f->minargs() <= 1);
		deleteButton->setEnabled(f->isLocal());
		deactivateButton->setEnabled(true);
		if(f->isActive()) {
			deactivateButton->setText(i18n("Deactivate"));
		} else {
			deactivateButton->setText(i18n("Activate"));
		}

		Argument *arg;
		Argument default_arg;
		TQString str, str2;
		const ExpressionName *ename = &f->preferredName(false, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) descriptionBrowser);
		str += "<i><b>";
		str += ename->name.c_str();
		str += "</b>";
		int iargs = f->maxargs();
		if(iargs < 0) {
			iargs = f->minargs() + 1;
		}
		str += "(";
		if(iargs != 0) {
			for(int i2 = 1; i2 <= iargs; i2++) {
				if(i2 > f->minargs()) {
					str += "[";
				}
				if(i2 > 1) {
					str += CALCULATOR->getComma().c_str();
					str += " ";
				}
				arg = f->getArgumentDefinition(i2);
				if(arg && !arg->name().empty()) {
					str += arg->name().c_str();
				} else {
					str += i18n("argument");
					str += " ";
					str += TQString::number(i2);
				}
				if(i2 > f->minargs()) {
					str += "]";
				}
			}
			if(f->maxargs() < 0) {
				str += CALCULATOR->getComma().c_str();
				str += " ...";
			}
		}
		str += ")";
		for(size_t i2 = 1; i2 <= f->countNames(); i2++) {
			if(&f->getName(i2) != ename) {
				str += "<br>";
				str += f->getName(i2).name.c_str();
			}
		}
		str += "</i>";
		str += "<br>";
		if(f->subtype() == SUBTYPE_DATA_SET) {
			str += "<br>";
			str2.sprintf(i18n("Retrieves data from the %s data set for a given object and property. If \"info\" is typed as property, a dialog window will pop up with all properties of the object.").utf8(), f->title().c_str());
			str2.replace("<", "&lt;");
			str2.replace(">", "&gt;");
			str += str2;
			str += "<br>";
		}
		if(!f->description().empty()) {
			str += "<br>";
			str2 = f->description().c_str();
			str2.replace("<", "&lt;");
			str2.replace(">", "&gt;");
			str += str2;
			str += "<br>";
		}
		if(f->subtype() == SUBTYPE_DATA_SET && !((DataSet*) f)->copyright().empty()) {
			str += "<br>";
			str2 = ((DataSet*) f)->copyright().c_str();
			str2.replace("<", "&lt;");
			str2.replace(">", "&gt;");
			str += str2;
			str += "<br>";
		}
		if(iargs) {
			str += "<br><b>";
			str += i18n("Arguments");
			str += "</b><br>";
			for(int i2 = 1; i2 <= iargs; i2++) {
				arg = f->getArgumentDefinition(i2);
				if(arg && !arg->name().empty()) {
					str += arg->name().c_str();
				} else {
					str += TQString::number(i2);
				}
				str += ": <i>";
				if(arg) {
					str2= arg->printlong().c_str();
				} else {
					str2= default_arg.printlong().c_str();
				}
				str2.replace("<", "&lt;");
				str2.replace(">", "&gt;");
				str += str2;
				if(i2 > f->minargs()) {
					str += " (";
					//optional argument
					str += i18n("optional");
					if(!f->getDefaultValue(i2).empty()) {
						str += ", ";
						//argument default, in description
						str += i18n("default: ");
						str += f->getDefaultValue(i2).c_str();
					}
					str += ")";
				}
				str += "</i><br>";
			}
		}
		if(!f->condition().empty()) {
			str += "<br>";
			str += i18n("Requirement");
			str += ": ";
			str2 = f->printCondition().c_str();
			str2.replace("<", "&lt;");
			str2.replace(">", "&gt;");
			str += str2;
			str += "<br>";
		}
		if(f->subtype() == SUBTYPE_DATA_SET) {
			DataSet *ds = (DataSet*) f;
			str += "<br><b>";
			str += i18n("Properties");
			str += "</b><br>";
			DataPropertyIter it;
			DataProperty *dp = ds->getFirstProperty(&it);
			while(dp) {
				if(!dp->isHidden()) {
					if(!dp->title(false).empty()) {
						str2 = dp->title().c_str();
						str2.replace("<", "&lt;");
						str2.replace(">", "&gt;");
						str += str2;
						str += ": ";
					}
					for(size_t i = 1; i <= dp->countNames(); i++) {
						if(i > 1) str += ", ";
						str += dp->getName(i).c_str();
					}
					if(dp->isKey()) {
						str += " (";
						str += i18n("key");
						str += ")";
					}
					str += "<br>";
					if(!dp->description().empty()) {
						str += "<i>";
						str2 = dp->description().c_str();
						str2.replace("<", "&lt;");
						str2.replace(">", "&gt;");
						str += str2;
						str += "</i><br>";
					}
				}
				dp = ds->getNextProperty(&it);
			}
		}
		str.replace("\n", "<br>");
		descriptionBrowser->setText(str);
	} else {
		editButton->setEnabled(false);
		insertButton->setEnabled(false);
		applyButton->setEnabled(false);
		deleteButton->setEnabled(false);
		deactivateButton->setEnabled(false);
		selected_function = NULL;
		descriptionBrowser->clear();
	}
}

void QalculateFunctionsDialog::addFunctionTreeItem(MathFunction *f) {
	TQListViewItem *i = new TDEListViewItem(functionView, f->title(true).c_str());
	functionItems[i] = f;
	if(f == selected_function) {
		functionView->setSelected(i, true);
	}
}


void QalculateFunctionsDialog::categorySelected() {
	TQListViewItem *selected = categoryView->selectedItem();
	bool no_cat = false, b_all = false, b_inactive = false;
	functionView->clear();
	functionItems.clear();
	if(!selected) {
		selected_category = "";
		functionSelected();
		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->functions.size(); i++) {
			if(CALCULATOR->functions[i]->isActive() && CALCULATOR->functions[i]->category().substr(0, selected_category.length() - 1) == str) {
				addFunctionTreeItem(CALCULATOR->functions[i]);
			}
		}
	} else {
		std::string str = selected_category.ascii();
		for(size_t i = 0; i < CALCULATOR->functions.size(); i++) {
			if((b_inactive && !CALCULATOR->functions[i]->isActive()) || (CALCULATOR->functions[i]->isActive() && (b_all || (no_cat && CALCULATOR->functions[i]->category().empty()) || (!b_inactive && CALCULATOR->functions[i]->category() == str)))) {
				addFunctionTreeItem(CALCULATOR->functions[i]);
			}
		}
	}
	if(!selected_function || !functionView->selectedItem()) {
		TQListViewItemIterator it(functionView);
		if(it.current())
			functionView->setSelected(it.current(), true);
	}

}


#include "qalculatefunctionsdialog.moc"
