// SPDX-FileCopyrightText: 2026 Ernie Pasveer <epasveer@att.net>
//
// SPDX-License-Identifier: GPL-3.0-or-later

#include "SeerCommandLogsWidget.h"
#include "SeerMacroToolButton.h"
#include "SeerLogWidget.h"
#include "SeerHelpPageDialog.h"
#include "QHContainerWidget.h"
#include <QtGui/QFont>
#include <QtWidgets/QTextEdit>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QMenu>
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QWidgetAction>
#include <QtCore/QSettings>
#include <QtCore/QDebug>

#include <QWidgetAction>

SeerCommandLogsWidget::SeerCommandLogsWidget (QWidget* parent) : QWidget(parent) {

    _consoleWidget              = 0;
    _consoleIndex               = -1;
    _consoleScrollLines         = 1000;
    _rememberManualCommandCount = 10;
    _aboutToQuit                = false;

    setupUi(this);

    // Setup the widgets
    QFont font;
    font.setFamily("monospace [Consolas]");
    font.setFixedPitch(true);
    font.setStyleHint(QFont::TypeWriter);

    m1ToolButton->setMacroName("M1");
    m2ToolButton->setMacroName("M2");
    m3ToolButton->setMacroName("M3");
    m4ToolButton->setMacroName("M4");
    m5ToolButton->setMacroName("M5");
    m6ToolButton->setMacroName("M6");
    m7ToolButton->setMacroName("M7");
    m8ToolButton->setMacroName("M8");
    m9ToolButton->setMacroName("M9");
    m0ToolButton->setMacroName("M0");

    _messagesBrowserWidget    = new SeerMessagesBrowserWidget(this);
    _breakpointsBrowserWidget = new SeerBreakpointsBrowserWidget(this);
    _watchpointsBrowserWidget = new SeerWatchpointsBrowserWidget(this);
    _catchpointsBrowserWidget = new SeerCatchpointsBrowserWidget(this);
    _printpointsBrowserWidget = new SeerPrintpointsBrowserWidget(this);
    _checkpointsBrowserWidget = new SeerCheckpointsBrowserWidget(this);

    _gdbOutputLog             = new SeerGdbLogWidget(this);
    _seerOutputLog            = new SeerSeerLogWidget(this);
    _gdbOutputLog->setPlaceholderText("[gdb output]");
    _seerOutputLog->setPlaceholderText("[seer output]");

    logsTabWidget->clear();
    logsTabWidget->addTab(_messagesBrowserWidget,    "Messages");
    logsTabWidget->addTab(_breakpointsBrowserWidget, "Breakpoints");
    logsTabWidget->addTab(_watchpointsBrowserWidget, "Watchpoints");
    logsTabWidget->addTab(_catchpointsBrowserWidget, "Catchpoints");
    logsTabWidget->addTab(_printpointsBrowserWidget, "Printpoints");
    logsTabWidget->addTab(_checkpointsBrowserWidget, "Checkpoints");
    logsTabWidget->addTab(_gdbOutputLog,             "GDB output");
    logsTabWidget->addTab(_seerOutputLog,            "Seer output");
    logsTabWidget->setCurrentIndex(0);

    QToolButton* tabsContextMenuButton = new QToolButton(logsTabWidget);
    tabsContextMenuButton->setIcon(QIcon(":/seer/resources/thenounproject/preferences.svg"));
    tabsContextMenuButton->setToolTip("Show/Hide tabs.");
    tabsContextMenuButton->setContextMenuPolicy(Qt::CustomContextMenu);

    QHContainerWidget* hcontainer = new QHContainerWidget(this);
    hcontainer->setSpacing(3);
    hcontainer->addWidget(tabsContextMenuButton);

    logsTabWidget->setCornerWidget(hcontainer, Qt::TopRightCorner);

    // Create the console tab.
    // Each RUN method will create and connect to the console's terminal.
    createConsole();

    // Set manual command settings.
    manualCommandComboBox->setFont(font);
    manualCommandComboBox->setEditable(true);
    manualCommandComboBox->lineEdit()->setPlaceholderText("Manually enter a gdb/mi command...");
    manualCommandComboBox->lineEdit()->setToolTip("Manually enter a gdb/mi command.");
    manualCommandComboBox->lineEdit()->setClearButtonEnabled(true);

    // Restore tab ordering and manual command history.
    readSettings();
    readHistorySettings();
    readLogSettings();

    // Connect things.
    QObject::connect(tabsContextMenuButton,             &QToolButton::clicked,                          this,   &SeerCommandLogsWidget::handleTabsContextMenuButtonClicked);
    QObject::connect(logsTabWidget->tabBar(),           &QTabBar::tabMoved,                             this,   &SeerCommandLogsWidget::handleLogsTabMoved);
    QObject::connect(logsTabWidget->tabBar(),           &QTabBar::currentChanged,                       this,   &SeerCommandLogsWidget::handleLogsTabChanged);
    QObject::connect(manualCommandComboBox->lineEdit(), &QLineEdit::returnPressed,                      this,   &SeerCommandLogsWidget::handleManualCommandExecute);
    QObject::connect(manualCommandComboBox,             QOverload<int>::of(&QComboBox::activated),      this,   &SeerCommandLogsWidget::handleManualCommandChanged);
    QObject::connect(_messagesBrowserWidget,            &SeerMessagesBrowserWidget::showMessages,       this,   &SeerCommandLogsWidget::handleRaiseMessageTab);
    QObject::connect(_gdbOutputLog,                     &SeerLogWidget::logEnabledChanged,              this,   &SeerCommandLogsWidget::handleLogOutputChanged);
    QObject::connect(_gdbOutputLog,                     &SeerLogWidget::logTimeStampChanged,            this,   &SeerCommandLogsWidget::handleLogOutputChanged);
    QObject::connect(_seerOutputLog,                    &SeerLogWidget::logEnabledChanged,              this,   &SeerCommandLogsWidget::handleLogOutputChanged);
    QObject::connect(_seerOutputLog,                    &SeerLogWidget::logTimeStampChanged,            this,   &SeerCommandLogsWidget::handleLogOutputChanged);
    QObject::connect(breakpointsLoadToolButton,         &QToolButton::clicked,                          this,   &SeerCommandLogsWidget::handleGdbLoadBreakpoints);
    QObject::connect(breakpointsSaveToolButton,         &QToolButton::clicked,                          this,   &SeerCommandLogsWidget::handleGdbSaveBreakpoints);
    QObject::connect(helpToolButton,                    &QToolButton::clicked,                          this,   &SeerCommandLogsWidget::handleHelpToolButtonClicked);
    QObject::connect(macroButtonGroup,                  &QButtonGroup::buttonClicked,                   this,   &SeerCommandLogsWidget::handleMacroToolButtonClicked);
    QObject::connect(qApp,                              &QCoreApplication::aboutToQuit,                 this,   &SeerCommandLogsWidget::handleAboutToQuit);
}

