"""
Feed discovery.
"""


from adjunct import discovery


__all__ = (
    'FeedExtractor',
)


# pylint: disable-msg=R0904
class FeedExtractor(discovery.LinkExtractor):
    """
    Extract any link or anchor elements that look like they might refer to
    feeds.
    """

    ACCEPTABLE = (
        'application/atom+xml',
        'application/rdf+xml',
        'application/rss+xml',
    )

    GUESSES = {
        'application/rss+xml': ('.rss', 'rss.xml', '/rss', '/rss/', '/feed/'),
        'application/rdf+xml': ('.rdf', 'rdf.xml', '/rdf', '/rdf/'),
        'application/atom+xml': ('.atom', 'atom.xml', '/atom', '/atom/'),
    }

    def __init__(self, base):
        discovery.LinkExtractor.__init__(self, base)
        self.anchor = None
        self.added = set()

    def handle_starttag(self, tag, attrs):
        if tag.lower() == 'a' and self.anchor is None:
            attrs = discovery.fix_attributes(attrs)
            if 'href' in attrs:
                attrs['@data'] = ''
                attrs.setdefault('type', self.guess_feed_type(attrs['href']))
                if attrs['type'] in self.ACCEPTABLE:
                    attrs.setdefault('rel', 'feed')
                    self.anchor = attrs
        else:
            discovery.LinkExtractor.handle_starttag(self, tag, attrs)

    def handle_data(self, data):
        # We only use the interstitial text as the title if none was provided
        # on the anchor element itself.
        if self.anchor is not None and 'title' not in self.anchor:
            self.anchor['@data'] += data

    def handle_endtag(self, tag):
        if tag.lower() == 'a' and self.anchor is not None:
            self.anchor.setdefault('title', self.anchor['@data'])
            del self.anchor['@data']
            self.append(self.anchor)
            self.anchor = None
        else:
            discovery.LinkExtractor.handle_endtag(self, tag)
            # Force scanning of the whole document.
            self.finished = False

    def guess_feed_type(self, href):
        """
        Guess the MIME type of a link based off of its ending.
        """
        # Reasonable assumption: we're dealing with <a> elements, and by this
        # time, we should've encountered any <base> elements we care about.
        href = self.fix_href(href)
        for mimetype, endings in self.GUESSES.iteritems():
            if href.lower().endswith(endings):
                return mimetype
        return None

    def append(self, attrs):
        if attrs['rel'] in ('alternate', 'feed'):
            if 'type' in attrs and attrs['type'].lower() in self.ACCEPTABLE:
                if 'href' in attrs and attrs['href'] not in self.added:
                    discovery.LinkExtractor.append(self, attrs)
                    self.added.add(attrs['href'])

@@ -94,187 +94,52 @@
 %0A%0A# 
-pylint: disable-msg=R0904%0Aclass FeedExtractor(discovery.LinkExtractor):%0A    %22%22%22%0A    Extract any link or anchor elements that look like they might refer to%0A    feeds.%0A    %22%22%22%0A%0A    
+Acceptable feed  types, sorted by priority.%0A
 ACCE
@@ -149,20 +149,16 @@
 BLE = (%0A
-    
     'app
@@ -173,28 +173,24 @@
 /atom+xml',%0A
-    
     'applica
@@ -204,28 +204,24 @@
 f+xml',%0A    
-   
- 
 'application
@@ -235,19 +235,128 @@
 l',%0A
-    )%0A%0A    
+)%0A%0A# Used when ordering feeds.%0AORDER = dict(%0A    (mimetype, i_type)%0A    for i_type, mimetype in enumerate(ACCEPTABLE))%0A%0A
 GUES
@@ -363,20 +363,16 @@
 SES = %7B%0A
-    
     'app
@@ -434,28 +434,24 @@
  '/feed/'),%0A
-    
     'applica
@@ -503,20 +503,16 @@
 rdf/'),%0A
-    
     'app
@@ -577,13 +577,187 @@
 '),%0A
-    %7D
+%7D%0A%0A%0A# pylint: disable-msg=R0904%0Aclass FeedExtractor(discovery.LinkExtractor):%0A    %22%22%22%0A    Extract any link or anchor elements that look like they might refer to%0A    feeds.%0A    %22%22%22
 %0A%0A  
@@ -1220,29 +1220,24 @@
 %5B'type'%5D in 
-self.
 ACCEPTABLE:%0A
@@ -2445,21 +2445,16 @@
 ings in 
-self.
 GUESSES.
@@ -2705,21 +2705,16 @@
 er() in 
-self.
 ACCEPTAB
@@ -2789,16 +2789,53 @@
 .added:%0A
+                    del attrs%5B'rel'%5D%0A
         

Move constants up to module level.