# -*- coding: ascii -*-

###########################################################################
# clive, video extraction utility
# Copyright (C) 2007-2008 Toni Gundogdu
#
# This file is part of clive.
#
# clive 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 3 of the License, or
# (at your option) any later version.
#
# clive 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 clive.  If not, see <http://www.gnu.org/licenses/>.
###########################################################################

## The classes for parsing rss/atom feeds

__all__ = ['FeedParser']

from clive.unicode import tostr
from clive.modules import Modules
from clive.opts import Options

## The feed parsing class
class FeedParser:

    ## Constructor
    def __init__(self, say, proxy):
        self._opts = Options()._opts
        self._say = say
        self._proxy = proxy
        self._fparser = Modules().getinst('feedparser')

    ## Reap feeds and display selection lists
    def parse(self, raw_urls):
        self._fparser.USER_AGENT = self._opts.http_agent
        urllib2 = Modules().getinst('urllib2')
        h = urllib2.ProxyHandler(self._proxy)
        # Reap URLs
        feeds = []
        for url in raw_urls:
            self._say('feed: %s' % url)
            d = self._fparser.parse(url, handlers=[h])
            if not hasattr(d.feed, 'title'):
                self._say('error: invalid rss/atom feed')
            elif not hasattr(d, 'entries'):
                self._say('error: no rss/atom feed entries found')
            else:
                feeds.append(d)
        # Display feeds and return user selection (video URLs)
        if len(feeds) == 0:
            raise SystemExit('error: no data: check feed url(s)')
        if self._opts.enable_confirm:            
            u = DisplayFeeds(feeds, self._opts)
            return u.get_selection()
        else: # Skip selection and use the whole list
            sel = []
            for d in feeds:
                for e in d.entries:
                    sel.append(e.link)
            return sel                    

## The class that displays the feeds with found video URLs
class DisplayFeeds:

    ## Constructor
    def __init__(self, feeds, opts):
        self._newt = Modules().getinst('newt')
        self._last = None # Selection before hitting "Resize"
        self._feeds = feeds
        self._opts = opts
        while 1:
            self._selection = self._main()
            if self._selection: break

    ## Returns the user selection of videos to be extracted
    def get_selection(self):
        return self._selection

    def _main(self):
        sel = []
        try:
            scr = self._newt.SnackScreen()
            sel = self._show_feeds(scr)
        finally:
            scr.finish()
        return sel

    def _ok(self):
        return self._ct.getSelection()

    def _cancel(self):
        raise SystemExit('Cancelled.')

    def _resize(self):
        self._last = self._ct.getSelection()
        return None

    def _show_feeds(self, scr):
        w = scr.width - (scr.width/6)
        ww = w-12
        ct = self._newt.CheckboxTree(scr.height/2, scroll=1)
        for (i,d) in enumerate(self._feeds):
            t = d.feed.title[:w]
            t += (' (%d)' % len(d.entries))
            try:
                t = tostr(t)
            except UnicodeDecodeError, err:
                continue # Skip item if decoding fails for some reason
            ct.append(t)
            for e in d.entries:
                try:
                    t = tostr(e.title[:ww])
                except UnicodeDecodeError, err:
                    continue # Skip item if decoding fails for some reason
                sel = False
                if self._last and e.link in self._last:
                    sel = True
                ct.addItem(t, (i, self._newt.snackArgs['append']),
                    e.link, selected=sel)
        g = self._newt.GridForm(scr, 'RSS/Atom Feeds: Videos found', 1,2)
        g.add(ct, col=0, row=0, padding=(0,0,0,1))
        b = self._newt.ButtonBar(scr,
            [('Resize',2),('Cancel',0), ('Extract',1)], compact=0)
        g.add(b, col=0, row=1, padding=(0,0,0,0))
        self._ct = ct
        d = {0:self._cancel, 1:self._ok, 2:self._resize, None:self._ok}
        return d.get(b.buttonPressed(g.runOnce()))()