SeerCommandLogsWidget::~SeerCommandLogsWidget () {

    deleteConsole();
}

SeerMessagesBrowserWidget* SeerCommandLogsWidget::messagesBrowser () {

    return _messagesBrowserWidget;
}

SeerBreakpointsBrowserWidget* SeerCommandLogsWidget::breakpointsBrowser () {

    return _breakpointsBrowserWidget;
}

SeerWatchpointsBrowserWidget* SeerCommandLogsWidget::watchpointsBrowser () {

    return _watchpointsBrowserWidget;
}

SeerCatchpointsBrowserWidget* SeerCommandLogsWidget::catchpointsBrowser () {

    return _catchpointsBrowserWidget;
}

SeerPrintpointsBrowserWidget* SeerCommandLogsWidget::printpointsBrowser () {

    return _printpointsBrowserWidget;
}

SeerCheckpointsBrowserWidget* SeerCommandLogsWidget::checkpointsBrowser () {

    return _checkpointsBrowserWidget;
}

SeerGdbLogWidget* SeerCommandLogsWidget::gdbOutputLog () {

    return _gdbOutputLog;
}

SeerSeerLogWidget* SeerCommandLogsWidget::seerOutputLog () {

    return _seerOutputLog;
}

SeerConsoleWidget* SeerCommandLogsWidget::console () {

    return _consoleWidget;
}

