#! /usr/bin/env python
# -*- coding: utf-8 -*-
#
#       webfortune.py
#       
#       Chagelog :
#       * version 0.3.0 :
#           - Add a nice error message when the web site is unreachable
#       * version 0.2.0 :
#           - Fix the 'fortune' command detection
#       * version 0.1.0 :
#           - First release
#       
#       
#       Copyright © 2007, Florian Birée <florian@biree.name>
#       
#       This program 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.
#       
#       This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
"""Fortunes extractor from websites"""

__author__ = "Florian Birée"
__version__ = "0.3.0"
__license__ = "GPL"
__copyright__ = "Copyright © 2007, Florian Birée"
__revision__ = "$Revision: $"
__date__ = "$Date: $"

import urllib2
import re
import commands
import sys
from optparse import OptionParser

# Constants
FORTUNE_URL = "http://www.fortunes-fr.org/fortunes.php"
FORTUNE_PATTERN = re.compile(r'''
        <p\sclass="fortune"> # Start of the tag
        ((?:[^<]|<(?!/p))*)  # Content of the paragraph
        </p>                 # End of the tag
        ''', re.VERBOSE | re.DOTALL)

class InternetHasDisappear(Exception):
    """Exception raised if the internet network is unjoinable"""
    
    def __init__(self):
        """Initialize the exception"""
        Exception.__init__(self)
        self.cookie = """Internet has disappear.
        -+- %s in There is a bug in Internet -+-
        """ % commands.getoutput('hostname')
    
    def __repr__(self):
        """Representation of the exception"""
        return self.cookie

class Fortune(object):
    """Class to get a fortune"""
    
    def __init__(self, url=FORTUNE_URL, pattern=FORTUNE_PATTERN,
                 try_local=True):
        """Initialize the fortune object"""
        self.url = url
        self.pattern = pattern
        self._text = None
        self.try_local = try_local
    
    def __repr__(self):
        """Representation of the fortune"""
        return self.text
    
    def _get_html(self) :
        """Return the html content from a web page."""
        try :
            sock = urllib2.urlopen(self.url)
            html_source = sock.read()
            sock.close()
        except urllib2.URLError:
            raise InternetHasDisappear
        return html_source
    
    def _html2text(self, html):
        """Delete LF and spaces, and replace <br /> and &nbsp;"""
        html = html.replace('\n', '')
        html = html.replace(' ', '')
        html = html.replace('<br/>', '\n')
        html = html.replace('&nbsp;', ' ')
        return html
    
    def _fortune_live_here(self):
        """Return if a fortune command is usable and if self.try_local"""
        return self.try_local and \
               commands.getoutput('which fortune').startswith('/')
    
    def _get_local_fortune(self):
        """Return a fortune from the local fortune command"""
        return commands.getoutput('fortune')
    
    def _get_text(self, new = False):
        """Return the fortune text (from the web or from the cache)"""
        if new or self._text is None:
            # Get a new fortune from the web or the local fortune
            if self._fortune_live_here():
                self._text = self._get_local_fortune()
            else:
                self._text = self._html2text(
                    self.pattern.findall(self._get_html())[0]
                )
        return self._text
    
    def _set_text(self, text):
        """Set the fortune text"""
        self._text = text
    
    text = property(fget=_get_text,
                    fset=_set_text,
                    doc = u'Fortune text')
    
    def next(self):
        """Get and return a new fortune"""
        return self._get_text(True)

def start():
    """Run webfortune"""
    # Make the parameters parser
    usage = u"usage: %prog [options] [url] [pattern]"
    opt_parser = OptionParser(usage=usage)
    opt_parser.add_option(
        "-w", "--web",
        action="store_false",
        dest="try_local",
        default=True,
        help=u"don't try to use the local fortune",
    )
    (options, args) = opt_parser.parse_args()
    # Check the number of arguments, and set arguments
    if len(args) > 2:
        opt_parser.print_help(sys.stderr)
        sys.exit(2)
    if len(args) > 0:
        url = args[0]
    else:
        url = FORTUNE_URL
    if len(args) > 1:
        pattern = re.compile(args[2], re.DOTALL)
    else:
        pattern = FORTUNE_PATTERN
    # Try to print a fortune
    try:
        print Fortune(url, pattern, options.try_local)
        sys.exit(0)
    except InternetHasDisappear, fortune:
        print fortune.cookie
        sys.exit(1)

if __name__ == '__main__':
    start()
