/*
 * mainwindow.cpp - part of abakus
 * Copyright (C) 2004, 2005 Michael Pyne <michael.pyne@kdemail.net>
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include "mainwindow.h"
#include "abakuscommon.h"

#include <tdeaccel.h>
#include <tdemenubar.h>
#include <tdeaction.h>
#include <kstdaction.h>
#include <tdeshortcut.h>
#include <kdebug.h>
#include <tdeconfig.h>
#include <tdeglobal.h>
#include <tdeconfigbase.h>
#include <tdeactionclasses.h>
#include <kinputdialog.h>

#include <tqlayout.h>
#include <tqvbox.h>
#include <tqhbox.h>
#include <tqradiobutton.h>
#include <tqbuttongroup.h>
#include <tqsplitter.h>

#include "editor.h"
#include "evaluator.h"
#include "function.h"
#include "resultlistview.h"
#include "resultlistviewtext.h"
#include "valuemanager.h"
#include "node.h"
#include "rpnmuncher.h"
#include "dcopIface.h"
#include "abakuslistview.h"
#include "result.h"

MainWindow::MainWindow() : TDEMainWindow(0, "abakus-mainwindow"), m_popup(0), m_insert(false)
{
    m_mainSplitter = new TQSplitter(this);
    TQWidget *box = new TQWidget(m_mainSplitter);
    TQVBoxLayout *layout = new TQVBoxLayout(box);
    m_layout = layout;
    layout->setSpacing(6);
    layout->setMargin(6);

    TQWidget *configBox = new TQWidget(box);
    layout->addWidget(configBox);

    TQHBoxLayout *configLayout = new TQHBoxLayout(configBox);

    configLayout->addWidget(new TQWidget(configBox));

    TQLabel *label = new TQLabel(i18n("History: "), configBox);
    label->setAlignment(AlignCenter);
    configLayout->addWidget(label);

    TQButtonGroup *buttonGroup = new TQButtonGroup(0);

    TQWidget *buttonGroupBox = new TQWidget(configBox);
    TQHBoxLayout *buttonGroupLayout = new TQHBoxLayout(buttonGroupBox);
    buttonGroupLayout->addStretch(0);

    configLayout->addWidget(buttonGroupBox);

    m_degrees = new TQRadioButton(i18n("&Degrees"), buttonGroupBox);
    buttonGroup->insert(m_degrees);
    buttonGroupLayout->addWidget(m_degrees);
    slotDegrees();
    connect(m_degrees, TQT_SIGNAL(clicked()), TQT_SLOT(slotDegrees()));

    m_radians = new TQRadioButton(i18n("&Radians"), buttonGroupBox);
    buttonGroup->insert(m_radians);
    buttonGroupLayout->addWidget(m_radians);
    connect(m_radians, TQT_SIGNAL(clicked()), TQT_SLOT(slotRadians()));

    m_history = new TQVBox(box);
    layout->addWidget(m_history);
    m_history->setSpacing(6);
    m_history->setMargin(0);

    m_result = new ResultListView(m_history);
    m_result->setSelectionMode(TQListView::NoSelection);
    m_result->setHScrollBarMode(ResultListView::AlwaysOff);
    connect(m_result, TQT_SIGNAL(signalEntrySelected(const TQString &)),
                      TQT_SLOT(slotEntrySelected(const TQString &)));
    connect(m_result, TQT_SIGNAL(signalResultSelected(const TQString &)),
                      TQT_SLOT(slotResultSelected(const TQString &)));

    m_history->setStretchFactor(m_result, 1);
    layout->setStretchFactor(m_history, 1);

    TQHBox *editBox = new TQHBox(box);
    layout->addWidget(editBox);
    editBox->setSpacing(6);

    m_edit = new Editor(editBox);
    m_edit->setFocus();
    editBox->setStretchFactor(m_edit, 1);

    KPushButton *evalButton = new KPushButton(i18n("&Evaluate"), editBox);

    connect(evalButton, TQT_SIGNAL(clicked()), TQT_SLOT(slotEvaluate()));

    connect(m_edit, TQT_SIGNAL(returnPressed()), TQT_SLOT(slotReturnPressed()));
    connect(m_edit, TQT_SIGNAL(textChanged()), TQT_SLOT(slotTextChanged()));

    m_listSplitter = new TQSplitter(Qt::Vertical, m_mainSplitter);
    m_fnList = new FunctionListView(m_listSplitter);
    m_fnList->addColumn("Functions");
    m_fnList->addColumn("Value");

    m_varList = new VariableListView(m_listSplitter);
    m_varList->addColumn("Variables");
    m_varList->addColumn("Value");

    connect(FunctionManager::instance(), TQT_SIGNAL(signalFunctionAdded(const TQString &)),
            this, TQT_SLOT(slotNewFunction(const TQString &)));
    connect(FunctionManager::instance(), TQT_SIGNAL(signalFunctionRemoved(const TQString &)),
            this, TQT_SLOT(slotRemoveFunction(const TQString &)));

    connect(ValueManager::instance(), TQT_SIGNAL(signalValueAdded(const TQString &, Abakus::number_t)),
            this, TQT_SLOT(slotNewValue(const TQString &, Abakus::number_t)));
    connect(ValueManager::instance(), TQT_SIGNAL(signalValueChanged(const TQString &, Abakus::number_t)),
            this, TQT_SLOT(slotChangeValue(const TQString &, Abakus::number_t)));
    connect(ValueManager::instance(), TQT_SIGNAL(signalValueRemoved(const TQString &)),
            this, TQT_SLOT(slotRemoveValue(const TQString &)));

    setupLayout();

    setCentralWidget(m_mainSplitter);

#if KDE_IS_VERSION(3,4,89)
    setupGUI(TQSize(450, 400), Keys | StatusBar | Save | Create);
#else
    setupGUI(Keys | StatusBar | Save | Create);
#endif

    m_dcopInterface = new AbakusIface();
}

bool MainWindow::inRPNMode() const
{
    return action<TDEToggleAction>("toggleExpressionMode")->isChecked();
}

bool MainWindow::eventFilter(TQObject *o, TQEvent *e)
{
    return TDEMainWindow::eventFilter(o, e);
}

bool MainWindow::queryExit()
{
    saveConfig();
    return TDEMainWindow::queryExit();
}

void MainWindow::contextMenuEvent(TQContextMenuEvent *e)
{
    static TDEPopupMenu *popup = 0;

    if(!popup) {
        popup = new TDEPopupMenu(this);
        action("options_show_menubar")->plug(popup);
    }

    if(!action<TDEToggleAction>("options_show_menubar")->isChecked())
        popup->popup(e->globalPos());
}

void MainWindow::polish()
{
    TDEMainWindow::polish();
    loadConfig();
}

void MainWindow::slotReturnPressed()
{
    TQString text = m_edit->text();

    text.replace("\n", "");

    m_edit->appendHistory(text);

    // Item to insert after
    ResultListViewText *after = m_result->lastItem();

    // Expand $foo references.
    TQString str = interpolateExpression(text, after);

    TQString resultVal;
    ResultListViewText *item;

    if(str.isNull())
        return; // Error already has been posted

    m_insert = false; // Assume we failed

    if(inRPNMode()) {
        // We're in RPN mode.
        Abakus::number_t result = RPNParser::rpnParseString(str);

        if(!RPNParser::wasError()) {
            resultVal = result.toString();
            ValueManager::instance()->setValue("ans", result);
            m_insert = true;
        }
        else {
            m_insert = false;
            resultVal = i18n("Error: %1").arg(RPNParser::errorString());
        }

        // Skip creating list view items if in compact mode.
        if(!m_history->isShown()) {
            m_edit->setText(resultVal);
            TQTimer::singleShot(0, m_edit, TQT_SLOT(selectAll()));

            return;
        }

        item = new ResultListViewText(m_result, str, resultVal, after, false);
    }
    else {

        // Check to see if it's just a function name, if so, add (ans).
        if(FunctionManager::instance()->isFunction(str))
            str += " ans";

        // Add right parentheses as needed to balance out the expression.
        int parenLevel = getParenthesesLevel(str);
        for(int i = 0; i < parenLevel; ++i)
            str += ')';

        Abakus::number_t result = parseString(str.latin1());

        bool compact = !m_history->isShown();

        switch(Result::lastResult()->type()) {
            case Result::Value:
                resultVal = result.toString();

                ValueManager::instance()->setValue("ans", result);
                if(!compact)
                    item = new ResultListViewText(m_result, str, result, after, false);

                m_insert = true;
            break;

            case Result::Null: // OK, no result to speak of
                resultVal = "OK";
                if(!compact)
                    item = new ResultListViewText(m_result, str, resultVal, after, true);
            break;

            default:
                resultVal = Result::lastResult()->message();
                if(!compact)
                    item = new ResultListViewText(m_result, str, resultVal, after, true);
        }

        // Skip creating list view items if in compact mode.
        if(compact) {
            m_edit->setText(resultVal);
            TQTimer::singleShot(0, m_edit, TQT_SLOT(selectAll()));

            return;
        }
    }

    m_edit->setText(text);

    m_result->setCurrentItem(item);
    m_result->ensureItemVisible(item);

    TQTimer::singleShot(0, m_edit, TQT_SLOT(selectAll()));
}

void MainWindow::slotTextChanged()
{
    TQString str = m_edit->text();

    if(str.length() == 1 && m_insert) {
        m_insert = false;

        // Don't do anything if in RPN Mode.
        if(inRPNMode())
            return;

        if(str.find(TQRegExp("^[-+*/^]")) != -1) {
            m_edit->setText("ans " + str + " ");
            m_edit->moveCursor(TQTextEdit::MoveEnd, false);
        }
    }
}

