#ifndef SBK_EXTERNALJSOBJECTWRAPPER_H
#define SBK_EXTERNALJSOBJECTWRAPPER_H

#include <javascript/externaljsobject.h>


// Argument includes
#include <QString>
#include <qcoreevent.h>
#include <qmetaobject.h>
#include <qobject.h>
#include <qobjectdefs.h>
#include <webpage.h>
#include <sbkpython.h>

#include <array>
namespace Shiboken { struct AutoDecRef; class GilState; }

namespace PySide { class DynamicQMetaObject; }

class ExternalJsObjectWrapper : public ExternalJsObject
{
public:
    ExternalJsObjectWrapper(::WebPage * page);
    ExternalJsObjectWrapper(const ExternalJsObjectWrapper &) = delete;
    ExternalJsObjectWrapper& operator=(const ExternalJsObjectWrapper &) = delete;
    ExternalJsObjectWrapper(ExternalJsObjectWrapper &&) = delete;
    ExternalJsObjectWrapper& operator=(ExternalJsObjectWrapper &&) = delete;
    ~ExternalJsObjectWrapper() override;

    void childEvent_protected(::QChildEvent * event) { QObject::childEvent(event); }
    void childEvent(::QChildEvent * event) override;
    void connectNotify_protected(const ::QMetaMethod & signal) { QObject::connectNotify(signal); }
    void connectNotify(const ::QMetaMethod & signal) override;
    void customEvent_protected(::QEvent * event) { QObject::customEvent(event); }
    void customEvent(::QEvent * event) override;
    void disconnectNotify_protected(const ::QMetaMethod & signal) { QObject::disconnectNotify(signal); }
    void disconnectNotify(const ::QMetaMethod & signal) override;
    bool event(::QEvent * event) override;
    bool eventFilter(::QObject * watched, ::QEvent * event) override;
    void timerEvent_protected(::QTimerEvent * event) { QObject::timerEvent(event); }
    void timerEvent(::QTimerEvent * event) override;

    const ::QMetaObject * metaObject() const override;
    int qt_metacall(QMetaObject::Call call, int id, void **args) override;
    void *qt_metacast(const char *_clname) override;
    static void pysideInitQtMetaTypes();

    void resetPyMethodCache();

private:
    mutable std::array<PyObject *, 7> m_PyMethodCache = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
};

#  ifndef SBK_QOBJECTWRAPPER_H
#  define SBK_QOBJECTWRAPPER_H

// Inherited base class:
class QObjectWrapper : public QObject
{
public:
    QObjectWrapper(::QObject * parent = nullptr);
    QObjectWrapper(const QObjectWrapper &) = delete;
    QObjectWrapper& operator=(const QObjectWrapper &) = delete;
    QObjectWrapper(QObjectWrapper &&) = delete;
    QObjectWrapper& operator=(QObjectWrapper &&) = delete;
    ~QObjectWrapper() override;

    void childEvent_protected(::QChildEvent * event) { QObject::childEvent(event); }
    void childEvent(::QChildEvent * event) override;
    static void sbk_o_childEvent([[maybe_unused]] const char *ownerClassName, [[maybe_unused]] const char *funcName, [[maybe_unused]] Shiboken::GilState &gil, [[maybe_unused]] const Shiboken::AutoDecRef &pyOverride, [[maybe_unused]] ::QChildEvent * event);
    void connectNotify_protected(const ::QMetaMethod & signal) { QObject::connectNotify(signal); }
    void connectNotify(const ::QMetaMethod & signal) override;
    void customEvent_protected(::QEvent * event) { QObject::customEvent(event); }
    void customEvent(::QEvent * event) override;
    static void sbk_o_customEvent([[maybe_unused]] const char *ownerClassName, [[maybe_unused]] const char *funcName, [[maybe_unused]] Shiboken::GilState &gil, [[maybe_unused]] const Shiboken::AutoDecRef &pyOverride, [[maybe_unused]] ::QEvent * event);
    void disconnectNotify_protected(const ::QMetaMethod & signal) { QObject::disconnectNotify(signal); }
    void disconnectNotify(const ::QMetaMethod & signal) override;
    bool event(::QEvent * event) override;
    static bool sbk_o_event([[maybe_unused]] const char *ownerClassName, [[maybe_unused]] const char *funcName, [[maybe_unused]] Shiboken::GilState &gil, [[maybe_unused]] const Shiboken::AutoDecRef &pyOverride, [[maybe_unused]] ::QEvent * event);
    bool eventFilter(::QObject * watched, ::QEvent * event) override;
    static bool sbk_o_eventFilter([[maybe_unused]] const char *ownerClassName, [[maybe_unused]] const char *funcName, [[maybe_unused]] Shiboken::GilState &gil, [[maybe_unused]] const Shiboken::AutoDecRef &pyOverride, [[maybe_unused]] ::QObject * watched, [[maybe_unused]] ::QEvent * event);
    bool isSignalConnected_protected(const ::QMetaMethod & signal) const { return QObject::isSignalConnected(signal); }
    int receivers_protected(const char * signal) const { return QObject::receivers(signal); }
    ::QObject * sender_protected() const { return QObject::sender(); }
    int senderSignalIndex_protected() const { return QObject::senderSignalIndex(); }
    void timerEvent_protected(::QTimerEvent * event) { QObject::timerEvent(event); }
    void timerEvent(::QTimerEvent * event) override;
    static void sbk_o_timerEvent([[maybe_unused]] const char *ownerClassName, [[maybe_unused]] const char *funcName, [[maybe_unused]] Shiboken::GilState &gil, [[maybe_unused]] const Shiboken::AutoDecRef &pyOverride, [[maybe_unused]] ::QTimerEvent * event);

    const ::QMetaObject * metaObject() const override;
    int qt_metacall(QMetaObject::Call call, int id, void **args) override;
    void *qt_metacast(const char *_clname) override;
    static void pysideInitQtMetaTypes();

    void resetPyMethodCache();

private:
    mutable std::array<PyObject *, 7> m_PyMethodCache = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
};

#  endif // SBK_QOBJECTWRAPPER_H

#endif // SBK_EXTERNALJSOBJECTWRAPPER_H
