#!/usr/bin/env python
"""Module for calling Artist related last.fm web services API methods"""

__author__ = "Abhinav Sarkar <abhinav@abhinavsarkar.net>"
__version__ = "0.2"
__license__ = "GNU Lesser General Public License"
__package__ = "lastfm"

from lastfm.base import LastfmBase
from lastfm.mixin import mixin
from lastfm.decorators import cached_property, top_property

@mixin("crawlable", "shoutable", "sharable",
    "taggable", "searchable", "cacheable", "property_adder")
class Artist(LastfmBase):
    """A class representing an artist."""
    class Meta(object):
        properties = ["name", "similar", "top_tags"]
        fillable_properties = ["mbid", "url", "image",
            "streamable", "stats", "bio"]
        
    def init(self, api, subject = None, **kwargs):
        """
        Create an Artist object by providing all the data related to it.
        
        @param api:             an instance of L{Api}
        @type api:              L{Api}
        @param name:            the artist name
        @type name:             L{str}
        @param mbid:            MBID of the artist
        @type mbid:             L{str}
        @param url:             URL of the artist on last.fm
        @type url:              L{str}
        @param image:           the images of the artist in various sizes
        @type image:            L{dict}
        @param streamable:      flag indicating if the artist is streamable from last.fm
        @type streamable:       L{bool}
        @param stats:           the artist statistics
        @type stats:            L{Stats}
        @param similar:         artists similar to the provided artist
        @type similar:          L{list} of L{Artist}
        @param top_tags:        top tags for the artist
        @type top_tags:         L{list} of L{Tag}
        @param bio:             biography of the artist
        @type bio:              L{Wiki}
        @param subject:         the subject to which this instance belongs to
        @type subject:          L{User} OR L{Artist} OR L{Tag} OR L{Track} OR L{WeeklyChart}
        
        @raise InvalidParametersError: If an instance of L{Api} is not provided as the first
                                       parameter then an Exception is raised.
        """
        if not isinstance(api, Api):
            raise InvalidParametersError("api reference must be supplied as an argument")
        
        self._api = api
        super(Artist, self).init(**kwargs)
        self._stats = hasattr(self, "_stats") and Stats(
            subject = self,
            listeners = self._stats.listeners,
            playcount = self._stats.playcount,
            weight = self._stats.weight,
            match = self._stats.match,
            rank = self._stats.rank
        ) or None
        self._bio = hasattr(self, "_bio") and Wiki(
            subject = self,
            published = self._bio.published,
            summary = self._bio.summary,
            content = self._bio.content
        ) or None
        self._subject = subject

    def get_similar(self, limit = None):
        """
        Get the artists similar to this artist.
        
        @param limit: the number of artists returned (optional)
        @type limit:  L{int}
        
        @return:      artists similar to this artist
        @rtype:       L{list} of L{Artist}
        """
        params = self._default_params({'method': 'artist.getSimilar'})
        if limit is not None:
            params.update({'limit': limit})
        data = self._api._fetch_data(params).find('similarartists')
        self._similar = [
                          Artist(
                                 self._api,
                                 subject = self,
                                 name = a.findtext('name'),
                                 mbid = a.findtext('mbid'),
                                 stats = Stats(
                                               subject = a.findtext('name'),
                                               match = float(a.findtext('match')),
                                               ),
                                 url = 'http://' + a.findtext('url'),
                                 image = {'large': a.findtext('image')}
                                 )
                          for a in data.findall('artist')
                          ]
        return self._similar[:]

    @property
    def similar(self):
        """
        artists similar to this artist
        @rtype: L{list} of L{Artist}
        """
        if not hasattr(self, "_similar") or self._similar is None or len(self._similar) < 6:
            return self.get_similar()
        return self._similar[:]

    @top_property("similar")
    def most_similar(self):
        """
        artist most similar to this artist
        @rtype: L{Artist}
        """
        pass

    @property
    def top_tags(self):
        """
        top tags for the artist
        @rtype: L{list} of L{Tag}
        """
        if not hasattr(self, "_top_tags") or self._top_tags is None or len(self._top_tags) < 6:
            params = self._default_params({'method': 'artist.getTopTags'})
            data = self._api._fetch_data(params).find('toptags')
            self._top_tags = [
                              Tag(
                                  self._api,
                                  subject = self,
                                  name = t.findtext('name'),
                                  url = t.findtext('url')
                                  )
                              for t in data.findall('tag')
                              ]
        return self._top_tags[:]

    @top_property("top_tags")
    def top_tag(self):
        """
        top tag for the artist
        @rtype: L{Tag}
        """
        pass

    @cached_property
    def events(self):
        """
        events for the artist
        @rtype: L{lazylist} of L{Event}
        """
        params = self._default_params({'method': 'artist.getEvents'})
        data = self._api._fetch_data(params).find('events')

        return [
                Event.create_from_data(self._api, e)
                for e in data
.findall('event')
                ]

    @cached_property
    def top_albums(self):
        """
        top albums of th
e artist
        @rtype: L{list} of L{Album}
        """
        params = self._default_params({'method': 'artist.getTopAlbums'})
        data = self._api._fetch_data(params).find('topalbums')

        return [
                Album(
                     self._api,
                     subject = self,
                     name = a.findtext('name'),
                     artist = self,
                     mbid = a.findtext('mbid'),
                     url = a.findtext('url'),
                     image = dict([(i.get('size'), i.text) for i in a.findall('image')]),
                     stats = Stats(
                                   subject = a.findtext('name'),
                                   playcount = int(a.findtext('playcount')),
                                   rank = int(a.attrib['rank'])
                                   )
                     )
                for a in data.findall('album')
                ]

    @top_property("top_albums")
    def top_album(self):
        """
        top album of the artist
        @rtype: L{Album}
        """
        pass

    @cached_property
    def top_fans(self):
        """
        top fans of the artist
        @rtype: L{list} of L{User}
        """
        params = self._default_params({'method': 'artist.getTopFans'})
        data = self._api._fetch_data(params).find('topfans')
        return [
                User(
                     self._api,
                     subject = self,
                     name = u.findtext('name'),
                     url = u.findtext('url'),
                     image = dict([(i.get('size'), i.text) for i in u.findall('image')]),
        