void MainWindow::slotEvaluate()
{
    slotReturnPressed();
}

void MainWindow::slotUpdateSize()
{
    if(m_newSize != TQSize(0, 0))
        resize(m_newSize);
    else
        resize(width(), minimumSize().height());
}

void MainWindow::slotDegrees()
{
    setTrigMode(Abakus::Degrees);
    m_degrees->setChecked(true);
    if(action("setDegreesMode"))
        action<TDEToggleAction>("setDegreesMode")->setChecked(true);
}

void MainWindow::slotRadians()
{
    setTrigMode(Abakus::Radians);
    m_radians->setChecked(true);
    if(action("setRadiansMode"))
        action<TDEToggleAction>("setRadiansMode")->setChecked(true);
}

int MainWindow::getParenthesesLevel(const TQString &str)
{
    int level = 0;

    for(unsigned i = 0; i < str.length(); ++i)
        if(str[i] == '(')
            ++level;
        else if(str[i] == ')')
            --level;

    return level;
}

void MainWindow::loadConfig()
{
    {
        TDEConfigGroup config(TDEGlobal::config(), "Settings");

        TQString mode = config.readEntry("Trigonometric mode", "Degrees");
        if(mode == "Degrees") {
            setTrigMode(Abakus::Degrees);
            m_degrees->setChecked(true);
        }
        else {
            setTrigMode(Abakus::Radians);
            m_radians->setChecked(true);
        }

        bool useRPN = config.readBoolEntry("Use RPN Mode", false);
        action<TDEToggleAction>("toggleExpressionMode")->setChecked(useRPN);

        int precision = config.readNumEntry("Decimal Precision", -1);
        if(precision < -1 || precision > 75)
            precision = -1;

        Abakus::m_prec = precision;
        selectCorrectPrecisionAction();
    }

    {
        TDEConfigGroup config(TDEGlobal::config(), "Variables");

        TQStringList list = config.readListEntry("Saved Variables");
        for(TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
            TQStringList values = TQStringList::split('=', *it);
            if(values.count() != 2) {
                kdWarning() << "Your configuration file has somehow been corrupted!\n";
                continue;
            }

            ValueManager::instance()->setValue(values[0], Abakus::number_t(values[1].latin1()));
        }
    }

    {
        TDEConfigGroup config(TDEGlobal::config(), "GUI");

        bool showHistory = config.readBoolEntry("ShowHistory", true);
        action<TDEToggleAction>("toggleHistoryList")->setChecked(showHistory);
        m_history->setShown(showHistory);

        bool showFunctions = config.readBoolEntry("ShowFunctions", true);
        action<TDEToggleAction>("toggleFunctionList")->setChecked(showFunctions);
        m_fnList->setShown(showFunctions);

        bool showVariables = config.readBoolEntry("ShowVariables", true);
        action<TDEToggleAction>("toggleVariableList")->setChecked(showVariables);
        m_varList->setShown(showVariables);

        bool compactMode = config.readBoolEntry("InCompactMode", false);
        compactMode = compactMode || !showHistory;
        action<TDEToggleAction>("toggleCompactMode")->setChecked(compactMode);

        if(compactMode)
            TQTimer::singleShot(0, TQT_TQOBJECT(this), TQT_SLOT(slotToggleCompactMode()));
    }

    {
        TDEConfigGroup config(TDEGlobal::config(), "Functions");

        TQStringList fnList = config.readListEntry("FunctionList");
        for(TQStringList::ConstIterator it = fnList.begin(); it != fnList.end(); ++it)
            parseString((*it).ascii()); // Run the function definitions through the parser
    }

    populateListViews();
}

