#!/usr/bin/env python
# -*- coding:Utf-8 -*- 

"""

Auteur :      thuban <thuban@yeuxdelibad.net>  
licence :     MIT
"""


from bottle import *
from threading import Thread
import webbrowser

from .database import DontPanicDB
from .i18nlib import _
from .subtitle import Subtitle
from .torrentsession import TorrentSession
from .utils import *
from .webutils import *

from urllib.parse import quote as quoteurl

import locale

def search2html(keywords, extrawords=' ', searchengine='alphareign', page=0, isserie=0):
    """
    Show search result

    Args:
        keywords:
        extrawords:
        searchengine:
        page:
        isserie:

    Return:

    """
    if searchengine == tpl_msg['tpl_all']:
        searchengine = "*"

    sch = '{} {}'.format(keywords, extrawords).strip()
    with TorrentSearch(searchengine) as ts:
        s = ts.search(sch, page)

    # If there is results
    if s:
        html = '<table class="sortable">\n'
        html += '<thead>\n'
        html += '<tr>\n'
        html += '<th class="text-left">{}</th>\n'.format(_('Name'))
        html += '<th>{}</th>\n'.format(_('Size'))
        html += '<th>{}</th>\n'.format(_('Leechs'))
        html += '<th id="seeds">{}</th>\n'.format(_('Seeds'))
        html += '</tr>\n'
        html += '</thead>\n'

        html += '<tbody>'
        for result in s:
            link = '/stream/{}/{}/{}'.format(keywords, quoteurl(result['magnet']), isserie)
            html += '<tr>\n'
            html += '<td><a href="{}">{}</a></td>\n'.format(link, result['name'])
            html += '<td class="text-center"><a href="{}">{}</a></td>\n'.format(link, result['size'])

            html += '<td class="text-center"><a href="{}">{}</a></td>\n'.format(link, result['leechs'])

            # color depending on seeds number
            color = 'grey'
            if result['seeds'] != '?':
                seeds = int(result['seeds'])
                if seeds <= 10:
                    color = 'red'
                elif 40 >= seeds > 10:
                    color = 'orange'
                elif 70 >= seeds > 40:
                    color = 'yellow'
                elif 100 >= seeds > 70:
                    color = 'blue'
                elif seeds > 100:
                    color = 'green'

            html += '<td class="text-center" style="background:{};"><a href="{}">{}</a></td>'.format(
                    color, link, result['seeds'])
            html += '</tr>'
        html += '</tbody>'
        html += '</table>'
        if searchengine in [ 'alphareign', 'btdb', 'digbt', 'p2psearch' ]:
            html += '<a href="/moreresults/{}/{}/{}/{}/{}">{}</a>'.format(
                    keywords, int(page) + 1, searchengine, extrawords, isserie, _('More results'))
    else:  # If there is no result
        html = '<p><br>{}</p>'.format(
            _('There is no result for your search, try something else'))

    return html



def watchlist(user):
    movies = ''
    series = ''
    with DontPanicDB() as db:
        watchlists = db.get_watchlist(user)

    for watch in watchlists:
        for ele in watch["list"]:
            date = ele["datetime"]
            title = ele["title"]
            magnet = ele["magnet"]
            video = str()

            link_remove = quoteurl('/_removeinwatchlist/{}/'.format(title))
            link_watch = quoteurl('/stream/{}/{}/{}'.format(title, magnet, 1 if watch["type"] == "serie" else 0))

            video += '<td>{}</td>\n'.format(date)
            video += '<td>{}</td>\n'.format(title)

            actions = str()
            if magnet:
                actions += '<span class="float-right"><a href="{}">▷ {}</a></span>'.format(link_watch, _('Watch again'))
            actions += '<span class="float-right"><a href="{}">✕ {}</a></span>'.format(link_remove, _('Remove'))
            video += '<td>{}</td>\n'.format(actions)

            video = '<tr>{}</tr>\n'.format(video)

            if watch["type"] == "serie":
                series += video
            else:
                movies += video

    if len(movies) > 0:
        movies = """
        <table style="padding-left: 30px;">
            <thead>
                <tr><th>{}</th><th>{}</th></tr>
            </thead>
            <tbody>{}</tbody>
        </table>""".format(_("Date"), _("Title"), movies)

    if len(series) > 0:
        series = """
        <table style="padding-left: 30px;">
            <thead>
                <tr><th>{}</th><th>{}</th></tr>
            </thead>
            <tbody>{}</tbody>
        </table>""".format(_("Date"), _("Title"), series)

    return movies, series


