// Copyright (C) 2022 JiDe Zhang <zccrs@live.com>.
// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#pragma once

#include <qwglobal.h>
#include <QObject>

struct wlr_ABC;

QW_BEGIN_NAMESPACE

class QWABCPrivate;
class QW_EXPORT QWABC : public QObject, public QWObject
{
    Q_OBJECT
    QW_DECLARE_PRIVATE(QWABC)
public:
    inline wlr_ABC *handle() const {
        return QWObject::handle<wlr_ABC>();
    }

    static QWABC *get(wlr_ABC *handle);
    static QWABC *from(wlr_ABC *handle);

Q_SIGNALS:
    void beforeDestroy(QWABC *self);

private:
    QWABC(wlr_ABC *handle, bool isOwner);
};

QW_END_NAMESPACE

// Copyright (C) 2022 JiDe Zhang <zccrs@live.com>.
// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#include "qwabc.h"
#include "util/qwsignalconnector.h"

#include <QHash>

extern "C" {
#include <wlr/types/wlr_abc.h>
}

QW_BEGIN_NAMESPACE

class QWABCPrivate : public QWObjectPrivate
{
public:
    QWABCPrivate(wlr_ABC *handle, bool isOwner, QWABC *qq)
        : QWObjectPrivate(handle, isOwner, qq)
    {
        Q_ASSERT(!map.contains(handle));
        map.insert(handle, qq);
        sc.connect(&handle->events.destroy, this, &QWABCPrivate::on_destroy);
    }
    ~QWABCPrivate() {
        if (!m_handle)
            return;
        destroy();
        if (isHandleOwner)
            wlr_ABC_destroy(q_func()->handle());
    }

    inline void destroy() {
        Q_ASSERT(m_handle);
        Q_ASSERT(map.contains(m_handle));
        Q_EMIT q_func()->beforeDestroy(q_func());
        map.remove(m_handle);
        sc.invalidate();
    }

    void on_destroy(void *);

    static QHash<void*, QWABC*> map;
    QW_DECLARE_PUBLIC(QWABC)
    QWSignalConnector sc;
};
QHash<void*, QWABC*> QWABCPrivate::map;

void QWABCPrivate::on_destroy(void *)
{
    destroy();
    m_handle = nullptr;
    delete q_func();
}

QWABC::QWABC(wlr_ABC *handle, bool isOwner)
    : QObject(nullptr)
    , QWObject(*new QWABCPrivate(handle, isOwner, this))
{

}

QWABC *QWABC::get(wlr_ABC *handle)
{
    return QWABCPrivate::map.value(handle);
}

QWABC *QWABC::from(wlr_ABC *handle)
{
    if (auto o = get(handle))
        return o;
    return new QWABC(handle, false);
}

QW_END_NAMESPACE