void MainWindow::saveConfig()
{
    {
        TDEConfigGroup config(TDEGlobal::config(), "Settings");

        config.writeEntry("Trigonometric mode",
             trigMode() == Abakus::Degrees
             ? "Degrees"
             : "Radians");

        config.writeEntry("Use RPN Mode", inRPNMode());
        config.writeEntry("Decimal Precision", Abakus::m_prec);
    }

    {
        TDEConfigGroup config(TDEGlobal::config(), "Variables");

        TQStringList list;
        TQStringList values = ValueManager::instance()->valueNames();
        TQStringList::ConstIterator it = values.begin();

        // Set precision to max for most accuracy
        Abakus::m_prec = 75;

        for(; it != values.end(); ++it) {
            if(ValueManager::instance()->isValueReadOnly(*it))
                continue;

            list += TQString("%1=%2")
                        .arg(*it)
                        .arg(ValueManager::instance()->value(*it).toString());
        }

        config.writeEntry("Saved Variables", list);
    }

    {
        TDEConfigGroup config(TDEGlobal::config(), "GUI");
        bool inCompactMode = action<TDEToggleAction>("toggleCompactMode")->isChecked();

        config.writeEntry("InCompactMode", inCompactMode);

        if(!inCompactMode) {
            config.writeEntry("ShowHistory", m_history->isShown());
            config.writeEntry("ShowFunctions", m_fnList->isShown());
            config.writeEntry("ShowVariables", m_varList->isShown());
        }
        else {
            config.writeEntry("ShowHistory", m_wasHistoryShown);
            config.writeEntry("ShowFunctions", m_wasFnShown);
            config.writeEntry("ShowVariables", m_wasVarShown);
        }
    }

    {
        TDEConfigGroup config(TDEGlobal::config(), "Functions");

        FunctionManager *manager = FunctionManager::instance();

        TQStringList userFunctions = manager->functionList(FunctionManager::UserDefined);
        TQStringList saveList;

        for(TQStringList::ConstIterator it = userFunctions.begin(); it != userFunctions.end(); ++it) {
            UnaryFunction *fn = dynamic_cast<UnaryFunction *>(manager->function(*it)->userFn->fn);
            TQString var = manager->function(*it)->userFn->varName;
            TQString expr = fn->operand()->infixString();

            saveList += TQString("set %1(%2) = %3").arg(*it).arg(var).arg(expr);
        }

        config.writeEntry("FunctionList", saveList);
    }
}