void SeerCommandLogsWidget::createConsole () {

    if (_consoleWidget == 0) {

        _consoleWidget = new SeerConsoleWidget(0);

        // The console needs to know when it's detached or reattached.
        QObject::connect(logsTabWidget, qOverload<QWidget*>(&QDetachTabWidget::tabDetached),   _consoleWidget, &SeerConsoleWidget::handleTabDetached);
        QObject::connect(logsTabWidget, qOverload<QWidget*>(&QDetachTabWidget::tabReattached), _consoleWidget, &SeerConsoleWidget::handleTabReattached);

        _consoleIndex = logsTabWidget->addTab(_consoleWidget, "Console output");

        QObject::connect(_consoleWidget, &SeerConsoleWidget::newTextAdded,  this, &SeerCommandLogsWidget::handleConsoleNewTextAdded);
        QObject::connect(_consoleWidget, &SeerConsoleWidget::newTextViewed, this, &SeerCommandLogsWidget::handleConsoleNewTextViewed);

        setConsoleMode(consoleMode());
        setConsoleScrollLines(consoleScrollLines());
    }
}

void SeerCommandLogsWidget::deleteConsole () {

    if (_consoleWidget) {

        if (_consoleIndex >= 0) {
            logsTabWidget->removeTab(_consoleIndex);
        }

        delete _consoleWidget;
        _consoleWidget = 0;
        _consoleIndex  = -1;
    }
}

void SeerCommandLogsWidget::reattachConsole () {

     if (_consoleIndex < 0) {
        return;
    }

    if (_consoleWidget == nullptr) {
        return;
    }

    _consoleMode = "attached";

    logsTabWidget->reattachTab(_consoleIndex);
}

void SeerCommandLogsWidget::setConsoleMode (const QString& mode) {

    _consoleMode = mode;

    handleConsoleModeChanged();
}

QString SeerCommandLogsWidget::consoleMode () const {

    return _consoleMode;
}

void SeerCommandLogsWidget::setConsoleScrollLines (int count) {

    _consoleScrollLines = count;

    if (_consoleWidget) {
        _consoleWidget->setScrollLines(_consoleScrollLines);
    }
}

int SeerCommandLogsWidget::consoleScrollLines () const {

    return _consoleScrollLines;
}

void SeerCommandLogsWidget::setManualCommands (const QStringList& commands) {

    manualCommandComboBox->clear();
    manualCommandComboBox->addItems(commands);

    // Point to last one.
    if (manualCommandComboBox->count() > 0) {
        manualCommandComboBox->setCurrentIndex(manualCommandComboBox->count()-1);
    }
}

QStringList SeerCommandLogsWidget::manualCommands(int count) const {

    // Select all if a zero.
    if (count == 0) {
        count = manualCommandComboBox->count();
    }

    // No more than count.
    if (count > manualCommandComboBox->count()) {
        count = manualCommandComboBox->count();
    }

    // Calculate starting position in list.
    int index = manualCommandComboBox->count() - count;

    // Get the list.
    QStringList list;

    for (; index<count; index++) {
        list << manualCommandComboBox->itemText(index);
    }

    return list;
}

void SeerCommandLogsWidget::setRememberManualCommandCount (int count) {

    _rememberManualCommandCount = count;
}

int SeerCommandLogsWidget::rememberManualCommandCount () const {

    return _rememberManualCommandCount;
}

void SeerCommandLogsWidget::clearManualCommandHistory () {

    // Zap the entries in the combobox.
    manualCommandComboBox->clear();

    // Write the history settings.
    writeHistorySettings();
}

void SeerCommandLogsWidget::handleLogsTabMoved (int to, int from) {

    Q_UNUSED(from);
    Q_UNUSED(to);

    // Keep track of console tab if it moved.
    if (_consoleIndex == from) {
        _consoleIndex = to;
    }

    // Don't handle anything here if Seer is exiting.
    if (_aboutToQuit) {
        return;
    }

    writeSettings();
}

void SeerCommandLogsWidget::handleLogsTabChanged (int index) {

    Q_UNUSED(index);

    // Don't handle anything here if Seer is exiting.
    if (_aboutToQuit) {
        return;
    }

    writeSettings();
}

void SeerCommandLogsWidget::handleRaiseMessageTab () {

    int idx = logsTabWidget->indexOf(_messagesBrowserWidget);

    if (idx < 0) {
        return;
    }

    logsTabWidget->setCurrentIndex(idx);
}

