# -*- coding: utf-8 -*-
"sets the options of the configuration objects Config object itself"
# Copyright (C) 2012 Team tiramisu (see AUTHORS for all contributors)
#
# 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# The original `Config` design model is unproudly borrowed from
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
class _const:
    """convenient class that emulates a module
    and builds constants (that is, unique names)"""
    class ConstError(TypeError): pass

    def __setattr__(self, name, value):
        if self.__dict__.has_key(name):
            raise self.ConstError, "Can't rebind group (%s)"%name
        self.__dict__[name] = value

    def __delattr__(self, name):
        if self.__dict__.has_key(name):
            raise self.ConstError, "Can't unbind group (%s)"%name
        raise NameError, name
# ____________________________________________________________
class GroupModule(_const):
    "emulates a module to manage unique group (OptionDescription) names"
    class GroupType(str):
        """allowed normal group (OptionDescription) names
        *normal* means : groups that are not master
        """
        pass
    class DefaultGroupType(GroupType):
        """groups that are default (typically 'default')"""
        pass

    class MasterGroupType(GroupType):
        """allowed normal group (OptionDescription) names
        *master* means : groups that have the 'master' attribute set
        """
        pass
# setting.groups (emulates a module)
groups = GroupModule()

def populate_groups():
    "populates the available groups in the appropriate namespaces"
    groups.master = groups.MasterGroupType('master')
    groups.default = groups.DefaultGroupType('default')
    groups.family = groups.GroupType('family')

# names are in the module now
populate_groups()
# ____________________________________________________________
class OwnerModule(_const):
    """emulates a module to manage unique owner names.

    owners are living in `Config._cfgimpl_value_owners`
    """
    class Owner(str):
        """allowed owner names
        """
        pass
    class DefaultOwner(Owner):
        """groups that are default (typically 'default')"""
        pass
# setting.owners (emulates a module)
owners = OwnerModule()

def populate_owners():
    """populates the available owners in the appropriate namespaces

    - 'user' is the generic is the generic owner.
    - 'default' is the config owner after init time
    """
    setattr(owners, 'default', owners.DefaultOwner('default'))
    setattr(owners,'user', owners.Owner('user'))
    def add_owner(name):
        """
        :param name: the name of the new owner
        """
        setattr(owners, name, owners.Owner(name))
    setattr(owners, 'add_owner', add_owner)

# names are in the module now
populate_owners()
#____________________________________________________________
class Setting():
    "``Config()``'s configuration options"
    # properties attribute: the name of a property enables this property
    properties = ['hidden', 'disabled']
    # overrides the validations in the acces of the option values
    permissive = []
    # a mandatory option must have a value that is not None
    mandatory = True
    frozen = True
    # enables validation function for options if set
    validator = False
    # generic owner
    owner = owners.user
    # in order to freeze everything, not **only** the frozen options
    everything_frozen = False
    #____________________________________________________________
    # properties methods
    def has_properties(self):
        "has properties means the Config's properties attribute is not empty"
        return bool(len(self.properties))

    def has_property(self, propname):
        """has property propname in the Config's properties attribute
        :param property: string wich is the name of the property"""
        return propname in self.properties

    def enable_property(self, propname):
        "puts property propname in the Config's properties attribute"
        if propname not in self.properties:
            self.properties.append(propname)

    def disable_property(self, propname):
        "deletes property propname in the Config's properties attribute"
        if self.has_property(propname):
            self.properties.remove(propname)
    #____________________________________________________________
    def set_permissive(self, permissive):
        if not isinstance(permissive, list):
            raise TypeError('permissive must be a list')
        self.permissive = permissive
    #____________________________________________________________
    # complete freeze methods
    def freeze_everything(self):
        """everything is frozen, not only the option that are tagged "frozen"
        """
        self.everything_frozen = True

    def un_freeze_everything(self):
        """everything is frozen, not only the option that are tagged "frozen"
        """
        self.everything_frozen = False

    def is_frozen_for_everything(self):
        """frozen for a whole config (not only the options
        that have been set to frozen)"""
        return self.everything_frozen
    #____________________________________________________________
    def read_only(self):
        "convenience method to freeze, hidde and disable"
        self.freeze_everything()
        self.freeze() # can be usefull...
        self.disable_property('hidden')
        self.enable_property('disabled')
        self.mandatory = True
        self.validator = True

    def read_write(self):
        "convenience method to freeze, hidde and disable"
        self.un_freeze_everything()
        self.freeze()
        self.enable_property('hidden')
        self.enable_property('disabled')
        self.mandatory = False
        self.validator = False

    def non_mandatory(self):
        """mandatory at the Config level means that the Config raises an error
        if a mandatory option is found"""
        self.mandatory = False

    def mandatory(self):
        """mandatory at the Config level means that the Config raises an error
        if a mandatory option is found"""
        self.mandatory = True

    def is_mandatory(self):
        "all mandatory Options shall have a value"
        return self.mandatory

    def freeze(self):
        "cannot modify the frozen `Option`'s"
        self.frozen = True

    def unfreeze(self):
        "can modify the Options that are frozen"
        self.frozen = False

    def is_frozen(self):
        "freeze flag at Config level"
        return self.frozen

    def setowner(self, owner):
        ":param owner: sets the default value for owner at the Config level"
        if not isinstance(owner, owners.Owner):
            raise TypeError("invalid generic owner {0}".format(str(owner)))
        self.owner = owner

    def getowner(self):
        return self.owner