void MainWindow::setupLayout()
{
    TDEActionCollection *ac = actionCollection();

    KStdAction::quit(TQT_TQOBJECT(kapp), TQT_SLOT(quit()), ac);
    KStdAction::showMenubar(TQT_TQOBJECT(this), TQT_SLOT(slotToggleMenuBar()), ac);

    TDEToggleAction *ta = new TDEToggleAction(i18n("&Degrees"), SHIFT + ALT + Key_D, TQT_TQOBJECT(this), TQT_SLOT(slotDegrees()), ac, "setDegreesMode");
    ta->setExclusiveGroup("TrigMode");
    ta->setChecked(trigMode() == Abakus::Degrees);

    ta = new TDEToggleAction(i18n("&Radians"), SHIFT + ALT + Key_R, TQT_TQOBJECT(this), TQT_SLOT(slotRadians()), ac, "setRadiansMode");
    ta->setExclusiveGroup("TrigMode");
    ta->setChecked(trigMode() == Abakus::Radians);

    ta = new TDEToggleAction(i18n("Show &History List"), SHIFT + ALT + Key_H, TQT_TQOBJECT(this), TQT_SLOT(slotToggleHistoryList()), ac, "toggleHistoryList");
    ta->setChecked(true);

    ta = new TDEToggleAction(i18n("Show &Variables"), SHIFT + ALT + Key_V, TQT_TQOBJECT(this), TQT_SLOT(slotToggleVariableList()), ac, "toggleVariableList");
    ta->setChecked(true);

    ta = new TDEToggleAction(i18n("Show &Functions"), SHIFT + ALT + Key_F, TQT_TQOBJECT(this), TQT_SLOT(slotToggleFunctionList()), ac, "toggleFunctionList");
    ta->setChecked(true);

    ta = new TDEToggleAction(i18n("Activate &Compact Mode"), SHIFT + ALT + Key_C, TQT_TQOBJECT(this), TQT_SLOT(slotToggleCompactMode()), ac, "toggleCompactMode");
    ta->setChecked(false);

    ta = new TDEToggleAction(i18n("Use R&PN Mode"), SHIFT + ALT + Key_P, TQT_TQOBJECT(this), TQT_SLOT(slotToggleExpressionMode()), ac, "toggleExpressionMode");
    ta->setChecked(false);

    // Precision actions.
    ta = new TDEToggleAction(i18n("&Automatic Precision"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotPrecisionAuto()), ac, "precisionAuto");
    ta->setExclusiveGroup("Precision");
    ta->setChecked(true);

    ta = new TDEToggleAction(i18n("&3 Decimal Digits"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotPrecision3()), ac, "precision3");
    ta->setExclusiveGroup("Precision");
    ta->setChecked(false);

    ta = new TDEToggleAction(i18n("&8 Decimal Digits"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotPrecision8()), ac, "precision8");
    ta->setExclusiveGroup("Precision");
    ta->setChecked(false);

    ta = new TDEToggleAction(i18n("&15 Decimal Digits"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotPrecision15()), ac, "precision15");
    ta->setExclusiveGroup("Precision");
    ta->setChecked(false);

    ta = new TDEToggleAction(i18n("&50 Decimal Digits"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotPrecision50()), ac, "precision50");
    ta->setExclusiveGroup("Precision");
    ta->setChecked(false);

    ta = new TDEToggleAction(i18n("C&ustom Precision..."), 0, TQT_TQOBJECT(this), TQT_SLOT(slotPrecisionCustom()), ac, "precisionCustom");
    ta->setExclusiveGroup("Precision");
    ta->setChecked(false);

    new TDEAction(i18n("Clear &History"), "editclear", SHIFT + ALT + Key_L, TQT_TQOBJECT(m_result), TQT_SLOT(clear()), ac, "clearHistory");

    new TDEAction(i18n("Select Editor"), "goto", Key_F6, TQT_TQOBJECT(m_edit), TQT_SLOT(setFocus()), ac, "select_edit");
}

