/***************************************************************************
 *   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 "qalculateinsertfunctiondialog.h"
#include "qalculate_tde_utils.h"
#include <tqvbox.h>
#include <kactivelabel.h>
#include <klineedit.h>
#include <tqlabel.h>
#include <tqgrid.h>
#include <tqhbox.h>
#include <tdelocale.h>
#include <tqspinbox.h>
#include <kcombobox.h>
#include <tqhbuttongroup.h>
#include <tqradiobutton.h>
#include <tqstring.h>
#include <tqpushbutton.h>
#include <kdatepicker.h>
#include <tdefiledialog.h>
#include <tdeversion.h>
#include <kstdguiitem.h>
#include "buttonwithindexsignal.h"
#include "qalculateinsertmatrixvectordialog.h"

extern TQWidget *expressionWidget;
extern PrintOptions printops;
extern EvaluationOptions evalops;

QalculateInsertFunctionDialog::QalculateInsertFunctionDialog(MathFunction *f, TQWidget *parent, const TQString &selected_text, const char *name) : KDialogBase(parent, name, true, f->title(true).c_str(), Ok|Apply|Cancel, Ok) {

#if TDE_VERSION_MAJOR < 4 && TDE_VERSION_MINOR < 2
	setButtonOKText(i18n("Insert"));
	setButtonApplyText(i18n("Execute"));
#else
#if TDE_VERSION_MAJOR < 4 && TDE_VERSION_MINOR < 3
	setButtonOK(KGuiItem(i18n("Insert")));
#else
	setButtonOK(KStdGuiItem::insert());	
#endif
	setButtonApply(KGuiItem(i18n("Execute")));
#endif	
	mathFunction = f;
	TQVBox *box = makeVBoxMainWidget();
	box->setSpacing(12);
	TQString titlestr = "<font size=\"5\">";
	titlestr += mathFunction->title(true).c_str();
	titlestr += "</font>";
	new TQLabel(titlestr, box);
	int args = 0;
	bool has_vector = false;
	if(mathFunction->args() > 0) {
		args = mathFunction->args();
	} else if(mathFunction->minargs() > 0) {
		args = mathFunction->minargs() + 1;
		has_vector = true;
	} else {
		args = 1;
		has_vector = true;
	}
	TQGrid *table = new TQGrid(3, box);
	table->setSpacing(6);
	table->setMargin(12);
	table->setFrameStyle(TQFrame::Sunken | TQFrame::GroupBoxPanel);
	label.resize(args);
	entry.resize(args);
	type_label.resize(args);
	TQString argstr, typestr, defstr, argtype;
	//create argument entries
	Argument *arg;
	for(int i = 0; i < args; i++) {
		arg = mathFunction->getArgumentDefinition(i + 1);
		if(!arg || arg->name().empty()) {
			if(args == 1) {
				argstr = i18n("Value:");
			} else {
				argstr = i18n("Argument");
				argstr += " ";
				argstr += TQString::number(i + 1);
				argstr += ":";
			}
		} else {
			argstr = arg->name().c_str();
			argstr += ":";
		}
		typestr = "";
		argtype = "";
		defstr = mathFunction->getDefaultValue(i + 1).c_str();
		if(arg && (arg->suggestsQuotes() || arg->type() == ARGUMENT_TYPE_TEXT) && defstr.length() >= 2 && defstr[0] == '\"' && defstr[defstr.length() - 1] == '\"') {
			defstr.remove(0, 1);
			defstr.truncate(defstr.length() - 1);
		}
		label[i] = new TQLabel(argstr, table);
		if(arg) {
			switch(arg->type()) {
				case ARGUMENT_TYPE_INTEGER: {
					IntegerArgument *iarg = (IntegerArgument*) arg;
					int min = -1000000, max = 1000000;
					if(iarg->min()) {
						min = iarg->min()->intValue();
					}
					if(iarg->max()) {
						max = iarg->max()->intValue();
					}
					TQSpinBox *qsp = new TQSpinBox(min, max, 1, table);
					entry[i] = qsp;
					qsp->setButtonSymbols(TQSpinBox::PlusMinus);
					int selected_value = 0;
					bool convok = false;
					if(i == 0 && !selected_text.isEmpty()) {
						selected_value = selected_text.toInt(&convok);
					}
					if(convok && selected_value >= min && selected_value <= max) {
						qsp->setValue(selected_value);
					} else if(!mathFunction->getDefaultValue(i + 1).empty()) {
						qsp->setValue(TQString(mathFunction->getDefaultValue(i + 1).c_str()).toInt());
					} else if(!arg->zeroForbidden() && min <= 0 && max >= 0) {
						qsp->setValue(0);
					} else {
						if(max < 0) {
							qsp->setValue(max);
						} else if(min <= 1) {
							qsp->setValue(1);
						} else {
							qsp->setValue(min);
						}
					}
					break;
				}
				case ARGUMENT_TYPE_BOOLEAN: {
					TQHButtonGroup *bg = new TQHButtonGroup(table);
					entry[i] = bg;
					bg->setFrameStyle(TQFrame::Plain | TQFrame::NoFrame);
					bg->setMargin(0);
					bg->setRadioButtonExclusive(TRUE);
					bg->insert(new TQRadioButton(i18n("True"), bg), 1);
					bg->insert(new TQRadioButton(i18n("False"), bg), 0);
					TQString str = selected_text.stripWhiteSpace();
					if(i == 0 && str == "1") {
						bg->setButton(1);
					} else if(i == 0 && str == "0") {
						bg->setButton(0);
					} else if(defstr == "1") {
						bg->setButton(1);
					} else {
						bg->setButton(0);
					}
					break;
				}
				case ARGUMENT_TYPE_DATA_PROPERTY: {
					if(mathFunction->subtype() == SUBTYPE_DATA_SET) {
						KComboBox *cb = new KComboBox(table);
						entry[i] = cb;
						DataPropertyIter it;
						DataSet *ds = (DataSet*) mathFunction;
						DataProperty *dp = ds->getFirstProperty(&it);
						bool active_set = false;
						while(dp) {
							if(!dp->isHidden()) {
								cb->insertItem(dp->title().c_str());
								if(!active_set && defstr == dp->getName().c_str()) {
									cb->setCurrentItem(cb->count() - 1);
									active_set = true;
								}
							}
							dp = ds->getNextProperty(&it);
						}
						cb->insertItem(i18n("Info"));
						if(!active_set) {
							cb->setCurrentItem(cb->count() - 1);
						}						
						break;
					}
				}
				default: {
					if(i >= mathFunction->minargs() && !has_vector) {
						typestr = "(";
						typestr += i18n("optional");
					}
					argtype = arg->print().c_str();
					if(typestr.isEmpty()) {
						typestr = "(";
					} else if(!argtype.isEmpty()) {
						typestr += " ";
					}
					if(!argtype.isEmpty()) {
						typestr += argtype;
					}
					typestr += ")";		
					if(typestr.length() == 2) {
						typestr = "";
					}
					entry[i] = new KLineEdit(table);
					if(i == 0 && !selected_text.isEmpty()) {
						((KLineEdit*) entry[i])->setText(selected_text);
					} else {
						((KLineEdit*) entry[i])->setText(defstr);
					}
				}
			}
		} else {
			entry[i] = new KLineEdit(table);
			if(i == 0 && !selected_text.isEmpty()) {
				((KLineEdit*) entry[i])->setText(selected_text);
			} else {
				((KLineEdit*) entry[i])->setText(defstr);
			}
		}
		if(typestr.isEmpty() && i >= mathFunction->minargs() && !has_vector) {
			typestr = "(";
			typestr += i18n("optional");
			typestr += ")";			
		}
		if(arg) {
			switch(arg->type()) {		
				case ARGUMENT_TYPE_DATE: {
					typestr.remove(0, 1);
					typestr.remove(typestr.length() - 1, 1);
					type_label[i] = new ButtonWithIndexSignal(typestr, i, table);
					TQObject::connect(type_label[i], TQ_SIGNAL(clickedWithIndex(int)), this, TQ_SLOT(selectDate(int)));
					break;
				}
				case ARGUMENT_TYPE_MATRIX: {
					typestr.remove(0, 1);
					typestr.remove(typestr.length() - 1, 1);
					type_label[i] = new ButtonWithIndexSignal(typestr, i, table);
					TQObject::connect(type_label[i], TQ_SIGNAL(clickedWithIndex(int)), this, TQ_SLOT(insertMatrix(int)));
					break;
				}
				case ARGUMENT_TYPE_VECTOR: {
					typestr.remove(0, 1);
					typestr.remove(typestr.length() - 1, 1);
					type_label[i] = new ButtonWithIndexSignal(typestr, i, table);
					TQObject::connect(type_label[i], TQ_SIGNAL(clickedWithIndex(int)), this, TQ_SLOT(insertVector(int)));
					break;
				}
				case ARGUMENT_TYPE_FILE: {
					typestr.remove(0, 1);
					typestr.remove(typestr.length() - 1, 1);
					type_label[i] = new ButtonWithIndexSignal(typestr, i, table);
					TQObject::connect(type_label[i], TQ_SIGNAL(clickedWithIndex(int)), this, TQ_SLOT(selectFile(int)));
					break;
				}
				default: {
					type_label[i] = new TQLabel(typestr, table);
				}
			}
		} else {
			type_label[i] = new TQLabel(typestr, table);
		}
		if(i == 0) entry[0]->setFocus();
	}
	//display function description
	if(!mathFunction->description().empty()) {
		TQString str = mathFunction->description().c_str();
		str.replace("<", "&lt;");
		str.replace(">", "&gt;");
		str.replace("\n", "<br>");
		KActiveLabel *descrLabel = new KActiveLabel(str, box);
		descrLabel->setAlignment(TQt::AlignJustify);
		enableButtonSeparator(true);
	}
}

QalculateInsertFunctionDialog::~QalculateInsertFunctionDialog() {
}

TQString QalculateInsertFunctionDialog::functionExpression() {
	TQString str = mathFunction->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressionWidget).name.c_str(), str2;
	str += "(";
	int args = 0;
	if(mathFunction->args() > 0) {
		args = mathFunction->args();
	} else if(mathFunction->minargs() > 0) {
		args = mathFunction->minargs() + 1;
	} else {
		args = 1;
	}
	for(int i = 0; i < args; i++) {
		if(mathFunction->getArgumentDefinition(i + 1) && mathFunction->getArgumentDefinition(i + 1)->type() == ARGUMENT_TYPE_BOOLEAN) {
			if(((TQButtonGroup*) entry[i])->id(((TQButtonGroup*) entry[i])->selected()) == 1) {
				str2 = "1";
			} else {
				str2 = "0";
			}
		} else if(mathFunction->getArgumentDefinition(i + 1) && mathFunction->getArgumentDefinition(i + 1)->type() == ARGUMENT_TYPE_INTEGER) {
			str2 = ((TQSpinBox*) entry[i])->text();
		} else if(mathFunction->subtype() == SUBTYPE_DATA_SET && mathFunction->getArgumentDefinition(i + 1) && mathFunction->getArgumentDefinition(i + 1)->type() == ARGUMENT_TYPE_DATA_PROPERTY) {
			int index = ((KComboBox*) entry[i])->currentItem();
			DataPropertyIter it;
			DataSet *ds = (DataSet*) mathFunction;
			DataProperty *dp = ds->getFirstProperty(&it);
			while(dp) {
				if(!dp->isHidden()) {
					if(index <= 0) break;
					index--;
				}
				dp = ds->getNextProperty(&it);
			}
			if(dp) {
				str2 = dp->getName().c_str();
			} else {
				str2 = "info";
			}
		} else {
			str2 = ((KLineEdit*) entry[i])->text();
		}
		//if the minimum number of function arguments have been filled, do not add anymore if entry is empty
		if(i >= mathFunction->minargs()) {
			str2 = str2.stripWhiteSpace();
		}
		if((i < mathFunction->minargs() || !str2.isEmpty()) && mathFunction->getArgumentDefinition(i + 1) && (mathFunction->getArgumentDefinition(i + 1)->suggestsQuotes() || (mathFunction->getArgumentDefinition(i + 1)->type() == ARGUMENT_TYPE_TEXT && str2.find(CALCULATOR->getComma().c_str()) >= 0))) {
			if(str2.length() < 1 || (str2[0] != '\"' && str[0] != '\'')) {
				str2.insert(0, "\"");
				str2 += "\"";
			}
		}
		if(i > 0) {
			str += CALCULATOR->getComma().c_str();
			str += " ";
		}
		str += str2;
	}
	str += ")";
	return str;
}

void QalculateInsertFunctionDialog::slotOk() {
	accept();
}

void QalculateInsertFunctionDialog::slotApply() {
	done(100);
}

void QalculateInsertFunctionDialog::selectDate(int index) {
	KDialogBase *dialog = new KDialogBase(this, 0, true, i18n("Date"), Ok|Cancel);
	KDatePicker *datePicker;
	TQDate date(TQDate::fromString(((KLineEdit*) entry[index])->text(), TQt::ISODate));
	if(date.isValid()) datePicker = new KDatePicker(dialog->makeVBoxMainWidget(), date);
	else datePicker = new KDatePicker(dialog->makeVBoxMainWidget());
	if(dialog->exec() == TQDialog::Accepted) {
		((KLineEdit*) entry[index])->setText(datePicker->date().toString(TQt::ISODate));
	}
	dialog->deleteLater();
}
void QalculateInsertFunctionDialog::selectFile(int index) {
	TQString filename = KFileDialog::getSaveFileName(((KLineEdit*) entry[index])->text(), TQString::null, this, i18n("File"));
	if(!filename.isEmpty()) {
		((KLineEdit*) entry[index])->setText(filename);
	}
}
void QalculateInsertFunctionDialog::insertMatrix(int index) {
	QalculateInsertMatrixVectorDialog *d = new QalculateInsertMatrixVectorDialog(this);
	TQString str = ((KLineEdit*) entry[index])->text();
	MathStructure mstruct;
	if(!str.isEmpty()) {
		CALCULATOR->parse(&mstruct, CALCULATOR->unlocalizeExpression(str.ascii(), evalops.parse_options));
	}
	if(mstruct.isVector()) {
		str = d->editMatrixVector(&mstruct, false);
	} else {
		str = d->editMatrixVector(NULL, false);
	}
	if(!str.isEmpty()) {
		((KLineEdit*) entry[index])->setText(str);
	}
	d->deleteLater();
}
void QalculateInsertFunctionDialog::insertVector(int index) {
	QalculateInsertMatrixVectorDialog *d = new QalculateInsertMatrixVectorDialog(this);
	TQString str = ((KLineEdit*) entry[index])->text();
	MathStructure mstruct;
	if(!str.isEmpty()) {
		CALCULATOR->parse(&mstruct, CALCULATOR->unlocalizeExpression(str.ascii(), evalops.parse_options));
	}
	if(mstruct.isVector()) {
		str = d->editMatrixVector(&mstruct, true);
	} else {
		str = d->editMatrixVector(NULL, true);
	}
	if(!str.isEmpty()) {
		((KLineEdit*) entry[index])->setText(str);
	}
	d->deleteLater();
}

#include "qalculateinsertfunctiondialog.moc"