# -*- coding: utf-8 -*-
#VERSION: 1.3
#AUTHORS: Joost Bremmer (toost.b@gmail.com)
#
#  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 <https://www.gnu.org/licenses/>.

import datetime
import os
import tempfile

try:
    import urllib2 as request
    from urllib import urlencode
    from cookielib import CookieJar
    from HTMLParser import HTMLParser
except ImportError:
    import urllib.request as request
    from urllib.parse import urlencode
    from http.cookiejar import CookieJar
    from html.parser import HTMLParser

# import qBT modules
try:
    from novaprinter import prettyPrinter
    from helpers import htmlentitydecode
except:
    pass


class bakabt(object):
    """Class used by qBittorrent to search bakabt.me for torrents

    It is important to replace the username and password values with your
    personal login information. Without this, this plugin will *not* work.
    """

    # Login information ######################################################
    #
    # SET THESE VALUES!!
    #
    username = "username"
    password = "password"
    ###########################################################################

    url = 'https://bakabt.me'
    name = 'BakaBT'
    # defines which search categories are supported by this search engine
    # and their corresponding id. Possible categories are:
    # 'all', 'movies', 'tv', 'music', 'games', 'anime', 'software', 'pictures',
    # 'books'
    supported_categories = {
            'all': 0,
            'anime': 1,
            'music': 3,     # Soundtracks
            'books': 4,     # Manga
            'movies': 5,
            'tv': 6,        # Live Action
            'pictures': 7}  # Artbooks

    class BakaDownloadParser(HTMLParser):
        """Parses BakaBT torrent page for download link"""
        def __init__(self):
            try:
                super().__init__()
            except:
                # See: http://stackoverflow.com/questions/9698614/
                HTMLParser.__init__(self)
            self.download = None

        def handle_starttag(self, tag, attr):
            if tag == 'a':
                self.start_a(attr)

        def start_a(self, attr):
            params = dict(attr)
            if 'class' in params and params['class'] == 'download_link':
                self.download = params['href']

    class BakaSearchParser(HTMLParser):
        """ Parses BakaBT browse page for search results and prints them"""
        def __init__(self, res, url):
            try:
                super().__init__()
            except:
                # See: http://stackoverflow.com/questions/9698614/
                HTMLParser.__init__(self)
            self.download = None
            self.results = res
            self.engine_url = url
            self.curr = None
            self.wait_for_title = False
            self.wait_for_date = False
            self.wait_for_size = False
            self.wait_for_seeds = False
            self.wait_for_peers = False

        def handle_starttag(self, tag, attr):
            if tag == 'a':
                self.start_a(attr)
            elif tag == 'td':
                self.start_td(attr)

        def start_a(self, attr):
            params = dict(attr)
            if 'class' in params and 'title' in params['class']:
                hit = {
                        'link': self.engine_url + '/' + params['href'],
                        'desc_link': self.engine_url + '/' + params['href']}
                self.curr = hit
                self.wait_for_title = True
            elif 'style' in params and params['style'] == "color: #00cc00":
                self.wait_for_seeds = True
            elif self.curr is not None and 'seeds' in self.curr:
                self.wait_for_peers = True

        def start_td(self, attr):
            params = dict(attr)
            if 'class' in params and self.curr is not None:
                if params['class'] == 'added':
                    pass
                    #  self.wait_for_date = True
                elif params['class'] == 'size':
                    self.wait_for_size = True

        def handle_data(self, data):
            if self.wait_for_title:
                self.curr['name'] = data.strip()
                self.wait_for_title = False
            elif self.wait_for_date:
                try:
                    date = datetime.datetime.strptime(data.strip(),
                                                      "%d %b '%y")
                except ValueError:
                    date = datetime.datetime.now()
                self.curr['date'] = date.strftime("%Y-%m-%d")
                self.wait_for_date = False
            elif self.wait_for_size:
                self.curr['size'] = data.strip()
                self.wait_for_size = False
            elif self.wait_for_seeds:
                self.curr['seeds'] = int(data.strip())
                self.wait_for_seeds = False
            elif self.wait_for_peers:
                self.curr['leech'] = int(data.strip())
                self.curr['engine_url'] = self.engine_url
                prettyPrinter(self.curr)
                self.results.append(self.curr)
                self.curr = None
                self.wait_for_peers = False

    def __init__(self):
        """class initialization, requires personal login information"""

        self.ua = \
            'Mozilla/5.0 (X11; Linux i686; rv:38.0) ' + \
            'Gecko/20100101 Firefox/38.0'
        self.sesh = None

        self._login(self.username, self.password)

    def _login(self, username, password):
        """Initiate a session and log into BakaBT"""

        # Build opener
        cj = CookieJar()
        params = {
                'username': self.username,
                'password': self.password,
                'returnto': 'browse.php'}
        sesh = request.build_opener(request.HTTPCookieProcessor(cj))

        # change user-agent
        sesh.addheaders.pop()
        sesh.addheaders.append(('User-Agent', self.ua))

        # send request
        try:
            sesh.open(
                    self.url + '/splash.php',
                    urlencode(params).encode('utf-8'))
            self.sesh = sesh
        except request.URLError as errorno:
            print("Connection Error: {}".format(errorno.reason))

    def _retreive_url(self, url):
        """Return the HTML content of url page as a string """
        try:
            res = self.sesh.open(url)
        except request.URLError as errorno:
            print("Connection Error: {}".format(errorno.reason))
            return ""

        charset = 'utf-8'
        info = res.info()
        try:
            _, charset = info['Content-Type'].split('charset=')
        except:
            pass
        dat = res.read()
        dat = dat.decode(charset, 'replace')

        dat = htmlentitydecode(dat)
        return dat

    def download_torrent(self, info):
        """Retrieve and save url as a temporary file."""
        file, path = tempfile.mkstemp()
        url = info

        parser = self.BakaDownloadParser()
        res = self._retreive_url(url)
        parser.feed(res)
        download = self.url + '/' + parser.download
        parser.close()

        torrent = self.sesh.open(download)
        with os.fdopen(file, "wb") as f:
            f.write(torrent.read())
        f.close()
        # Print file path and url.
        print(path+" "+download)
        parser.close()

    # DO NOT CHANGE the name and parameters of this function
    # This function will be the one called by nova2.py
    def search(self, what, cat='all'):
        """
        Retreive and parse all BakaBT search results by category and query.

        Parameters:
        :param what: a string with the search tokens, already escaped
                     (e.g. "Ubuntu+Linux")
        :param cat:  the name of a search category, see supported_categories.
        """
        if cat in self.supported_categories:
            url = "{0}/browse.php?limit=100&ordertype=seeders&q={1}&cat={2}"\
                    .format(
                            self.url,
                            what,
                            self.supported_categories[cat])
        else:
            url = "{0}/browse.php?limit=100&ordertype=seeders&q={1}"\
                    .format(self.url, what)

        hits = []
        parser = self.BakaSearchParser(hits, self.url)
        i = 0
        while True:
            res = self._retreive_url(url + "&page={}".format(i))
            parser.feed(res)
            if len(hits) < 100:
                break
            del hits[:]
            i += 1
        parser.close()
