// This is the implementation of the QPyDBusReply class.
//
// Copyright (c) 2014 Riverbank Computing Limited <info@riverbankcomputing.com>
// 
// This file is part of PyQt.
// 
// This file may be used under the terms of the GNU General Public
// License versions 2.0 or 3.0 as published by the Free Software
// Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
// included in the packaging of this file.  Alternatively you may (at
// your option) use any later version of the GNU General Public
// License if such license has been publicly approved by Riverbank
// Computing Limited (or its successors, if any) and the KDE Free Qt
// Foundation. In addition, as a special exception, Riverbank gives you
// certain additional rights. These rights are described in the Riverbank
// GPL Exception version 1.1, which can be found in the file
// GPL_EXCEPTION.txt in this package.
// 
// If you are unsure which license is appropriate for your use, please
// contact the sales department at sales@riverbankcomputing.com.
// 
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.


#include <Python.h>

#include <QDBusMessage>
#include <QDBusPendingCall>

#include "sipAPIQtDBus.h"

#include "qpydbusreply.h"


// Extract a reply from a message.  The GIL should be held.
QPyDBusReply::QPyDBusReply(const QDBusMessage &reply)
{
    *this = reply;
}


// Extract a reply from a pending call.  The GIL should be held.
QPyDBusReply::QPyDBusReply(const QDBusPendingCall &call)
{
    *this = call;
}


// Extract a reply from an error.
QPyDBusReply::QPyDBusReply(const QDBusError &error)
{
    _q_value = 0;
    _q_is_valid = !error.isValid();
    _q_error = error;
}


// Copy a reply.  The GIL should be held.
QPyDBusReply::QPyDBusReply(const QPyDBusReply &other)
{
    _q_value = other._q_value;
    Py_XINCREF(_q_value);

    _q_value_variant = other._q_value_variant;
    _q_is_valid = other._q_is_valid;
    _q_error = other._q_error;
}


// A reply created from a QDBusReply<> mapped type convertor.
QPyDBusReply::QPyDBusReply(PyObject *q_value, bool q_is_valid, const QDBusError &q_error) : _q_value(q_value), _q_is_valid(q_is_valid), _q_error(q_error)
{
}


// The dtor.  The GIL should be held.
QPyDBusReply::~QPyDBusReply()
{
    Py_XDECREF(_q_value);
}


// Return the value of the reply.  The GIL should be held.
PyObject *QPyDBusReply::value(PyObject *type) const
{
    if (!_q_is_valid)
    {
        PyErr_SetString(PyExc_ValueError, "QDBusReply value is invalid");
        return 0;
    }

    // Return any explicit value.
    if (_q_value)
    {
        if (type)
        {
            PyErr_SetString(PyExc_ValueError,
                    "'type' argument cannot be used with an explcitly typed reply");
            return 0;
        }

        Py_INCREF(_q_value);
        return _q_value;
    }

    QVariant val(_q_value_variant);

    return qpycore_qvariant_value(val, type);
}


// Extract a reply from a message.  The GIL should be held.
QPyDBusReply &QPyDBusReply::operator=(const QDBusMessage &reply)
{
    _q_value = 0;
    _q_error = reply;
    _q_is_valid = !_q_error.isValid();

    if (_q_is_valid)
    {
        QList<QVariant> results = reply.arguments();

        if (results.count() == 0)
        {
            Py_INCREF(Py_None);
            _q_value = Py_None;
        }
        else
        {
            // Convert this later if requested.
            _q_value_variant = results.at(0);
        }
    }

    return *this;
}


// Extract a reply from a pending call.  The GIL should be held.
QPyDBusReply &QPyDBusReply::operator=(const QDBusPendingCall &call)
{
    QDBusPendingCall other(call);

    Py_BEGIN_ALLOW_THREADS
    other.waitForFinished();
    Py_END_ALLOW_THREADS

    return *this = other.reply();
}
