#!/usr/bin/python

# This is a part of the external Quote applet for Cairo-Dock
#
# Author: Eduardo Mucelli Rezende Oliveira
# E-mail: edumucelli@gmail.com or eduardom@dcc.ufmg.br
#
# 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.

# This applet provides a "Quote of the day" feature from some internet sources
# such as Quotationspage.com, Bash.org, Xkcdb.com, Qdb.us, Danstonchat.fr,
# Jokes2go.com, and Vidademerda.com.br

import itertools

try:
	import gtk
except:
	from gi.repository import Gtk as gtk

from sgmllib import SGMLParser
try:
    from urllib.request import FancyURLopener
except:
    from urllib import FancyURLopener
from util import log

from CDApplet import CDApplet, _

# To add a new parser you have to:
# 1 - Create a file NameOfTheSiteParser.py, see BashParser.py, QdbParser.py, etc
# 1.1 - For specific parts on the creation of the parser, refer to BashParser, some documentation is there
# 2 - Import it "from MyWebSiteParser (module name) import MyWebSiteParser (class name)"
# 3 - Add one identificator for the parser, for example, "quotationspage" = 1. Look that we already have
#     many parsers. For each new one you add, you have  increment the parameter on the range method
# 4 - On the fetch method, add a new block
#     elif (self.source == mywebsite):
#       parser = MyNewWebSiteParser
#     And check if it is necessary to remove some extra character, check the documented part on the fetch method
# 5 - Add the website option on the Quote.conf, see the [Configuration] section inside it

from BashParser import BashParser                                       # Bash.org
from QdbParser import QdbParser                                         # Qdb.us
from XkcdbParser import XkcdbParser                                     # Xkcdb.com
from QuotationspageParser import QuotationspageParser                   # Quotationspage.com
from DanstonchatParser import DanstonchatParser                         # Danstonchat.fr
from JokestogoParser import JokestogoParser                             # Jokes2go.com
from VidademerdaParser import VidademerdaParser                         # Vidademerda.com.br
from ViedemerdeParser import ViedemerdeParser                           # Viedemerde.fr
from FmylifeParser import FmylifeParser                                 # Fmylife.com
from VitadimerdaParser import VitadimerdaParser                         # VitadimerdaParser.it
from HundredblaguesParser import HundredblaguesParser                   # HundredblaguesParser.com
from ChucknorrisfactsfrParser import ChucknorrisfactsfrParser           # Chucknorrisfacts.fr

# quotationspage = 0, bash = 1, xkcdb = 2, qdb = 3, danstonchat = 4, jokestogo = 5, vidademerda = 6, viedemerde = 7, fmylife = 8, vitadimerda = 9, hundredblagues = 10, chucknorrisfactsfr = 11
quotationspage, bash, xkcdb, qdb, danstonchat, jokestogo, vidademerda, viedemerde, fmylife, vitadimerda, hundredblagues, chucknorrisfactsfr = list(range(12))  

class AgentOpener(FancyURLopener):
  """Masked user-agent otherwise the access would be forbidden"""
  version = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11'

class Interface:

  def __init__(self, source):
    self.source = source                                                # The source of the quotes, it is the 
    self.author = []                                                    # List of authors of the current source
    self.quote = []                                                     # List of quotes of the current source

  def fetch(self):
    if self.source == quotationspage:
      parser = QuotationspageParser()                                   # QuotationspageParser.py
    elif self.source == bash:
      parser = BashParser()                                             # BashParser.py
    elif self.source == xkcdb:
      parser = XkcdbParser()                                            # XkcdbParser.py
    elif self.source == qdb:
      parser = QdbParser()                                              # QdbParser.py
    elif self.source == danstonchat:
      parser = DanstonchatParser()                                      # DanstonchatParser.py
    elif self.source == jokestogo:
      parser = JokestogoParser()                                        # JokestogoParser.py
    elif self.source == vidademerda:                                    
      parser = VidademerdaParser()                                      # VidademerdaParser.py
    elif self.source == viedemerde:
      parser = ViedemerdeParser()                                       # ViedemerdeParser.py
    elif self.source == fmylife:                                                               
      parser = FmylifeParser()                                          # FmylifeParser.py
    elif self.source == vitadimerda:
      parser = VitadimerdaParser()                                      # VitadimerdaParser.py
    elif self.source == hundredblagues:
      parser = HundredblaguesParser()                                   # HundredblaguesParser.py
    else:                                                               
      parser = ChucknorrisfactsfrParser()

    opener = AgentOpener()                                              # opens the web connection with masked user-agent

    try:
      page = opener.open(parser.url)                                    # get the HTML
    except IOError:
      log ("Problem to open %s" % (parser.url))
    else:
      parser.parse(str(page.read()))                                    # feed the parser with the page's content
      page.close()                                                      # close the page connection
            
      # Handle different kind of returns from the parser. It is necessary because some sources return quotes with extra
      # characters that we need to filter here. Some come with extra '', others come with linebreaks, etc.
      
      if self.source == quotationspage:
        self.quote = parser.quote
        self.author = parser.author
      elif self.source in [bash, xkcdb, qdb, danstonchat, viedemerde, fmylife, vitadimerda, hundredblagues, chucknorrisfactsfr]:
        self.quote = [_f for _f in parser.quote if _f]                         # remove the '' from the array
      elif self.source == jokestogo:                                    # jokestogo
        self.quote = list(filter(self.linebreak, parser.quote))               # remove linebreak from the array
      else:                                                             # vidademerda
        self.quote = [''.join(parser.quote)]
        self.author = parser.author
    return self.quote, self.author

  def linebreak(self, item):
    return not item == '\n'