void SeerCommandLogsWidget::handleConsoleModeChanged () {

    if (_consoleIndex < 0) {
        return;
    }

    if (_consoleWidget == nullptr) {
        return;
    }

    if (_consoleMode == "detached") {
        logsTabWidget->detachTab(_consoleIndex, false);
        _consoleWidget->raise();
        _consoleWidget->resetSize();
    }else if (_consoleMode == "detachedminimized") {
        logsTabWidget->detachTab(_consoleIndex, true);
        _consoleWidget->resetSize();
    }else if (_consoleMode == "attached") {
        logsTabWidget->reattachTab(_consoleIndex);
    }else{
        logsTabWidget->reattachTab(_consoleIndex);
    }
}

void SeerCommandLogsWidget::handleConsoleNewTextAdded () {

    if (_consoleIndex >= 0) {
        logsTabWidget->setTabIcon(_consoleIndex, QIcon(":/seer/resources/RelaxLightIcons/data-information.svg"));
    }
}

void SeerCommandLogsWidget::handleConsoleNewTextViewed () {

    if (_consoleIndex >= 0) {
        logsTabWidget->setTabIcon(_consoleIndex, QIcon());
    }
}

void SeerCommandLogsWidget::handleManualCommandExecute () {

    // Get new command.
    QString command = manualCommandComboBox->currentText();

    // Do nothing if it is blank.
    if (command == "") {
        return;
    }

    // Remove the second to last line, if it is blank.
    if (manualCommandComboBox->count() >= 2) {

        QString lastCommand = manualCommandComboBox->itemText(manualCommandComboBox->count()-2);

        if (lastCommand == "") {
            manualCommandComboBox->removeItem(manualCommandComboBox->count()-2);
        }
    }

    // Remove the last line, if it is blank.
    if (manualCommandComboBox->count() >= 1) {

        QString lastCommand = manualCommandComboBox->itemText(manualCommandComboBox->count()-1);

        if (lastCommand == "") {
            manualCommandComboBox->removeItem(manualCommandComboBox->count()-1);
        }
    }

    // Add entered command to the end of the list as long as it's not
    // already there.
    if (manualCommandComboBox->count() > 0) {

        QString lastCommand = manualCommandComboBox->itemText(manualCommandComboBox->count()-1);

        if (lastCommand != command) {
            manualCommandComboBox->addItem(command);
        }
    }

    // Add a blank entry. It will be removed when the next manual command is entered.
    manualCommandComboBox->addItem("");

    // Point to last one.
    manualCommandComboBox->setCurrentIndex(manualCommandComboBox->count()-1);

    // Execute it.
    emit executeGdbCommand(command);

    writeHistorySettings();
}

void SeerCommandLogsWidget::handleManualCommandChanged () {

    writeHistorySettings();
}


void SeerCommandLogsWidget::handleLogOutputChanged () {

    writeLogSettings();
}

void SeerCommandLogsWidget::handleGdbLoadBreakpoints () {

    QFileDialog dialog(this, "Seer - Load Breakpoints from a file.", "./", "Breakpoints (*.seer);;All files (*.*)");
    dialog.setOptions(QFileDialog::DontUseNativeDialog);
    dialog.setAcceptMode(QFileDialog::AcceptOpen);
    dialog.setFileMode(QFileDialog::AnyFile);
    dialog.setDefaultSuffix("seer");

    if (dialog.exec() != QDialog::Accepted) {
        return;
    }

    QStringList files = dialog.selectedFiles();

    if (files.size() == 0) {
        return;
    }

    if (files.size() > 1) {
        QMessageBox::critical(this, tr("Error"), tr("Select only 1 file."));
        return;
    }

    QString fname = files[0];

    emit executeGdbCommand("source -v " + fname);
    emit refreshBreakpointsList();

    QMessageBox::information(this, "Seer", "Loaded.");
}

