/*
    SPDX-FileCopyrightText: 2008 Torsten Rahn <rahn@kde.org>

    SPDX-License-Identifier: LGPL-2.0-or-later
*/

#include "GeoSceneSettings.h"

#include "MarbleDebug.h"

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

namespace Marble
{

class GeoSceneSettingsPrivate
{
public:
    ~GeoSceneSettingsPrivate()
    {
        qDeleteAll(m_properties);
        qDeleteAll(m_groups);
    }

    /// The hash table holding all the properties in the settings.
    QList<GeoSceneProperty *> m_properties;
    QList<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
{
    QList<GeoSceneProperty *>::const_iterator it = d->m_properties.constBegin();
    QList<GeoSceneProperty *>::const_iterator propEnd = d->m_properties.constEnd();
    for (; it != propEnd; ++it) {
        if ((*it)->name() == name) {
            available = (*it)->available();
            return true;
        }
    }

    QList<GeoSceneGroup *>::const_iterator itGroup = d->m_groups.constBegin();
    QList<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)
{
    mDebug() << name << "to" << value;

    QList<GeoSceneProperty *>::const_iterator it = d->m_properties.constBegin();
    QList<GeoSceneProperty *>::const_iterator propEnd = d->m_properties.constEnd();
    for (; it != propEnd; ++it) {
        if ((*it)->name() == name) {
            (*it)->setValue(value);
            return true;
        }
    }

    QList<GeoSceneGroup *>::const_iterator itGroup = d->m_groups.constBegin();
    QList<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
{
    QList<GeoSceneProperty *>::const_iterator it = d->m_properties.constBegin();
    QList<GeoSceneProperty *>::const_iterator propEnd = d->m_properties.constEnd();
    for (; it != propEnd; ++it) {
        if ((*it)->name() == name) {
            value = (*it)->value();
            return true;
        }
    }

    QList<GeoSceneGroup *>::const_iterator itGroup = d->m_groups.constBegin();
    QList<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;
}

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

    QList<GeoSceneGroup *>::const_iterator itGroup = d->m_groups.constBegin();
    QList<GeoSceneGroup *>::const_iterator groupEnd = d->m_groups.constEnd();
    for (; itGroup != groupEnd; ++itGroup) {
        allProperties << (*itGroup)->properties();
    }

    allProperties << d->m_properties;

    return allProperties;
}

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

    QList<GeoSceneGroup *>::const_iterator itGroup = d->m_groups.constBegin();
    QList<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
    QList<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;

    QList<GeoSceneGroup *>::const_iterator it = d->m_groups.constBegin();
    QList<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
    QList<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;

    QList<GeoSceneProperty *>::const_iterator it = d->m_properties.constBegin();
    QList<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));
}

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

}

#include "moc_GeoSceneSettings.cpp"
