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

from os.path import dirname
from logging import log, DEBUG
from hashlib import md5
from time import time
from shutil import move

from nose.tools import nottest

from helper.Stubs import Core
from helper.parser import parse_config
from helper.PluginTester import PluginTester

from pyload.datatypes.PyFile import PyFile, statusMap
from pyload.plugins.Base import Fail
from pyload.utils import accumulate
from pyload.utils.fs import save_join, join, exists, listdir, remove, stat

DL_DIR = join("Downloads", "tmp")


class HosterPluginTester(PluginTester):
    files = {}

    def setUp(self):
        PluginTester.setUp(self)
        for f in self.files:
            if exists(save_join(DL_DIR, f)): remove(save_join(DL_DIR, f))

        # folder for reports
        report = join("tmp", self.__class__.__name__)
        if exists(report):
            for f in listdir(report):
                remove(join(report, f))


    @nottest
    def test_plugin(self, name, url, status):
        # Print to stdout to see whats going on
        print "%s: %s, %s" % (name, url.encode("utf8"), status)
        log(DEBUG, "%s: %s, %s", name, url.encode("utf8"), status)

        # url and plugin should be only important thing
        pyfile = PyFile(self.core, -1, url, url, 0, 0, 0, 0, url, name, "", 0, 0, 0, 0)
        pyfile.initPlugin()

        self.thread.pyfile = pyfile
        self.thread.plugin = pyfile.plugin

        try:
            a = time()
            pyfile.plugin.preprocessing(self.thread)

            log(DEBUG, "downloading took %ds" % (time() - a))
            log(DEBUG, "size %d kb" % (pyfile.size / 1024))

            if status == "offline":
                raise Exception("No offline Exception raised.")

            if pyfile.name not in self.files:
                raise Exception("Filename %s not recognized." % pyfile.name)

            if not exists(save_join(DL_DIR, pyfile.name)):
                raise Exception("File %s does not exists." % pyfile.name)

            hash = md5()
            f = open(save_join(DL_DIR, pyfile.name), "rb")
            while True:
                buf = f.read(4096)
                if not buf: break
                hash.update(buf)
            f.close()

            if hash.hexdigest() != self.files[pyfile.name]:
                log(DEBUG, "Hash is %s" % hash.hexdigest())

                size = stat(f.name).st_size
                if size < 1024 * 1024 * 10: # 10MB
                    # Copy for debug report
                    log(DEBUG, "Downloaded file copied to report")
                    move(f.name, join("tmp", plugin, f.name))

                raise Exception("Hash does not match.")

        except Exception, e:
            if isinstance(e, Fail) and status == "failed":
                pass
            elif isinstance(e, Fail) and status == "offline" and e.message == "offline":
                pass
            else:
                raise

# setup methods
c = Core()

sections = parse_config(join(dirname(__file__), "hosterlinks.txt"))

for f in sections["files"]:
    name, hash = f.rsplit(" ", 1)
    HosterPluginTester.files[name] = str(hash)

del sections["files"]

urls = []
status = {}

for k, v in sections.iteritems():
    if k not in statusMap:
        print "Unknown status %s" % k
    for url in v:
        urls.append(url)
        status[url] = k

hoster, c = c.pluginManager.parseUrls(urls)

plugins = accumulate(hoster)
for plugin, urls in plugins.iteritems():
    # closure functions to retain local scope
    def meta_class(plugin):
        class _testerClass(HosterPluginTester):
            pass

        _testerClass.__name__ = plugin
        return _testerClass

    _testerClass = meta_class(plugin)

    for i, url in enumerate(urls):
        def meta(__plugin, url, status, sig):
            def _test(self):
                self.test_plugin(__plugin, url, status)

            _test.func_name = sig
            return _test

        tmp_status = status.get(url)
        if tmp_status != "online":
            sig = "test_LINK%d_%s" % (i, tmp_status)
        else:
            sig = "test_LINK%d" % i

        # set test method
        setattr(_testerClass, sig, meta(plugin, url, tmp_status, sig))

    #register class
    locals()[plugin] = _testerClass
    # remove from locals, or tested twice
    del _testerClass