class Applet(CDApplet):

  def __init__(self):
    self.authors = None
    self.quotes = None
    self.quotation = ""
    self.dialog_active_time = 30                                        # time in seconds that the dialog window will be active
    self.copy_current_quote_key = 0
    self.go_next_quote_key = 1
    self.source = quotationspage
    self.names = ["Quotationspage.com","Bash.org","Xkcdb.com","Qdb.us","Danstonchat.com","Jokes2go.com",
                    "Vidademerda.com.br","Viedemerde.fr","Fmylife.com", "Vitadimerda.it", "100blagues.com", "Chucknorrisfacts.fr"]
    
    CDApplet.__init__(self)                                             # call high-level init
  
  # Clipboard operations
  def set_to_clipboard(self, sentence):
    clipboard = gtk.clipboard_get()                                     # get the clipboard
    clipboard.set_text(sentence)                                        # set the clipboard the current quote

  # Quotes
  def get_quotes_from_web(self):
    self.inform_start_of_waiting_process()                              # write "..." on the icon
    interface = Interface(self.source)
    quote, author = interface.fetch()
    if (self.source == quotationspage):                                 # sources that gives the same quotes per fetch, we need circular iterator
      self.quotes = itertools.cycle(quote)
      self.authors = itertools.cycle(author)
    else:                                                               # all the rest of sources that gives different quotes per fetch, for example, 
      self.quotes = iter(quote)                                         # pages that have "random" section from where we always fetch new quotes
      self.authors = iter(author)                                       # from where we do not need to use circular iterator
    self.inform_end_of_waiting_process()                                # remove the "..." from the icon

  def show_quote(self):
    if (self.source == quotationspage):
      self.quotation = "\"%s\" ~ %s" % (next(self.quotes), next(self.authors)) # quote[x] ~ author[x]
    elif self.source in [bash, xkcdb, qdb, danstonchat, viedemerde, fmylife, vitadimerda, hundredblagues, chucknorrisfactsfr]:
      try:                                                              # check if it is possible to show the already stored quotes
        current = next(self.quotes)
      except StopIteration:                                             # all were already shown
        self.get_quotes_from_web()                                      # fetch more
        current = next(self.quotes)                                    # get the first
      self.quotation = "%s" % current
    elif (self.source == jokestogo):                                    # jokestogo provides only one quote per request ...
      self.quotation = "%s" % self.quotes.next().rstrip()                 
      self.get_quotes_from_web()                                        # ... so it is necessary to request it again
    else:                                     
      self.quotation = "%s ~ %s" % (next(self.quotes), next(self.authors))  # vidademerda  provides only one quote per request ...
      self.get_quotes_from_web()                                        # ... so it is necessary to request it again
    self.icon.PopupDialog({'message':self.quotation, "buttons":"stock_copy;go-next;cancel"}, {})

  def inform_start_of_waiting_process(self):
    self.icon.SetQuickInfo("...")

  def inform_end_of_waiting_process(self):
    self.icon.SetQuickInfo("")
  
  def display_source_name(self):
    if self.config['default title'] == "":
      self.icon.SetLabel(self.names[self.source])
  
  # Inherited methods from CDApplet
  def begin(self):
    self.get_quotes_from_web()
    self.display_source_name()

  def get_config(self, keyfile):
    self.source = keyfile.getint('Configuration', 'source')             # get the source of quotations
    self.config['default title'] = keyfile.get('Icon', 'name')          # icon's label set by the user.

  def reload(self):
    self.get_quotes_from_web()                                          # refresh the quotations
    self.display_source_name()

  # Callbacks
  def on_click(self, key):
    self.show_quote()

  def on_answer_dialog(self, key, content):
    if (key == self.copy_current_quote_key):                            # cancel button = 1, and copy_current_quote_key = 0
      self.set_to_clipboard(self.quotation)                             # copy to the transfer area the current quotation
    elif (key == self.go_next_quote_key or key == CDApplet.DIALOG_KEY_ENTER):
      self.show_quote()

if __name__ == '__main__':
  Applet().run()
