"""
"""
from __future__ import unicode_literals

from restinmagento.backend import BackEndRegistry
from restinmagento.collectionmanager import CollectionManager, ImageCollectionManager


class ModelException(Exception):
    pass

class classproperty(object):

    def __init__(self, fget):
        self.fget = fget

    def __get__(self, owner_self, owner_cls):
        return self.fget(owner_cls)


class Model(object):
    """Base class of every magento objects: products, inventory...
    A Model objects provides ORM like functionnality.

    
    Once initialized a model objects behave just like any regular python object.
    For example changing the name of a model object is done the following way:

    .. code-block:: python
            :linenos:

            mymodel.name = 'newname'
           



    .. py:attribute:: pk

        Read only attribute. Primary key of the object.
    """

    special_attrs = ('transient', 'pk', 'updated_data', 'data')

    def __init__(self, data=dict(), **kwargs):
        """Constructs a Model object with the data contained in data.

        When you initialize a Model with this method, the object is transient. 
        That means it has never been saved to any backend. It has no primary key.

        :param data: the data of your model.
        :type data: a dictionnary
        """
        self.data = data
        self.updated_data = dict()
        self.transient = True
        for attr_name, attr_value in kwargs.items():
            setattr(self, attr_name, attr_value)

    def __getattr__(self, attr):
        if attr in self.updated_data:
            return self.updated_data[attr]
        if attr in self.data:
            return self.data[attr]
        raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__,
                attr))

    def __setattr__(self, name, value):
        if name in self.special_attrs:
             return object.__setattr__(self, name, value)
        if name in self.data:
            self.updated_data[name] = value   
        else:
            object.__setattr__(self, name, value)                

    @classmethod
    def objs(cls, **kwargs):
        return CollectionManager(path=cls.cm_path, inst_cls=cls, **kwargs)

    @classproperty
    def objects(cls):
        """Class property that returns a CollectionManager
        """
        return cls.objs()

    @property
    def path(self):
        """Read only property that give the relative path where this resource lives
        in the Magento server.
        """
        return self.cm_path + '/%s' % self.pk

    def delete(self):
        """Delete the object from the backend.
        """
        if self.transient == False:
            backend = BackEndRegistry().get_default_backend()
            backend.delete(self.path)

    def reload(self):
        """Reload the model from the backend.
        """
        if self.transient:
            raise ModelException("Only a non transient object can be reloaded")
        backend = BackEndRegistry().get_default_backend()
        obj_dict = backend.get(self.path)
        self.data = obj_dict

    def save(self, reload=True):
        """Save the object to the backend.
        Save is a creation if the object does not exist in the backend.
        Save is an update if the object is known by the backend.

        :param reload: if True performs an automatic reload just after saving.

        This is usefull in case of an oject creation to obtain every default values 
        generated by the backend of non mandatory attributes.
        """
        backend = BackEndRegistry().get_default_backend()
        if self.transient == True:
            self._create()
            self.transient = False
        else:
            data_dict = self._get_dirty_attrs()
            backend.put(self.path, data_dict)
        if reload:
            self.reload()

    def persist(self):
        self.transient = False
        self.pk = self.data[self.id_attr]

    def _create(self):
        """Store the model in the magento backend.
        The model is supposed to be in the transient state.
        """
        backend = BackEndRegistry().get_default_backend()
        path = backend.create(self.cm_path, self.data)
        self.pk = path.split('/')[-1]
        

    def _get_dirty_attrs(self):
        result = dict()
        for key, value in self.updated_data.items():
            value = str(value)
            if value != self.data[key]:
                result[key] = value
        return result
        

class Product(Model):

    cm_path = '/products'
    id_attr = 'entity_id'

    @property
    def websites_path(self):
        return self.path + '/websites'

    @property
    def categories_path(self):
        return self.path + '/categories'


    @property
    def images(self):
        return ImageCollectionManager(product_id=self.pk, inst_cls=Image)


    def get_websites(self):
        backend = getattr(BackEndRegistry(), 'default')
        weblist = backend.get(self.websites_path)
        return [res_dict['website_id'] for res_dict in weblist]

    def set_websites(self, websites_ids):
        backend = getattr(BackEndRegistry(), 'default')
        data = [dict(website_id=eyed) for eyed in websites_ids]
        weblist = backend.post(self.websites_path, data=data)

    def get_categories(self):
        backend = getattr(BackEndRegistry(), 'default')
        res = backend.get(self.categories_path)
        return [res_dict['category_id'] for res_dict in res]

    def set_categories(self, category_id):
        backend = getattr(BackEndRegistry(), 'default')
        data = dict(category_id=category_id)
        backend.post(self.categories_path, data=data)
        

class StockItem(Model):

    cm_path = '/stockitems'
    id_attr = 'item_id'


class Order(Model):

    cm_path = '/orders'
    id_attr = 'entity_id'

    @property
    def addresses(self):
        """Return the billing and shipping addresses.
        See http://www.magentocommerce.com/api/rest/Resources/Orders/order_addresses.html
        """
        backend = BackEndRegistry().get_default_backend()
        url = self.path + '/adresses'
        return backend.get(url)

    @property
    def billing_addresses(self):
        """Return the billing addresses.
        See http://www.magentocommerce.com/api/rest/Resources/Orders/order_addresses.html
        """
        backend = BackEndRegistry().get_default_backend()
        url = self.path + '/adresses/billing'
        return backend.get(url)

    @property
    def shipping_addresses(self):
        """Return the shipping addresses.
        See http://www.magentocommerce.com/api/rest/Resources/Orders/order_addresses.html
        """
        backend = BackEndRegistry().get_default_backend()
        url = self.path + '/adresses/shipping'
        return backend.get(url)

    @property
    def comments(self):
        """Return the comments.
        See http://www.magentocommerce.com/api/rest/Resources/Orders/order_comments.html
        """
        backend = BackEndRegistry().get_default_backend()
        url = self.path + '/comments'
        return backend.get(url)


    @property
    def items(self):
        """Return the items.
        See http://www.magentocommerce.com/api/rest/Resources/Orders/order_items.html
        """
        backend = BackEndRegistry().get_default_backend()
        url = self.path + '/items'
        return backend.get(url)



class Customer(Model):

    cm_path = '/customers'
    id_attr = 'entity_id'


class Image(Model):

    special_attrs = ('transient', 'pk', 'updated_data', 'data', 'product_id')
    id_attr = 'id'

    def __init__(self, product_id, data=dict(), **kwargs):
        self.product_id = product_id
        super(Image, self).__init__(data, **kwargs)
        
    @property
    def cm_path(self):
        return "/products/%s/images" % self.product_id

    @classmethod
    def objects(cls, product_id):
        return ImageCollectionManager(product_id=product_id, inst_cls=cls)



 