__license__   = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
'''
Fetch cover from LibraryThing.com based on ISBN number.
'''

import sys, re, random

from lxml import html
import mechanize

from calibre import browser, prints
from calibre.utils.config import OptionParser
from calibre.ebooks.chardet import strip_encoding_declarations

OPENLIBRARY = 'http://covers.openlibrary.org/b/isbn/%s-L.jpg?default=false'

def get_ua():
    choices = [
        'Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11'
        'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)'
        'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)'
        'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)'
        'Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16'
        'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.2.153.1 Safari/525.19'
        'Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11'
    ]
    return choices[random.randint(0, len(choices)-1)]

_lt_br = None
def get_browser():
    global _lt_br
    if _lt_br is None:
        _lt_br = browser(user_agent=get_ua())
    return _lt_br.clone_browser()

class HeadRequest(mechanize.Request):

    def get_method(self):
        return 'HEAD'

def check_for_cover(isbn, timeout=5.):
    br = get_browser()
    br.set_handle_redirect(False)
    try:
        br.open_novisit(HeadRequest(OPENLIBRARY%isbn), timeout=timeout)
        return True
    except Exception, e:
        if callable(getattr(e, 'getcode', None)) and e.getcode() == 302:
            return True
    return False

class LibraryThingError(Exception):
    pass

class ISBNNotFound(LibraryThingError):
    pass

class ServerBusy(LibraryThingError):
    pass

def login(br, username, password):
    raw = br.open('http://www.librarything.com').read()
    if '>Sign out' in raw:
        return
    br.select_form('signup')
    br['formusername'] = username
    br['formpassword'] = password
    raw = br.submit().read()
    if '>Sign out' not in raw:
        raise ValueError('Failed to login as %r:%r'%(username, password))

def option_parser():
    parser = OptionParser(usage=\
_('''
%prog [options] ISBN

Fetch a cover image/social metadata for the book identified by ISBN from LibraryThing.com
'''))
    parser.add_option('-u', '--username', default=None,
                      help='Username for LibraryThing.com')
    parser.add_option('-p', '--password', default=None,
                      help='Password for LibraryThing.com')
    return parser

def get_social_metadata(title, authors, publisher, isbn, username=None,
        password=None):
    from calibre.ebooks.metadata import MetaInformation
    mi = MetaInformation(title, authors)
    if isbn:
        br = get_browser()
        try:
            login(br, username, password)

            raw = br.open_novisit('http://www.librarything.com/isbn/'
                        +isbn).read()
        except:
            return mi
        if '/wiki/index.php/HelpThing:Verify' in raw:
            raise Exception('LibraryThing is blocking calibre.')
        if not raw:
            return mi
        raw = raw.decode('utf-8', 'replace')
        raw = strip_encoding_declarations(raw)
        root = html.fromstring(raw)
        h1 = root.xpath('//div[@class="headsummary"]/h1')
        if h1 and not mi.title:
            mi.title = html.tostring(h1[0], method='text', encoding=unicode)
        h2 = root.xpath('//div[@class="headsummary"]/h2/a')
        if h2 and not mi.authors:
            mi.authors = [html.tostring(x, method='text', encoding=unicode) for
                    x in h2]
        h3 = root.xpath('//div[@class="headsummary"]/h3/a')
        if h3:
            match = None
            for h in h3:
               series = html.tostring(h, method='text', encoding=unicode)
               match = re.search(r'(.+) \((.+)\)', series)
               if match is not None:
                   break
            if match is not None:
                mi.series = match.group(1).strip()
                match = re.search(r'[0-9.]+', match.group(2))
                si = 1.0
                if match is not None:
                    si = float(match.group())
                mi.series_index = si
        #tags = root.xpath('//div[@class="tags"]/span[@class="tag"]/a')
        #if tags:
        #    mi.tags = [html.tostring(x, method='text', encoding=unicode) for x
        #            in tags]
        span = root.xpath(
                '//table[@class="wsltable"]/tr[@class="wslcontent"]/td[4]//span')
        if span:
            raw = html.tostring(span[0], method='text', encoding=unicode)
            match = re.search(r'([0-9.]+)', raw)
            if match is not None:
                rating = float(match.group())
                if rating > 0 and rating <= 5:
                    mi.rating = rating
    return mi


def main(args=sys.argv):
    parser = option_parser()
    opts, args = parser.parse_args(args)
    if len(args) != 2:
        parser.print_help()
        return 1
    isbn = args[1]
    from calibre.customize.ui import metadata_sources, cover_sources
    lt = None
    for x in metadata_sources('social'):
        if x.name == 'LibraryThing':
            lt = x
            break
    lt('', '', '', isbn, True)
    lt.join()
    if lt.exception:
        print lt.tb
        return 1
    mi = lt.results
    prints(mi)
    mi.isbn = isbn

    lt = None
    for x in cover_sources():
        if x.name == 'librarything.com covers':
            lt = x
            break

    from threading import Event
    from Queue import Queue
    ev = Event()
    lt.has_cover(mi, ev)
    hc = ev.is_set()
    print 'Has cover:', hc
    if hc:
        abort = Event()
        temp = Queue()
        lt.get_covers(mi, temp, abort)

        cover = temp.get_nowait()
        if cover[0]:
            open(isbn + '.jpg', 'wb').write(cover[1])
            print 'Cover saved to:', isbn+'.jpg'
        else:
            print 'Cover download failed'
            print cover[2]

    return 0

if __name__ == '__main__':
    sys.exit(main())
