#!/usr/bin/env python
#
# Copyright 2011 Jonathan LeBlanc
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import re
import urllib
import urllib2

'''
' Class: Błąd subskrypcji
' Description: Niestandardowa klasa błędu dla wyjątków subskrypcji
'''
class SubscribeError(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)

'''
' Class: Subskrybent
' Description: Umożliwia dodawanie/usuwanie subskrypcji kanałów huba
'''
class Subscriber:
    regex_url = re.compile('^https?://')    # prosty mechanizm weryfikacji adresu URL
    
    # Konstruktor zapisujący adresy URL huba i wywołań zwrotnych dla danego subskrybenta
    def __init__(self, hub, callback):
        if self.regex_url.match(hub): self.hub = hub
        else: raise SubscribeError('Nieprawidłowy adres URL huba')
        
        if self.regex_url.match(callback): self.callback = callback
        else: raise SubscribeError('Nieprawidłowy adres URL wywołania zwrotnego')
    
    # Wysyła żądanie dodania subskrypcji kanału
    def subscribe(self, feed):
        return self.change_subscription('subscribe', feed)
    
    # Wysyła żądanie usunięcia subskrypcji kanału
    def unsubscribe(self, feed):
        return self.change_subscription('unsubscribe', feed)
    
    # Wysyła żądanie usunięcia subskrypcji kanału
    def change_subscription(self, mode, feed):
        # Sprawdza, czy przekazany adres URL kanału jest prawidłowy
        if self.regex_url.match(feed): 
            # Ustawia łańcuch żądania POST dodania lub usunięcia subskrypcji
            post_string = 'hub.mode=%s&hub.callback=%s&hub.verify=async&hub.topic=%s' % (mode, self.callback, urllib.quote(feed))
            
            try:
                # wysyła żądanie do huba
                file = urllib2.urlopen(self.hub, post_string)
                return True
            except (IOError, urllib2.HTTPError), e:
                # przetwarza prawidłowe odpowiedzi HTTP (z przedziału 2xx)
                if hasattr(e, 'code') and str(e.code)[0] == '2':
                    return True
                
                # przetwarza kody błędów
                error = ''
                if hasattr(e, 'read'):
                    error = e.read()
                raise SubscribeError('%s, Odpowiedź: "%s"' % (e, error))
        else:
            raise SubscribeError('Nieprawidłowy adres URL kanału')