"""
$URL: svn+ssh://svn.mems-exchange.org/repos/trunk/dulcinea/lib/property/property_list.py $
$Id: property_list.py 30312 2007-11-27 11:26:59Z dbinger $
"""
from dulcinea.base import DulcineaPersistent
from dulcinea.property.property import Property
from dulcinea.property.property_template import PropertyTemplate
from qp.lib.spec import either, require, Mixin, add_getters_and_setters
from qp.lib.spec import specify, string_classes


class PropertyList (DulcineaPersistent):

    list_is = [either(Property, PropertyTemplate)]

    def __init__(self, values=None):
        self.list = []
        if values:
            for value in values:
                self.add(value)

    def __copy__(self):
        result = self.__class__()
        result.list = self.list[:]
        return result

    def __eq__(self, other):
        require(other, PropertyList)
        if len(self) != len(other):
            return False
        def as_dict(property_list):
            return dict((p.get_name(), p) for p in property_list)
        return as_dict(self) == as_dict(other)

    def __str__(self):
        return "PropertyList(%s)" % self.list

    def __len__(self):
        return len(self.list)

    def __getitem__(self, index):
        return self.list[index]

    def __add__(self, other):
        return PropertyList(list(self) + list(other))

    def get_names(self):
        """() -> [string]

        Return the list of all names in the list.
        """
        return [property.get_name() for property in self]

    def find(self, name):
        """(name : string) -> any

        Searches the list for a value with name 'name'.  Returns the
        matching value, or None if it couldn't find one.
        """
        for property in self.list:
            if name == property.get_name():
                return property
        require(name, either(*string_classes))
        return None

    def add(self, property):
        """(property : Property|PropertyTemplate)

        Raises ValueError if this list already has a value with the same name.
        """
        require(property, either(Property, PropertyTemplate))
        if self.find(property.get_name()) is not None:
            raise ValueError(
                "list already has a value named %r" % property.get_name())
        self._p_note_change()
        self.list.append(property)

    def __iter__(self):
        for item in self.list:
            yield item

    def get_value_properties(self):
        """Return a new PropertyList containing all properties from the
        current list that have values.
        """
        return PropertyList([property for property in self
            if isinstance(property, Property)])


    def get_templates(self):
        """Return a new PropertyList containing all properties from the
        current list that don't have values.
        """
        return PropertyList([property for property in self
            if isinstance(property, PropertyTemplate)])

    def get_visible(self):
        return PropertyList([property for property in self
            if not property.is_hidden()])


class Propertied (Mixin):

    properties_is = PropertyList

    def __init__(self):
        self.properties = PropertyList()

    def set_properties(self, properties):
        specify(self, properties=PropertyList(properties))

    def find_property(self, name):
        return self.properties.find(name)

    def get_value_properties(self):
        return self.properties.get_value_properties()

    def get_input_templates(self):
        return self.properties.get_templates()

    def find_value_property(self, name):
        for property in self.properties:
            if property.get_name() == name:
                if property.is_input():
                    return None
                else:
                    return property
        return None

    def get_property_value(self, name, default=None):
        p = self.find_value_property(name)
        if p is None or p.value is None:
            return default
        else:
            return p.value

add_getters_and_setters(Propertied)

