# -*- coding: utf-8 -*-

import re
import socket
import struct
import sys
import time

from os import makedirs
from os.path import exists, join
from select import select

from pyload.plugin.Hoster import Hoster
from pyload.utils import fs_join


class Xdcc(Hoster):
    __name    = "Xdcc"
    __type    = "hoster"
    __version = "0.32"

    __config = [("nick", "str", "Nickname", "pyload"),
                ("ident", "str", "Ident", "pyloadident"),
                ("realname", "str", "Realname", "pyloadreal")]

    __description = """Download from IRC XDCC bot"""
    __license     = "GPLv3"
    __authors     = [("jeix", "jeix@hasnomail.com")]


    def setup(self):
        self.debug = 0  # 0,1,2
        self.timeout = 30
        self.multiDL = False


    def process(self, pyfile):
        # change request type
        self.req = pyfile.m.core.requestFactory.getRequest(self.__name, type="XDCC")

        self.pyfile = pyfile
        for _i in xrange(0, 3):
            try:
                nmn = self.doDownload(pyfile.url)
                self.logDebug("Download of %s finished." % nmn)
                return
            except socket.error, e:
                if hasattr(e, "errno"):
                    errno = e.errno
                else:
                    errno = e.args[0]

                if errno == 10054:
                    self.logDebug("Server blocked our ip, retry in 5 min")
                    self.setWait(300)
                    self.wait()
                    continue

                self.fail(_("Failed due to socket errors. Code: %d") % errno)

        self.fail(_("Server blocked our ip, retry again later manually"))


    def doDownload(self, url):
        self.pyfile.setStatus("waiting")  # real link

        m = re.match(r'xdcc://(.*?)/#?(.*?)/(.*?)/#?(\d+)/?', url)
        server = m.group(1)
        chan = m.group(2)
        bot = m.group(3)
        pack = m.group(4)
        nick = self.getConfig('nick')
        ident = self.getConfig('ident')
        real = self.getConfig('realname')

        temp = server.split(':')
        ln = len(temp)
        if ln == 2:
            host, port = temp
        elif ln == 1:
            host, port = temp[0], 6667
        else:
            self.fail(_("Invalid hostname for IRC Server: %s") % server)

        #######################
        # CONNECT TO IRC AND IDLE FOR REAL LINK
        dl_time = time.time()

        sock = socket.socket()
        sock.connect((host, int(port)))
        if nick == "pyload":
            nick = "pyload-%d" % (time.time() % 1000)  # last 3 digits
        sock.send("NICK %s\r\n" % nick)
        sock.send("USER %s %s bla :%s\r\n" % (ident, host, real))

        self.setWait(3)
        self.wait()

        sock.send("JOIN #%s\r\n" % chan)
        sock.send("PRIVMSG %s :xdcc send #%s\r\n" % (bot, pack))

        # IRC recv loop
        readbuffer = ""
        done = False
        retry = None
        m = None
        while True:

            # done is set if we got our real link
            if done:
                break

            if retry:
                if time.time() > retry:
                    retry = None
                    dl_time = time.time()
                    sock.send("PRIVMSG %s :xdcc send #%s\r\n" % (bot, pack))

            else:
                if (dl_time + self.timeout) < time.time():  # todo: add in config
                    sock.send("QUIT :byebye\r\n")
                    sock.close()
                    self.fail(_("XDCC Bot did not answer"))

            fdset = select([sock], [], [], 0)
            if sock not in fdset[0]:
                continue

            readbuffer += sock.recv(1024)
            temp = readbuffer.split("\n")
            readbuffer = temp.pop()

            for line in temp:
                if self.debug is 2:
                    print "*> " + unicode(line, errors='ignore')
                line = line.rstrip()
                first = line.split()

                if first[0] == "PING":
                    sock.send("PONG %s\r\n" % first[1])

                if first[0] == "ERROR":
                    self.fail(_("IRC-Error: %s") % line)

                msg = line.split(None, 3)
                if len(msg) != 4:
                    continue

                msg = {
                    "origin": msg[0][1:],
                    "action": msg[1],
                    "target": msg[2],
                    "text": msg[3][1:]
                }

                if nick == msg['target'][0:len(nick)] and "PRIVMSG" == msg['action']:
                    if msg['text'] == "\x01VERSION\x01":
                        self.logDebug("Sending CTCP VERSION")
                        sock.send("NOTICE %s :%s\r\n" % (msg['origin'], "pyLoad! IRC Interface"))
                    elif msg['text'] == "\x01TIME\x01":
                        self.logDebug("Sending CTCP TIME")
                        sock.send("NOTICE %s :%d\r\n" % (msg['origin'], time.time()))
                    elif msg['text'] == "\x01LAG\x01":
                        pass  # don't know how to answer

                if not (bot == msg['origin'][0:len(bot)]
                        and nick == msg['target'][0:len(nick)]
                        and msg['action'] in ("PRIVMSG", "NOTICE")):
                    continue

                if self.debug is 1:
                    print "%s: %s" % (msg['origin'], msg['text'])

                if "You already requested that pack" in msg['text']:
                    retry = time.time() + 300

                if "you must be on a known channel to request a pack" in msg['text']:
                    self.fail(_("Wrong channel"))

                m = re.match('\x01DCC SEND (.*?) (\d+) (\d+)(?: (\d+))?\x01', msg['text'])
                if m:
                    done = True

        # get connection data
        ip = socket.inet_ntoa(struct.pack('L', socket.ntohl(int(m.group(2)))))
        port = int(m.group(3))
        packname = m.group(1)

        if len(m.groups()) > 3:
            self.req.filesize = int(m.group(4))

        self.pyfile.name = packname

        download_folder = self.config['general']['download_folder']
        filename = fs_join(download_folder, packname)

        self.logInfo(_("Downloading %s from %s:%d") % (packname, ip, port))

        self.pyfile.setStatus("downloading")
        newname = self.req.download(ip, port, filename, sock, self.pyfile.setProgress)
        if newname and newname != filename:
            self.logInfo(_("%(name)s saved as %(newname)s") % {"name": self.pyfile.name, "newname": newname})
            filename = newname

        # kill IRC socket
        # sock.send("QUIT :byebye\r\n")
        sock.close()

        self.lastDownload = filename
        return self.lastDownload