def create_select_search_engine(selected):
    #list_search_engines = ["btdigg", "kickasstorrents", "piratebay", "torrentproject", tpl_msg['tpl_all']]
    list_search_engines = ["alphareign", "btdb", "digbt", "p2psearch", "kickasstorrents", "piratebay", "isohunt", "torrent9", tpl_msg['tpl_all']]

    list_html = str()
    for search_engine in list_search_engines:
        list_html += "\t<option{}>{}</option>\n".format(" selected" if search_engine == selected else "",
                                                        search_engine)

    return '<select name="searchengine" size="1">\n{}</select>'.format(list_html)


def pick_welcomemsg():
    return WELCOMEMSG[random.randrange(0, len(WELCOMEMSG))]


def pick_logo():
    if time.strftime("%m") == "12":
        return "dontpanic-noel.png"
    else:
        return "favicon.png"




class DontPanic:
    def __init__(self, host, port, admin, adminpw="password", local_=True, magnet=""):
        self.startperc = None
        self.tmp = tempdir
        self.uplimit = None
        self.downlimit = None
        self.proxy = ""
        self.proxy_type = ""
        self.proxy_hostname = ""
        self.proxy_username = ""
        self.proxy_password = ""
        self.fav_sch_engine = ""
        self.lastversion = islastversion()

        self.app = Bottle()
        self.host = host
        self.port = port
        self.local = local_
        self.dldic = {}
        self.secret = randomtext(22)
        self.read_config()

        self.admin = admin
        self.adminpw = adminpw

        self.magnet_as_arg = magnet

        with DontPanicDB() as db:
            db.add_user(admin, adminpw)

        @self.app.route('/')
        def index():
            user = ''
            if self.local:
                response.set_cookie("username", self.admin, secret=self.secret, httponly=True)
                user = self.admin

            # show recent search
            html = ''
            if user == '':
                user = request.get_cookie("username", secret=self.secret)


            tplvars = {'welcomemsg': pick_welcomemsg(),
                       'recents': html,
                       'logo': pick_logo(),
                       'islastv' : self.lastversion,
                       'search_engines': create_select_search_engine(self.fav_sch_engine)}
            tplvars.update(tpl_msg)
            return template('towel', tplvars)

        @self.app.route('/static/<filename:path>')
        def static(filename):
            return static_file(filename, root='./static/')

        @self.app.route('/me')
        def login():
            whoami = request.get_cookie("username", secret=self.secret)
            if not whoami:
                return '''
                        <form action="/me" method="post">
                            {}: <input name="username" type="text" />
                            {}: <input name="password" type="password" />
                            <input value="{}" type="submit" />
                        </form>
                        <p><a href="/sign">{}</a></p>
                        '''.format(_("Username"), _("Password"), _("Login"), _("Register"))
            else:
                movies, series = watchlist(whoami)
                tplvars = {'username': whoami, 'movies': movies, 'series': series}
                tplvars.update(tpl_msg)

                return template('perso', tplvars)

        @self.app.route('/me', method='POST')
        def do_login():
            username, password = request.forms.get('username'), request.forms.get('password')

            with DontPanicDB() as database:
                if database.check_login(username, password):
                    response.set_cookie("username", username, secret=self.secret)
                    redirect('/me')
                else:
                    abort(401, _('Your login information was incorrect'))

        @self.app.route('/logout')
        def logout():
            response.delete_cookie("username")
            redirect('/')

        @self.app.route('/sign')
        def sign():
            return ('''
                    <h1>{}</h1>
                    <form action="/sign" method="post">
                        {}: <input name="username" type="text" />
                        {}: <input name="password" type="password" />
                        <input value="{}" type="submit" />
                    </form>
                    '''.format(_("Register"), _("Username"), _("Password"), _("Login")))

        @self.app.route('/sign', method='POST')
        def do_sign():
            username, password = request.forms.get('username'), request.forms.get('password')

            with DontPanicDB() as database:
                if database.add_user(username, password):
                    return '''
                        <h1>{}</h1>
                        <p><a href="/me">{}</a> ;)</p>
                        '''.format(_("Congratulations, your subscription is a success"), _("Now, log in"))
                else:
                    return '<h1>{} {}</h1>'.format(_("Oh no!"), _("User {} already exists".format(username)))

        @self.app.route('/unsubscribe')
        def unsubscribe():
            whoami = request.get_cookie("username", secret=self.secret)
            if not whoami:
                html = _("You're not logged in")
            else:
                with DontPanicDB() as database:
                    if database.delete_user(whoami):
                        html = _("Your account is deleted")
                    else:
                        html = _("An error occurred while deleting your account. Please contact the administrator")

            html = "<div>{}</div>".format(html)

            tplvars = {'htmlstuff': html, 'title': _("Unsubscribe")}
            tplvars.update(tpl_msg)

            return template('classic', tplvars)

        @self.app.route('/clean')
        def cleanup():
            cleancache()
            redirect('/_admin')

        @self.app.route('/cleantorrent')
        def cleantorrent():
            self._clean_torlist()
            redirect('/_admin')

        @self.app.route('/search', method='get')
        def search():
            keywords = request.query.get('keywords')
            searchengine = request.query.get('searchengine')
            nocatalog = request.query.get('nocatalog')
            extrawords = request.query.get('extrawords')
            isserie = request.query.get('isserie')

            if not searchengine:
                searchengine = ''
            if not nocatalog:
                nocatalog = 0
            if not extrawords:
                extrawords = ' '
            if not isserie:
                isserie = '0'

            logger.info('Searching on {}...   '.format(searchengine))
            # FIXME: Better handle when a search engine has modified its html code
            try:
                htmlresults = search2html(keywords, extrawords=extrawords, searchengine=searchengine, isserie=isserie)
            except Exception as e:
                print(e)
                logger.info('Error while searching :  {}...   '.format(e))
                htmlresults = '<div><br>{}</div>'.format(_("Error while searching. Try another engine"))

            tplvars = {'sch_res': htmlresults,
                       'the_search': '{} {}'.format(keywords, extrawords).strip(),
                       'isserie': isserie,
                       'search_engines': create_select_search_engine(searchengine),
                       'nocatalog': nocatalog}
            tplvars.update(tpl_msg)
            return template('results', tplvars)

        @self.app.route('/moreresults/<keywords>/<page>/<searchengine>/<extrawords>/<isserie>')
        def moreresults(keywords, page, searchengine, extrawords, isserie):
            # FIXME: Better handle when a search engine has modified its html code
            try:
                htmlresults = search2html(keywords.strip(),
                                          extrawords=extrawords,
                                          searchengine=searchengine,
                                          page=page,
                                          isserie=isserie)
            except Exception as e:
                logger.info('Error while searching :  {}...   '.format(e))
                htmlresults = _("Error while searching. Try another engine")

            tplvars = {
                'sch_res': htmlresults,
                'the_search': '{} {}'.format(keywords, extrawords).strip(),
                'search_engines': create_select_search_engine(searchengine),
                'isserie': isserie}
            tplvars.update(tpl_msg)
            return template('results', tplvars)


        @self.app.route("/stream/<name>/<magnet:path>/<isserie>")
        def stream(name, magnet, isserie):
            # Start download
            if self.proxy != "none":
                newses = TorrentSession(self.proxy_type, self.proxy_hostname, self.proxy_username, self.proxy_password)
            else:
                newses = TorrentSession()
            newses.download(magnet, self.tmp, self.uplimit, self.downlimit)

            index = 1
            if len(self.dldic) > 0:
                while index in self.dldic.keys():
                    index += 1
            self.dldic[index] = newses

            # Record to watchlist
            whoami = request.get_cookie("username", secret=self.secret)
            if whoami:
                t = Thread(target=self._add_when_ready, args=(newses, whoami, name, magnet, isserie))
                t.start()

            tplvars = {'movie_name': name,
                       'status': '',
                       'playlink': '',
                       'subtitles': '',
                       'stop': '',
                       'index': index}
            tplvars.update(tpl_msg)

            return template('towel-dl', tplvars)

        @self.app.route('/_getinfos/<name>/<index:int>')
        def getinfos(name, index):
            """
            Give infos html formatted

            Args:
                name: Title of the video
                index:
            """
            session = self.dldic[index]
            perc = session.get_progress()
            state = session.get_state()
            peers = session.get_peers()
            downrate = session.get_downrate()

            # Hack for progress bar
            # htmlperc = '<div class="progressbar" style="background-size: {}% 100%; ">'.format(perc)
            htmlperc = '<div>{}% <br>{} - {}/s - {} peers</div>'.format(perc, state, downrate, peers)
            htmlperc += '<div class="progressbar"><progress value="{0}" max="100" ></progress>'.format(perc)
            htmlperc += '</div>'

            # To stop the download
            stop = ''
            if state != "downloading metadata":
                stop = '<a href="/stopdl/{}" >{}</a>'.format(index, _('Stop this download'))

            # Show the play link
            moviepath = session.get_file_name()
            playlink = ''
            subtitles = ''
            if perc >= int(self.startperc) and session.ready2watch():
                # Show the link to play the file
                playlink = '<p><span class="big">' \
                           '\t<a href="/html5/{}" target="_blank">{} ▷</a>' \
                           '</span></p>'.format(moviepath, _('Play'))
                subtitles = '<a href="/getsubtitles/{}/{}" target="_blank">{}</a> - '.format(
                    name, moviepath, _('Find subtitles'))

            return {'status': htmlperc,
                    'playlink': playlink,
                    'subtitles': subtitles,
                    'stop': stop}

        @self.app.route('/stopdl/<i:int>')
        def stopdl(i):
            t = self.dldic[i]
            whoami = request.get_cookie("username", secret=self.secret)
            if whoami != self.admin:
                return _("Only the administrator can delete a download")
            else:
                h = t.handle
                session = t.session
                session.remove_torrent(h)
                self.dldic.pop(i)
                del session

                html = "<div>{}</div>".format(_("Torrent deleted"))

                tplvars = {'htmlstuff': html, 'title': "Deleted"}
                tplvars.update(tpl_msg)
                return template('classic', tplvars)

        @self.app.route('/html5/<filename:path>')
        def html5(filename):
            mt = mimetypes.guess_type(filename)[0]

            
            if mt == 'video/x-msvideo-nimportequoi' :
                #video = '<object data="/video/{}" width="360" height="250">\n'.format(filename)
                #video += '<param name="src" value="/video/{}" /> </object>\n'.format(filename)
                video = '<embed src="/video/{}">\n'.format(filename)
            else:
                mtype = 'type="{}"'.format(mt)
                video = '<video width="640" controls preload="auto" autoplay="true" >\n'
                video += '<source src="/video/{}" {} >\n'.format(filename, mtype)
                video += '</video>\n'

            links = '<div>\n'
            links += '<br/>\n'
            links += _("If your browser doesn't support the player above, you may want to : ")
            links += '<br/>\n'
            if self.local:
                links += '<a href="/localvideo/{}">▷ {}</a> - \n'.format(filename, _('Play with external video player'))
            links += '<a href="/video/{}">↓ {}</a>\n'.format(filename, _('Download the video'))
            links += '</div>\n'

            html = "<div>{} {}</div>".format(video, links)

            tplvars = {'title': os.path.basename(filename), 'htmlstuff': html}
            tplvars.update(tpl_msg)
            return template('classic', tplvars)

        @self.app.route('/video/<filename:path>')
        def send_static_video(filename):
            return static_file(filename, root=self.tmp)
            # return "<script>javascript:history.back();</script>"

        @self.app.route('/localvideo/<filename:path>')
        def open_in_external_player(filename):
            file_path = os.path.join(self.tmp, filename)
            if which("xdg-open"):
                import subprocess
                subprocess.Popen(["xdg-open", file_path])
            else:
                os.startfile(file_path)

            return "<script>javascript:history.back();</script>"

        @self.app.route('/getsubtitles/<title>/<filename:path>')
        def showsubtitles(title, filename):
            opensubtitles = '<p>{} <a href="http://www.opensubtitles.org/search2/moviename-{}">' \
                            'Opensubtitles.org</a></p>'.format(_('Look for subtitles on'), title)

            fullpath = os.path.join(self.tmp, filename)
            hash = get_hash(fullpath)
            avail = Subtitle.search(hash)
            if avail:
                subdb = "<p>{}:</p>\n".format(_('Choose a language to download subtitle'))
                subdb += '<ul">\n'
                o = os.path.splitext(filename)[0] + '.srt'
                for l in avail:
                    subdb += '<li style="display:inline-block;">- <a href="/dlsub/{0}/{1}/{2}">{0}</a> -</li>\n'.format(
                        l, hash, o)

                subdb += '</ul>\n'
            else:
                subdb = '<p>{}</p>'.format(_('No subtitle available on subdb'))

            html = "<div>{} {}</div>".format(subdb, opensubtitles)

            tplvars = {'title': title, 'htmlstuff': html}
            tplvars.update(tpl_msg)
            return template('classic', tplvars)

        @self.app.route('/dlsub/<lang>/<hash>/<filename:path>')
        def dlsub(lang, hash, filename):
            if Subtitle.download(hash, lang, os.path.join(self.tmp, filename)):
                html = """<div>
                        <p>{}<br><a href="/video/{}">{}</a></p>
                        <p>{}</p>
                        </div>
                        """.format(_("Success: your subtitles are in the torrent folder"),
                                   filename,
                                   _("Click here if you want to download them on you computer"),
                                   _("You may now close this page"))
            else:
                html = "<div>{}</div>".format(_("Failed to download subtitles"))

            tplvars = {'title': _("Subtitles"), 'htmlstuff': html}
            tplvars.update(tpl_msg)
            return template('classic', tplvars)

        @self.app.route('/_admin')
        def configure():
            whoami = request.get_cookie("username", secret=self.secret)
            if whoami != self.admin:
                return '''
                    <p>{}</p>
                    <form action="/_admin" method="post">
                        {}: <input name="username" type="text" />
                        {}: <input name="password" type="password" />
                        <input value="{}" type="submit" />
                    </form>
                    '''.format(_("Only the administrator can see this page"),
                               _("Username"),
                               _("Password"),
                               _("Login"))
            else:
                conf = load_config()

                tplvars = {
                    'cache': get_cache_size(),
                    'ntor': len(self.dldic),
                    'startperc': conf['startperc'],
                    'uplimit': conf['uplimit'],
                    'downlimit': conf['downlimit'],
                    'search_engines': create_select_search_engine(conf['searchengine']),
                    'proxy_type': conf['proxy_type'],
                    'proxy_hostname': conf['proxy_hostname'],
                    'proxy_username': conf['proxy_username'],
                    'proxy_password': conf['proxy_password']
                    }
                tplvars.update(tpl_msg)
                return template('config', tplvars)

        @self.app.route('/_admin', method='POST')
        def do_login():
            username, password = request.forms.get('username'), request.forms.get('password')
            if username == self.admin and password == self.adminpw:
                response.set_cookie("username", username, secret=self.secret)
                redirect('/_admin')
            else:
                return '<p>{}</p>'.format(_('Go to hell, take the highway. You are not the administrator.'))

        @self.app.route('/_applyconfig', method='post')
        def applyconfig():
            config_list = ["searchengine", "startperc", "uplimit", "downlimit",
                           "proxy_type", "proxy_hostname", "proxy_password"]
            user_config = load_config()
            update_config = False

            for config_to_check in config_list:
                new_config = request.forms.get(config_to_check)

                if user_config[config_to_check] != new_config:
                    user_config[config_to_check] = new_config

                    if not update_config:
                        update_config = True

            if update_config:
                save_config(user_config)

            self.read_config()

            redirect('/_admin')

        @self.app.route('/_goodbye')
        def stop_server():
            whoami = request.get_cookie("username", secret=self.secret)
            if whoami == self.admin:
                htmlstuff = "<p>{}.</p><p>{}! ☺</p>".format(_("Don't Panic is now off"), _('See you soon'))
                title = "ARGH! 😵"

                tplvars = {'htmlstuff': htmlstuff, 'title': title}
                tplvars.update(tpl_msg)
                yield template('goodbye', tplvars)
                self.stop()
            else:
                redirect('/')

        @self.app.route('/_about')
        def show_about():
            htmlstuff = "<p>{}. ☺</p><br/><p>{}! ♥</p>".format(_("Dontpanic is a free (as in 'freedom') python "
                                                                 "application to look for any movie or serie and watch "
                                                                 "them in 'streaming'. It looks like Popcorn Time or "
                                                                 "Torrents Time, but doesn't depend of a centralized "
                                                                 "api"),
                                                               _("This has been made by two independent developers "
                                                                 "who love free software"))
            title = "Don't Panic"
            version = "{}: {}".format(_("Version"), progversion)

            tplvars = {'title': title, 'version': version, 'logo': pick_logo(), 'htmlstuff': htmlstuff}
            tplvars.update(tpl_msg)
            yield template('about', tplvars)

        @self.app.route('/_toggleep/<title>/')
        def toggle_episode(title):
            whoami = request.get_cookie("username", secret=self.secret)
            link = request.headers.get('Referer')
            with DontPanicDB() as database:
                database.toggle_in_wl(whoami, title)
            redirect(link)

        @self.app.route('/_removeinwatchlist/<title>/')
        def remove_in_watchlist(title):
            whoami = request.get_cookie("username", secret=self.secret)
            link = request.headers.get('Referer')
            with DontPanicDB() as database:
                database.delete_title_in_wl(whoami, title)
            redirect(link)

        @self.app.route('/_removeinrecent/<title>/')
        def remove_in_recent(title):
            whoami = request.get_cookie("username", secret=self.secret)
            link = request.headers.get('Referer')
            with DontPanicDB() as database:
                database.remove_in_recent(whoami, title)
            redirect(link)

    def read_config(self):
        conf = load_config()
        self.startperc = conf['startperc']  # percent to start a movie
        self.uplimit = conf['uplimit']
        self.downlimit = conf['downlimit']
        self.fav_sch_engine = conf['searchengine']
        self.proxy = conf['proxy_type']
        self.proxy_hostname = conf['proxy_hostname']
        self.proxy_username = conf['proxy_username']
        self.proxy_password = conf['proxy_password']

        return conf

    def open_in_browser(self):
        while not is_running():
            time.sleep(0.1)

        time.sleep(0.5)
        if self.magnet_as_arg:
            webbrowser.open("http://localhost:{}/stream/dontpanic/{}/0".format(port, self.magnet_as_arg))
        else:
            print("Open your browser at : http://localhost:{}".format(self.port))
            webbrowser.open("http://localhost:{}".format(self.port))

    def stop(self):
        if sys.platform == 'win32' and sys.version_info < (3, 2):
            """Kill for Win32 (https://docs.python.org/2/faq/windows.html#how-do-i-emulate-os-kill-in-windows)"""
            import ctypes
            kernel32 = ctypes.windll.kernel32
            handle = kernel32.OpenProcess(1, 0, os.getpid())
            kernel32.TerminateProcess(handle, 0)
        else:
            import signal
            os.kill(os.getpid(), signal.SIGKILL)

    def run(self):
        openurl = Thread(target=self.open_in_browser)
        openurl.daemon = True
        openurl.start()
        # Warning for the debug: http://bottlepy.org/docs/dev/tutorial.html#tutorial-debugging
        # We can use it on the development branch but for the new release, this is recommend to disable it
        #self.app.run(host=self.host, port=self.port, debug=True, quiet=True, adapter="auto")
        self.app.run(host=self.host, port=self.port, debug=False, quiet=True, adapter="auto")

    def _add_when_ready(self, torsession, user, title, magnet, isserie):
        while not torsession.handle:
            time.sleep(1)

        while torsession.get_state() != "downloading metadata":
            time.sleep(1)

        with DontPanicDB() as db:
            if db.is_user_in(user):
                logger.info("add {} to watchlist".format(title))
                db.add2watchlist(user, title, magnet, isserie)

    def _add_to_recent_search(self, user, title, year, poster, isserie):
        with DontPanicDB() as db:
            if db.is_user_in(user):
                logger.info("add {} to recent research".format(title))
                db.add2recent(user, title, year, poster, isserie)

    def _clean_torlist(self):
        """Remove every finished torrent in self.dldic"""
        for i, t in self.dldic.items():
            if t.get_state() in ['finished', 'seeding']:
                h = t.handle
                session = t.session
                session.remove_torrent(h)
                self.dldic.pop(i)
                del session


