#####################################################################
#                                                                   #
# qsettings_wrapper.py                                              #
#                                                                   #
# Copyright 2013, Christopher Billington, Philip Starkey            #
#                                                                   #
# This file is part of the qtutils project                          #
# (see https://github.com/philipstarkey/qtutils )                   #
# and is licensed under the 2-clause, or 3-clause, BSD License.     #
# See the license.txt file in the root of the project               #
# for the full license.                                             #
#                                                                   #
#####################################################################

from qtutils.qt.QtCore import QSettings

import ast

from qtutils import inmain_decorator


class type_with_properties(type):
    """A metaclass to create properties for a class based on the contents
    of its a class _fields. _fields should be a list of strings. At
    class creation, property getters and setters will be created,
    hooking each name up to _get and _set class methods."""
    def __init__(cls, name, superclasses, attrs):
        type.__init__(cls, name, superclasses, attrs)
        for name in cls._fields:
            method = property(lambda self, name=name: cls._get(self, name),
                              lambda self, value, name=name: cls._set(self, name, value))
            setattr(cls, name, method)


class QSettingsWrapper(object):
    """A class that wraps QSettings to provide automatic type conversion
    and reduce the need for boilerplace code"""
    __metaclass__ = type_with_properties
    _fields = []  # to be overridden by subclasses

    def __init__(self, companyname, appname):
        self._qsettings = QSettings(companyname, appname)
        # set default values to None:
        for name in self._fields:
            if not self._qsettings.contains(name):
                self._set(name, None)

    @inmain_decorator()
    def _get(self, name):
        valrepr = self._qsettings.value(name)
        return ast.literal_eval(valrepr)

    @inmain_decorator()
    def _set(self, name, value):
        valrepr = repr(value)
        try:
            assert value == ast.literal_eval(valrepr)
        except (ValueError, AssertionError, SyntaxError):
            raise ValueError('Value too complex to store. Can only store values for which x == ast.literal_eval(repr(x))')
        self._qsettings.setValue(name, valrepr)
        self._qsettings.sync()


if __name__ == '__main__':

    # Test and example implementation

    class TestSettings(QSettingsWrapper):
        _fields = ['test']

        def __init__(self):
            QSettingsWrapper.__init__(self, 'test', 'test')

    s = TestSettings()
    s.test = 5
    assert s.test == 5
    s.test += 2
    assert s.test == 7