void MainWindow::populateListViews()
{
    TQStringList values = ValueManager::instance()->valueNames();

    Abakus::number_t value = ValueManager::instance()->value("pi");
    new ValueListViewItem(m_varList, "pi", value);

    value = ValueManager::instance()->value("e");
    new ValueListViewItem(m_varList, "e", value);
}

TDEAction *MainWindow::action(const char *key) const
{
    return actionCollection()->action(key);
}

void MainWindow::slotEntrySelected(const TQString &text)
{
    m_edit->setText(text);
    m_edit->moveCursor(TQTextEdit::MoveEnd, false);
}

void MainWindow::slotResultSelected(const TQString &text)
{
    m_edit->insert(text);
}

void MainWindow::slotToggleMenuBar()
{
    menuBar()->setShown(!menuBar()->isShown());
}

void MainWindow::slotToggleFunctionList()
{
    bool show = action<TDEToggleAction>("toggleFunctionList")->isChecked();
    m_fnList->setShown(show);

    if(!m_history->isShown()) {
        m_history->setShown(true);
        action<TDEToggleAction>("toggleHistoryList")->setChecked(true);
        slotToggleHistoryList();
    }

    action<TDEToggleAction>("toggleCompactMode")->setChecked(false);
}

void MainWindow::slotToggleVariableList()
{
    bool show = action<TDEToggleAction>("toggleVariableList")->isChecked();
    m_varList->setShown(show);

    if(!m_history->isShown()) {
        m_history->setShown(true);
        action<TDEToggleAction>("toggleHistoryList")->setChecked(true);
        slotToggleHistoryList();
    }

    action<TDEToggleAction>("toggleCompactMode")->setChecked(false);
}

