/* ============================================================
 *
 * This file is a part of digiKam project
 * https://www.digikam.org
 *
 * Date        : 2023-05-15
 * Description : geolocation engine based on Marble.
 *               (c) 2007-2022 Marble Team
 *               https://invent.kde.org/education/marble/-/raw/master/data/credits_authors.html
 *
 * SPDX-FileCopyrightText: 2023-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 *
 * ============================================================ */

#include "GeoSceneSettings.h"

// Local includes

#include "GeoSceneProperty.h"
#include "GeoSceneGroup.h"
#include "GeoSceneTypes.h"
#include "digikam_debug.h"

namespace Marble
{

class Q_DECL_HIDDEN GeoSceneSettingsPrivate
{
public:

    ~GeoSceneSettingsPrivate()
    {
        qDeleteAll(m_properties);
        qDeleteAll(m_groups);
    }

public:

    /// The hash table holding all the properties in the settings.

    QVector<GeoSceneProperty*>  m_properties;
    QVector<GeoSceneGroup*>     m_groups;
};


GeoSceneSettings::GeoSceneSettings()
    : d(new GeoSceneSettingsPrivate)
{
}

GeoSceneSettings::~GeoSceneSettings()
{
    delete d;
}

const char* GeoSceneSettings::nodeType() const
{
    return GeoSceneTypes::GeoSceneSettingsType;
}

bool GeoSceneSettings::propertyAvailable(const QString& name, bool& available) const
{
    QVector<GeoSceneProperty*>::const_iterator it      = d->m_properties.constBegin();
    QVector<GeoSceneProperty*>::const_iterator propEnd = d->m_properties.constEnd();

    for ( ; it != propEnd ; ++it)
    {
        if ((*it)->name() == name)
        {
            available = (*it)->available();

            return true;
        }
    }

    QVector<GeoSceneGroup*>::const_iterator itGroup  = d->m_groups.constBegin();
    QVector<GeoSceneGroup*>::const_iterator groupEnd = d->m_groups.constEnd();

    for ( ; itGroup != groupEnd ; ++itGroup)
    {
        bool success = (*itGroup)->propertyAvailable(name, available);

        if (success)
        {
            return true;
        }
    }

    available = false;

    return false;
}

bool GeoSceneSettings::setPropertyValue(const QString& name, bool value)
{
    qCDebug(DIGIKAM_MARBLE_LOG) << "GeoSceneSettings: Property " << name << "to" << value;

    QVector<GeoSceneProperty*>::const_iterator it      = d->m_properties.constBegin();
    QVector<GeoSceneProperty*>::const_iterator propEnd = d->m_properties.constEnd();

    for ( ; it != propEnd ; ++it)
    {
        if ((*it)->name() == name)
        {
            (*it)->setValue(value);

            return true;
        }
    }

    QVector<GeoSceneGroup*>::const_iterator itGroup  = d->m_groups.constBegin();
    QVector<GeoSceneGroup*>::const_iterator groupEnd = d->m_groups.constEnd();

    for ( ; itGroup != groupEnd ; ++itGroup)
    {
        bool success = (*itGroup)->setPropertyValue(name, value);

        if (success)
        {
            return true;
        }
    }

    return false;
}

bool GeoSceneSettings::propertyValue(const QString& name, bool& value) const
{
    QVector<GeoSceneProperty*>::const_iterator it      = d->m_properties.constBegin();
    QVector<GeoSceneProperty*>::const_iterator propEnd = d->m_properties.constEnd();

    for ( ; it != propEnd ; ++it)
    {
        if ((*it)->name() == name)
        {
            value = (*it)->value();

            return true;
        }
    }

    QVector<GeoSceneGroup*>::const_iterator itGroup  = d->m_groups.constBegin();
    QVector<GeoSceneGroup*>::const_iterator groupEnd = d->m_groups.constEnd();

    for ( ; itGroup != groupEnd ; ++itGroup)
    {
        bool success = (*itGroup)->propertyValue(name, value);

        if (success)
        {
            return true;
        }
    }

    value = false;

    return false;
}

QVector<GeoSceneProperty*> GeoSceneSettings::allProperties()
{
    QVector<GeoSceneProperty*> allProperties;

    QVector<GeoSceneGroup*>::const_iterator itGroup  = d->m_groups.constBegin();
    QVector<GeoSceneGroup*>::const_iterator groupEnd = d->m_groups.constEnd();

    for ( ; itGroup != groupEnd ; ++itGroup)
    {
        allProperties << (*itGroup)->properties();
    }

    allProperties << d->m_properties;

    return allProperties;
}

QVector<const GeoSceneProperty*> GeoSceneSettings::allProperties() const
{
    QVector<const GeoSceneProperty*> allProperties;

    QVector<GeoSceneGroup*>::const_iterator itGroup  = d->m_groups.constBegin();
    QVector<GeoSceneGroup*>::const_iterator groupEnd = d->m_groups.constEnd();

    for ( ; itGroup != groupEnd ; ++itGroup)
    {
        allProperties << const_cast<const GeoSceneGroup*>(*itGroup)->properties();
    }

    allProperties.reserve(allProperties.size() + d->m_properties.size());

    for (const GeoSceneProperty* property : d->m_properties)
    {
        allProperties << property;
    }

    return allProperties;
}

void GeoSceneSettings::addGroup(GeoSceneGroup* group)
{
    // Remove any property that has the same name

    QVector<GeoSceneGroup*>::iterator it = d->m_groups.begin();

    while (it != d->m_groups.end())
    {
        GeoSceneGroup* currentGroup = *it;

        if (currentGroup->name() == group->name())
        {
            delete currentGroup;
            d->m_groups.erase(it);

            break;
        }

        else
        {
            ++it;
        }
    }

    if (group)
    {
        d->m_groups.append(group);

        // Establish connection to the outside, e.g. the LegendBrowser

        connect(group, SIGNAL(valueChanged(QString,bool)),
                SIGNAL(valueChanged(QString,bool)));
    }
}

const GeoSceneGroup* GeoSceneSettings::group(const QString& name) const
{
    GeoSceneGroup* group = nullptr;

    QVector<GeoSceneGroup*>::const_iterator it       = d->m_groups.constBegin();
    QVector<GeoSceneGroup*>::const_iterator groupEnd = d->m_groups.constEnd();

    for ( ; it != groupEnd ; ++it)
    {
        if ((*it)->name() == name)
        {
            group = *it;

            break;
        }
    }

    return group;
}

// implement non-const method by means of const method,
// for details, see "Effective C++" (third edition)

GeoSceneGroup* GeoSceneSettings::group(const QString& name)
{
    return const_cast<GeoSceneGroup*>(static_cast<GeoSceneSettings const*>(this)->group(name));
}

void GeoSceneSettings::addProperty(GeoSceneProperty* property)
{
    // Remove any property that has the same name

    QVector<GeoSceneProperty*>::iterator it = d->m_properties.begin();

    while (it != d->m_properties.end())
    {
        GeoSceneProperty* currentProperty = *it;

        if (currentProperty->name() == property->name())
        {
            delete currentProperty;
            d->m_properties.erase(it);

            break;
        }

        else
        {
            ++it;
        }
    }

    if (property)
    {
        d->m_properties.append(property);

        // Establish connection to the outside, e.g. the LegendBrowser

        connect(property, SIGNAL(valueChanged(QString,bool)),
                SIGNAL(valueChanged(QString,bool)));

        Q_EMIT valueChanged(property->name(), property->value());
    }
}

const GeoSceneProperty* GeoSceneSettings::property(const QString& name) const
{
    GeoSceneProperty* property = nullptr;

    QVector<GeoSceneProperty*>::const_iterator it      = d->m_properties.constBegin();
    QVector<GeoSceneProperty*>::const_iterator propEnd = d->m_properties.constEnd();

    for ( ; it != propEnd ; ++it)
    {
        if ((*it)->name() == name)
        {
            property = *it;

            break;
        }
    }

    return property;
}

// implement non-const method by means of const method,
// for details, see "Effective C++" (third edition)

GeoSceneProperty* GeoSceneSettings::property(const QString& name)
{
    return const_cast<GeoSceneProperty*>(static_cast<GeoSceneSettings const*>(this)->property(name));
}

QVector<GeoSceneProperty*> GeoSceneSettings::rootProperties()
{
    return d->m_properties;
}

} // namespace Marble

#include "moc_GeoSceneSettings.cpp"