void SeerCommandLogsWidget::handleGdbSaveBreakpoints () {

    if (breakpointsBrowser()->isEmpty() &&
        watchpointsBrowser()->isEmpty() &&
        catchpointsBrowser()->isEmpty() &&
        printpointsBrowser()->isEmpty()) {

        QMessageBox::information(this, "Seer", "No breakpoints of any kind to save.");

        return;
    }

    QFileDialog dialog(this, "Seer - Save Breakpoints to a file.", "./", "Breakpoints (*.seer);;All files (*.*)");
    dialog.setOptions(QFileDialog::DontUseNativeDialog);
    dialog.setAcceptMode(QFileDialog::AcceptSave);
    dialog.setFileMode(QFileDialog::AnyFile);
    dialog.setDefaultSuffix("seer");
    dialog.selectFile("breakpoints.seer");

    if (dialog.exec() != QDialog::Accepted) {
        return;
    }

    QStringList files = dialog.selectedFiles();

    if (files.size() == 0) {
        return;
    }

    if (files.size() > 1) {
        QMessageBox::critical(this, tr("Error"), tr("Select only 1 file."));
        return;
    }

    QString fname = files[0];

    emit executeGdbCommand("save breakpoints " + fname);

    QMessageBox::information(this, "Seer", "Saved.");
}

void SeerCommandLogsWidget::handleHelpToolButtonClicked () {

    SeerHelpPageDialog* help = new SeerHelpPageDialog;
    help->loadFile(":/seer/resources/help/BreakpointGdbSeerManager.md");
    help->show();
    help->raise();
}

void SeerCommandLogsWidget::handleMacroToolButtonClicked (QAbstractButton* button) {

    if (button == nullptr) {
        return;
    }

    SeerMacroToolButton* tb = qobject_cast<SeerMacroToolButton*>(button);

    QString macroFileName = tb->macroFileName();

    if (macroFileName == "") {
        return;
    }

    emit executeGdbCommand("source -v " + macroFileName);
}

void SeerCommandLogsWidget::writeSettings () {

    // Build up visible list.
    QStringList visible;

    for (int i=0; i<logsTabWidget->tabBar()->count(); i++) {
        visible.append(logsTabWidget->isTabVisible(i) ? "true" : "false");
    }

    // Build up tab order.
    QStringList tabs;

    for (int i=0; i<logsTabWidget->tabBar()->count(); i++) {
        tabs.append(logsTabWidget->tabBar()->tabText(i));
    }

    // Build up current tab.
    QString current = logsTabWidget->tabBar()->tabText(logsTabWidget->tabBar()->currentIndex());

    //qDebug() << "Tabs"    << tabs;
    //qDebug() << "Current" << current;

    // Write settings.
    QSettings settings;

    settings.beginGroup("logsmanagerwindow"); {
        settings.setValue("taborder",   tabs.join(','));
        settings.setValue("tabvisible", visible.join(','));
        settings.setValue("tabcurrent", current);
    } settings.endGroup();
}

void SeerCommandLogsWidget::readSettings () {

    QSettings settings;

    // Read tab order from settings.
    QStringList tabs;
    QStringList visible;
    QString     current;

    settings.beginGroup("logsmanagerwindow"); {
        tabs    = settings.value("taborder").toString().split(',');
        visible = settings.value("tabvisible").toString().split(',');
        current = settings.value("tabcurrent").toString();
    } settings.endGroup();

    //qDebug() << "Tabs"    << tabs;
    //qDebug() << "Current" << current;

    // Move tabs to the requested order.
    for (int i=0; i<tabs.count(); i++) {

        QString tab = tabs[i];
        int     tb  = -1;

        for (int j=0; j<logsTabWidget->tabBar()->count(); j++) {
            if (logsTabWidget->tabBar()->tabText(j) == tab) {
                tb = j;
                break;
            }
        }

        if (tb != -1) {
            logsTabWidget->tabBar()->moveTab(tb, i);
        }
    }

    // Find the console tab index.
    _consoleIndex = -1;
    for (int i=0; i<logsTabWidget->tabBar()->count(); i++) {
        if (logsTabWidget->tabBar()->tabText(i) == "Console output") {
            _consoleIndex = i;
            break;
        }
    }

    if (_consoleIndex < 0) {
        qDebug() << "The console tab index is not in the settings.";
    }

    // Show/Hide tabs.
    for (int i=0; i<visible.count(); i++) {
        QString flag = visible[i];
        if (flag == "true") {
            logsTabWidget->setTabVisible(i,true);
        }else if (flag == "false") {
            logsTabWidget->setTabVisible(i,false);
        }else{
            logsTabWidget->setTabVisible(i,true);
        }
    }

    // Make a tab current.
    if (current != "") {
        for (int i=0; i<logsTabWidget->tabBar()->count(); i++) {
            if (logsTabWidget->tabBar()->tabText(i) == current) {
                logsTabWidget->setCurrentIndex(i);
                break;
            }
        }
    }else{
        logsTabWidget->setCurrentIndex(0);
    }
}