void MainWindow::slotToggleHistoryList()
{
    bool show = action<TDEToggleAction>("toggleHistoryList")->isChecked();
    m_history->setShown(show);

    action<TDEToggleAction>("toggleCompactMode")->setChecked(false);
}

void MainWindow::slotNewFunction(const TQString &name)
{
    UserFunction *userFn = FunctionManager::instance()->function(name)->userFn;
    UnaryFunction *fn = dynamic_cast<UnaryFunction *>(userFn->fn);
    TQString fnName = TQString("%1(%2)").arg(name, userFn->varName);
    TQString expr = fn->operand()->infixString();

    new TDEListViewItem(m_fnList, fnName, expr);
}

void MainWindow::slotRemoveFunction(const TQString &name)
{
    UserFunction *userFn = FunctionManager::instance()->function(name)->userFn;
    TQString fnName = TQString("%1(%2)").arg(name, userFn->varName);

    TQListViewItem *item = 0;
    while((item = m_fnList->findItem(fnName, 0)) != 0)
        delete item;
}

void MainWindow::slotNewValue(const TQString &name, Abakus::number_t value)
{
    new ValueListViewItem(m_varList, name, value);
}

void MainWindow::slotChangeValue(const TQString &name, Abakus::number_t value)
{
    ValueListViewItem *item = static_cast<ValueListViewItem *>(m_varList->findItem(name, 0));

    if(item)
        item->valueChanged(value);
}

void MainWindow::slotRemoveValue(const TQString &name)
{
    delete m_varList->findItem(name, 0);
}

