"""
***************************************************************************
    qgssettings.py
    ---------------------
    Date                 : May 2018
    Copyright            : (C) 2018 by Denis Rouzaud
    Email                : denis@opengis.ch
***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************
"""

import qgis  # required to get base class of enums
from qgis.core import QgsSettings

from .metaenum import metaEnumFromValue


def _qgssettings_enum_value(
    self, key, enumDefaultValue, section=QgsSettings.Section.NoSection
):
    """
    Return the setting value for a setting based on an enum.
    This forces the output to be a valid and existing entry of the enum.
    Hence if the setting value is incorrect, the given default value is returned.

    :param self: the QgsSettings object
    :param key: the setting key
    :param enumDefaultValue: the default value as an enum value
    :param section: optional section
    :return: the setting value

     .. note::  The enum needs to be declared with Q_ENUM.

    """

    meta_enum = metaEnumFromValue(enumDefaultValue)
    if meta_enum is None or not meta_enum.isValid():
        # this should not happen
        raise ValueError(
            f"could not get the meta enum for given enum default value (type: {enumDefaultValue.__class__})"
        )

    str_val = self.value(key, meta_enum.valueToKey(enumDefaultValue), str, section)
    # need a new meta enum as QgsSettings.value is making a copy and leads to seg fault (probably a PyQt issue)
    meta_enum_2 = metaEnumFromValue(enumDefaultValue)
    (enu_val, ok) = meta_enum_2.keyToValue(str_val)

    if not ok:
        enu_val = enumDefaultValue
    else:
        # cast to the enum class
        enu_val = enumDefaultValue.__class__(enu_val)

    return enu_val


def _qgssettings_set_enum_value(
    self, key, enumValue, section=QgsSettings.Section.NoSection
):
    """
    Save the setting value for a setting based on an enum.
    This forces the output to be a valid and existing entry of the enum.
    The entry is saved as a string.

    :param self: the QgsSettings object
    :param key: the setting key
    :param enumValue: the value to be saved
    :param section: optional section
    :return: the setting value

     .. note::  The enum needs to be declared with Q_ENUM.

    """
    meta_enum = metaEnumFromValue(enumValue)
    if meta_enum is None or not meta_enum.isValid():
        # this should not happen
        raise ValueError(
            f"could not get the meta enum for given enum default value (type: {type(enumValue)})"
        )

    self.setValue(key, meta_enum.valueToKey(enumValue), section)


def _qgssettings_flag_value(
    self, key, flagDefaultValue, section=QgsSettings.Section.NoSection
):
    """
    Return the setting value for a setting based on a flag.
    This forces the output to be a valid and existing entry of the enum.
    Hence if the setting value is incorrect, the given default value is returned.

    :param self: the QgsSettings object
    :param key: the setting key
    :param flagDefaultValue: the default value as a flag value
    :param section: optional section
    :return: the setting value
    """

    default_value_str = "|".join(
        [e.name for e in flagDefaultValue.__class__ if flagDefaultValue & e]
    )
    str_val = self.value(key, default_value_str, str, section)

    flag_val = flagDefaultValue.__class__(0)
    for part in str_val.split("|"):
        try:
            flag_val |= getattr(flagDefaultValue.__class__, part)
        except AttributeError:
            return flagDefaultValue

    return flag_val