void SeerCommandLogsWidget::writeHistorySettings () {

    QSettings settings;

    // Write the manual command history.
    settings.beginWriteArray("manualgdbcommandshistory"); {
        QStringList commands = manualCommands(rememberManualCommandCount());
        if (commands.size() > 0) {
            for (int i = 0; i < commands.size(); ++i) {
                settings.setArrayIndex(i);
                settings.setValue("command", commands[i]);
            }
        }
    } settings.endArray();
}

void SeerCommandLogsWidget::readHistorySettings () {

    QSettings settings;

    // Read the manual command history.
    int size = settings.beginReadArray("manualgdbcommandshistory"); {
        QStringList commands;
        for (int i = 0; i < size; ++i) {
            settings.setArrayIndex(i);
            commands << settings.value("command").toString();
        }
        setManualCommands(commands);
    } settings.endArray();
}

void SeerCommandLogsWidget::writeLogSettings () {

    QSettings settings;

    // Write log settings.
    settings.beginGroup("gdboutputlog"); {
        settings.setValue("enabled",   _gdbOutputLog->isLogEnabled());
        settings.setValue("timestamp", _gdbOutputLog->isTimeStampEnabled());
    } settings.endGroup();

    settings.beginGroup("seeroutputlog"); {
        settings.setValue("enabled",   _seerOutputLog->isLogEnabled());
        settings.setValue("timestamp", _seerOutputLog->isTimeStampEnabled());
    } settings.endGroup();
}

void SeerCommandLogsWidget::readLogSettings () {

    QSettings settings;

    // Read log settings.
    settings.beginGroup("gdboutputlog"); {
        _gdbOutputLog->setLogEnabled(settings.value("enabled", true).toBool());
        _gdbOutputLog->setTimeStampEnabled(settings.value("timestamp", false).toBool());
    } settings.endGroup();

    settings.beginGroup("seeroutputlog"); {
        _seerOutputLog->setLogEnabled(settings.value("enabled", true).toBool());
        _seerOutputLog->setTimeStampEnabled(settings.value("timestamp", false).toBool());
    } settings.endGroup();
}

void SeerCommandLogsWidget::handleAboutToQuit () {

    _aboutToQuit = true;
}

void SeerCommandLogsWidget::handleTabsContextMenuButtonClicked() {

    // Build the menu and execute it.
    QMenu        contextMenu;
    QWidget*     container = new QWidget(&contextMenu);
    QVBoxLayout* layout    = new QVBoxLayout(container);

    for (int i = 0; i < logsTabWidget->count(); i++) {

        QString title = logsTabWidget->tabText(i);
        QCheckBox* showTabCheckBox = new QCheckBox(title, container);
        showTabCheckBox->setChecked(logsTabWidget->isTabVisible(i));
        layout->addWidget(showTabCheckBox);

        QObject::connect(showTabCheckBox, &QCheckBox::toggled, [this, showTabCheckBox, i](bool checked) {

            // Count visible tabs.
            int count=0;

            for (int x=0; x<logsTabWidget->count(); x++) {
                if (logsTabWidget->isTabVisible(x)) {
                    count++;
                }
            }

            // Adjust the count. The 'checked' is made before the UI is updated.
            if (checked == true) {
                count++;
            }else{
                count--;
            }

            // Reset the checkbox UI if the last visible tab was clicked.
            if (checked == false and count == 0) {
                showTabCheckBox->setChecked(true);
            // Don't hide last visible tab.
            }else if (checked == false and count > 1) {
                logsTabWidget->setTabVisible(i, checked);
            // Always show tabs when asked.
            }else{
                logsTabWidget->setTabVisible(i, checked);
            }

            writeSettings();
        });
    }
    container->setLayout(layout);

    QWidgetAction* action = new QWidgetAction(&contextMenu);
    action->setDefaultWidget(container);
    contextMenu.addAction(action);

    contextMenu.exec(QCursor::pos());
}

