# Copyright (c) 2004 Jean-Yves Lefort
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. Neither the name of Jean-Yves Lefort nor the names of its contributors
#    may be used to endorse or promote products derived from this software
#    without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

import sys, re, ST, gobject, gtk
from ST import _

### constants #################################################################

class FIELD:
    BANNER, DESCRIPTION, HOMEPAGE = range(3)

PUNKCAST_COM_ROOT	= "http://punkcast.com/"

re_url			= re.compile('href="?(http://punkcast.com/)?([0-9]+.*?)"?>')
re_special_url		= re.compile("href=(http://209.*?)>")
re_img			= re.compile('SRC="?(http://punkcast.com/)?(.*?\.(jpg|JPG|gif|GIF|png|PNG))')
re_alt			= re.compile('ALT="(.*?)"')

### helpers ###################################################################

class struct:
    def __init__ (self, **entries):
        self.__dict__.update(entries)

def parse_error (err):
    handler.notice(_("parse error: %s") % (err))

### transfer callbacks ########################################################

def streams_line_cb (line, streams, info):
    if not hasattr(info, "aborted"):
        url = None
        match = re_url.search(line)
        if match is not None:
            url = PUNKCAST_COM_ROOT + match.group(2)
        else:
            match = re_special_url.search(line)
            if match is not None:
                url = match.group(1)

        if url is not None:
            if info.stream is not None \
               and info.stream.name != "http://punkcast.com/17/index.html" \
               and info.stream.name != "http://punkcast.com/18/index.html":
                parse_error("incomplete stream")

            info.stream = PunkcastComStream()
            info.stream.name = url
            info.stream.fields[FIELD.HOMEPAGE] = url
            streams.append(info.stream)

        match = re_img.search(line)
        if match is not None:
            if info.stream is None:
                parse_error("misplaced image")
            else:
                info.stream.image_url = PUNKCAST_COM_ROOT + match.group(2)

        match = re_alt.search(line)
        if match is not None:
            if info.stream is None:
                parse_error("misplaced alt")
            else:
                info.stream.fields[FIELD.DESCRIPTION] = ST.sgml_ref_expand(match.group(1))
                info.stream = None
                        
### stream implementation #####################################################

class PunkcastComStream (ST.Stream):
    image_url = None

### handler implementation ####################################################

class PunkcastComHandler (ST.Handler):
    def __new__ (cls):
        self = ST.Handler.__new__(cls, "punkcast.com.py")

        self.label = "punkcast.com"
        self.home = PUNKCAST_COM_ROOT
        self.flags = ST.HANDLER_NO_CATEGORIES
        self.icon = gtk.gdk.pixbuf_new_from_file(ST.find_icon("punkcast.com.png"))
        self.cached_images = {}

        self.config.register(("download-images",
                              bool,
                              None,
                              None,
                              1,
                              gobject.PARAM_READWRITE))

        self.add_field(ST.HandlerField(FIELD.BANNER,
                                       _("Show"),
                                       gtk.gdk.Pixbuf,
                                       ST.HANDLER_FIELD_VISIBLE,
                                       _("The show banner")))
        self.add_field(ST.HandlerField(FIELD.DESCRIPTION,
                                       _("Description"),
                                       str,
                                       ST.HANDLER_FIELD_VISIBLE,
                                       _("The show description")))
        self.add_field(ST.HandlerField(FIELD.HOMEPAGE,
                                       _("Homepage"),
                                       str,
                                       ST.HANDLER_FIELD_VISIBLE
                                       | ST.HANDLER_FIELD_START_HIDDEN,
                                       _("The show homepage URL")))

        return self

    def reload (self, category):
        streams = []
        session = ST.TransferSession()
        session.get_by_line(PUNKCAST_COM_ROOT,
                            flags = ST.TRANSFER_UTF8 | ST.TRANSFER_PARSE_HTTP_CHARSET | ST.TRANSFER_PARSE_HTML_CHARSET,
                            body_cb = streams_line_cb,
                            body_args = (streams, struct(stream = None)))

        for stream in streams:
            if stream.image_url is not None:
                if not self.cached_images.has_key(stream.image_url) and handler.config["download-images"]:
                    try:
                        buffer = session.get_binary(stream.image_url)
                    except ST.AbortError:
                        break
                    except:
                        handler.notice(_("unable to download image %s: %s") % (stream.image_url, sys.exc_value))
                    else:
                        try:
                            loader = gtk.gdk.PixbufLoader()
                            loader.write(buffer)
                            self.cached_images[stream.image_url] = loader.get_pixbuf()
                            loader.close()
                        except:
                            handler.notice(_("unable to load image %s: %s") % (stream.image_url, sys.exc_value))
                if self.cached_images.has_key(stream.image_url):
                    stream.fields[FIELD.BANNER] = self.cached_images[stream.image_url]
                
        return ((), streams)

    def stream_get_stock_field (self, stream, stock_field):
        if stock_field == ST.HANDLER_STOCK_FIELD_NAME:
            return stream.fields[FIELD.DESCRIPTION]
        elif stock_field == ST.HANDLER_STOCK_FIELD_HOMEPAGE:
            return stream.fields[FIELD.HOMEPAGE]

    def stream_browse (self, stream):
    	ST.action_run("view-web", stream.fields[FIELD.HOMEPAGE])

    def preferences_widget_new (self):
        check = gtk.CheckButton(_("_Download images"))
        check.set_active(self.config["download-images"])
        check.connect("toggled", self.download_images_toggled_h)
        ST.set_tooltip(check, _("If this option is enabled, the show banners will be downloaded."))
        check.show()

        return ST.HIGSection(_("Images"), check)

    def download_images_toggled_h (self, check):
        self.config["download-images"] = check.get_active()

### initialization ############################################################

def init ():
    global handler

    if not ST.check_api_version(2, 0):
        raise RuntimeError, _("API version mismatch")
    
    ST.action_register("view-web", _("Open a web page"), "epiphany %q")

    handler = PunkcastComHandler()
    ST.handlers_add(handler)

init()