void MainWindow::slotToggleCompactMode()
{
    if(action<TDEToggleAction>("toggleCompactMode")->isChecked()) {
        m_wasFnShown = m_fnList->isShown();
        m_wasVarShown = m_varList->isShown();
        m_wasHistoryShown = m_history->isShown();

        m_fnList->setShown(false);
        m_varList->setShown(false);
        m_history->setShown(false);

        action<TDEToggleAction>("toggleFunctionList")->setChecked(false);
        action<TDEToggleAction>("toggleVariableList")->setChecked(false);
        action<TDEToggleAction>("toggleHistoryList")->setChecked(false);

        m_oldSize = size();
        m_newSize = TQSize(0, 0);
        TQTimer::singleShot(0, TQT_TQOBJECT(this), TQT_SLOT(slotUpdateSize()));
    }
    else {
        m_fnList->setShown(m_wasFnShown);
        m_varList->setShown(m_wasVarShown);
        m_history->setShown(m_wasHistoryShown);

        action<TDEToggleAction>("toggleFunctionList")->setChecked(m_wasFnShown);
        action<TDEToggleAction>("toggleVariableList")->setChecked(m_wasVarShown);
        action<TDEToggleAction>("toggleHistoryList")->setChecked(m_wasHistoryShown);

        m_newSize = m_oldSize;
        TQTimer::singleShot(0, TQT_TQOBJECT(this), TQT_SLOT(slotUpdateSize()));
    }
}

void MainWindow::slotToggleExpressionMode()
{
}

TQString MainWindow::interpolateExpression(const TQString &text, ResultListViewText *after)
{
    TQString str(text);
    TQRegExp stackRE("\\$\\d+");
    int pos;

    while((pos = stackRE.search(str)) != -1) {
        TQString stackStr = stackRE.cap();
        Abakus::number_t value;
        unsigned numPos = stackStr.mid(1).toUInt();

        if(!m_result->getStackValue(numPos, value)) {
            new ResultListViewText(m_result, text, i18n("Marker %1 isn't set").arg(stackStr), after, true);
            return TQString();
        }

        str.replace(pos, stackStr.length(), value.toString());
    }

    return str;
}

void MainWindow::slotPrecisionAuto()
{
    Abakus::m_prec = -1;
    redrawResults();
}

void MainWindow::slotPrecision3()
{
    Abakus::m_prec = 3;
    redrawResults();
}

void MainWindow::slotPrecision8()
{
    Abakus::m_prec = 8;
    redrawResults();
}

void MainWindow::slotPrecision15()
{
    Abakus::m_prec = 15;
    redrawResults();
}

void MainWindow::slotPrecision50()
{
    Abakus::m_prec = 50;
    redrawResults();
}

void MainWindow::slotPrecisionCustom()
{
    bool ok = false;
    int precision = KInputDialog::getInteger(i18n("Select number of decimal digits to display"),
            i18n("Decimal precision:"), Abakus::m_prec, 0, 75, 1, &ok, this);

    if(ok) {
        Abakus::m_prec = precision;
        redrawResults();
    }

    selectCorrectPrecisionAction();
}

void MainWindow::redrawResults()
{
    TQListViewItemIterator it(m_result);

    while(it.current()) {
        static_cast<ResultListViewText *>(it.current())->precisionChanged();
        ++it;
    }

    it = TQListViewItemIterator (m_varList);

    while(it.current()) {
        static_cast<ValueListViewItem *>(it.current())->valueChanged();
        ++it;
    }

    // Because of the way we implemented the menu, it is possible to deselect
    // every possibility, so make sure we have at least one selected.
    selectCorrectPrecisionAction();
}

// This function selects the correct precision action based on the value of
// Abakus::m_prec.  Useful for loading settings, or for custom precision
// selection.
void MainWindow::selectCorrectPrecisionAction()
{
    switch(Abakus::m_prec) {
        case 3:
            action<TDEToggleAction>("precision3")->setChecked(true);
        break;

        case 8:
            action<TDEToggleAction>("precision8")->setChecked(true);
        break;

        case 15:
            action<TDEToggleAction>("precision15")->setChecked(true);
        break;

        case 50:
            action<TDEToggleAction>("precision50")->setChecked(true);
        break;

        case -1:
            action<TDEToggleAction>("precisionAuto")->setChecked(true);
        break;

        default:
            action<TDEToggleAction>("precisionCustom")->setChecked(true);
    }
}

#include "mainwindow.moc"

// vim: set et ts=8 sw=4: