/*  This file is part of the KDE libraries and the Kate part.
 *
 *  Copyright (C) 2009 Dominik Haumann <dhaumann kde org>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301, USA.
 */

#include "katecommandlinescript.h"

#include <QScriptValue>
#include <QScriptEngine>

#include <KLocalizedString>
#include <KShell>

#include "katedocument.h"
#include "kateview.h"
#include "katecmd.h"
#include "katepartdebug.h"

KateCommandLineScript::KateCommandLineScript(const QString &url, const KateCommandLineScriptHeader &header)
    : KateScript(url)
    , KTextEditor::Command(header.functions())
    , m_commandHeader(header)
{
}

KateCommandLineScript::~KateCommandLineScript()
{
}

const KateCommandLineScriptHeader &KateCommandLineScript::commandHeader()
{
    return m_commandHeader;
}

bool KateCommandLineScript::callFunction(const QString &cmd, const QStringList args, QString &errorMessage)
{
    clearExceptions();
    QScriptValue command = function(cmd);
    if (!command.isValid()) {
        errorMessage = i18n("Function '%1' not found in script: %2", cmd, url());
        return false;
    }

    // add the arguments that we are going to pass to the function
    QScriptValueList arguments;
    foreach (const QString &arg, args) {
        arguments << QScriptValue(m_engine, arg);
    }

    QScriptValue result = command.call(QScriptValue(), arguments);
    // error during the calling?
    if (m_engine->hasUncaughtException()) {
        errorMessage = backtrace(result, i18n("Error calling %1", cmd));
        return false;
    }

    return true;
}

ScriptActionInfo KateCommandLineScript::actionInfo(const QString &cmd)
{
    clearExceptions();
    QScriptValue actionFunc = function(QLatin1Literal("action"));
    if (!actionFunc.isValid()) {
        qCDebug(LOG_PART) << i18n("Function 'action' not found in script: %1", url());
        return ScriptActionInfo();
    }

    // add the arguments that we are going to pass to the function
    QScriptValueList arguments;
    arguments << cmd;

    QScriptValue result = actionFunc.call(QScriptValue(), arguments);
    // error during the calling?
    if (m_engine->hasUncaughtException()) {
        displayBacktrace(result, i18n("Error calling action(%1)", cmd));
        return ScriptActionInfo();
    }

    ScriptActionInfo info;
    info.setCommand(cmd);
    info.setText(result.property(QLatin1String("text")).toString());
    info.setIcon(result.property(QLatin1String("icon")).toString());
    info.setCategory(result.property(QLatin1String("category")).toString());
    info.setInteractive(result.property(QLatin1String("interactive")).toBool());
    info.setShortcut(result.property(QLatin1String("shortcut")).toString());

    return info;
}

bool KateCommandLineScript::exec(KTextEditor::View *view, const QString &cmd, QString &msg,
                                 const KTextEditor::Range &range)
{
    if (range.isValid())
        view->setSelection(range);
    
    KShell::Errors errorCode;
    QStringList args(KShell::splitArgs(cmd, KShell::NoOptions, &errorCode));

    if (errorCode != KShell::NoError) {
        msg = i18n("Bad quoting in call: %1. Please escape single quotes with a backslash.", cmd);
        return false;
    }

    QString _cmd(args.first());
    args.removeFirst();

    if (!view) {
        msg = i18n("Could not access view");
        return false;
    }

    if (setView(qobject_cast<KTextEditor::ViewPrivate *>(view))) {
        // setView fails if the script cannot be loaded
        // balance edit stack in any case!
        qobject_cast<KTextEditor::ViewPrivate *>(view)->doc()->pushEditState();
        bool success = callFunction(_cmd, args, msg);
        qobject_cast<KTextEditor::ViewPrivate *>(view)->doc()->popEditState();
        return success;
    }

    return false;
}

bool KateCommandLineScript::supportsRange(const QString &)
{
    return true;
}

bool KateCommandLineScript::help(KTextEditor::View *view, const QString &cmd, QString &msg)
{
    if (!setView(qobject_cast<KTextEditor::ViewPrivate *>(view))) {
        // setView fails, if the script cannot be loaded
        return false;
    }

    clearExceptions();
    QScriptValue helpFunction = function(QLatin1String("help"));
    if (!helpFunction.isValid()) {
        return false;
    }

    // add the arguments that we are going to pass to the function
    QScriptValueList arguments;
    arguments << QScriptValue(m_engine, cmd);

    QScriptValue result = helpFunction.call(QScriptValue(), arguments);

    // error during the calling?
    if (m_engine->hasUncaughtException()) {
        msg = backtrace(result, i18n("Error calling 'help %1'", cmd));
        return false;
    }

    if (result.isUndefined() || !result.isString()) {
        qCDebug(LOG_PART) << i18n("No help specified for command '%1' in script %2", cmd, url());
        return false;
    }
    msg = result.toString();

    return !msg.isEmpty();
}

