#
# Original file from BitTorrent-5.3-GPL.tar.gz
# Copyright (C) Bram Cohen
#
# Modifications for use in Deluge:
# Copyright (C) 2007 Andrew Resch <andrewresch@gmail.com>
#
# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
# the additional special exception to link portions of this program with the OpenSSL library.
# See LICENSE for more details.
#

import logging
import os.path
import time
from hashlib import sha1 as sha

import deluge.component as component
from deluge.bencode import bencode
from deluge.common import utf8_encode_structure
from deluge.event import CreateTorrentProgressEvent

log = logging.getLogger(__name__)

ignore = ['core', 'CVS', 'Thumbs.db', 'desktop.ini']

noncharacter_translate = {}
for i in range(0xD800, 0xE000):
    noncharacter_translate[i] = ord('-')
for i in range(0xFDD0, 0xFDF0):
    noncharacter_translate[i] = ord('-')
for i in (0xFFFE, 0xFFFF):
    noncharacter_translate[i] = ord('-')


def gmtime():
    return time.mktime(time.gmtime())


def dummy(*v):
    pass


class RemoteFileProgress:
    def __init__(self, session_id):
        self.session_id = session_id

    def __call__(self, piece_count, num_pieces):
        component.get('RPCServer').emit_event_for_session_id(
            self.session_id, CreateTorrentProgressEvent(piece_count, num_pieces)
        )


def make_meta_file(
    path,
    url,
    piece_length,
    progress=None,
    title=None,
    comment=None,
    safe=None,
    content_type=None,
    target=None,
    webseeds=None,
    name=None,
    private=False,
    created_by=None,
    trackers=None,
):
    data = {'creation date': int(gmtime())}
    if url:
        data['announce'] = url.strip()
    a, b = os.path.split(path)
    if not target:
        if b == '':
            f = a + '.torrent'
        else:
            f = os.path.join(a, b + '.torrent')
    else:
        f = target

    if progress is None:
        progress = dummy
        try:
            session_id = component.get('RPCServer').get_session_id()
        except KeyError:
            pass
        else:
            if session_id:
                progress = RemoteFileProgress(session_id)

    info = makeinfo(path, piece_length, progress, name, content_type, private)

    # check_info(info)
    data['info'] = info
    if title:
        data['title'] = title.encode('utf8')
    if comment:
        data['comment'] = comment.encode('utf8')
    if safe:
        data['safe'] = safe.encode('utf8')

    httpseeds = []
    url_list = []

    if webseeds:
        for webseed in webseeds:
            if webseed.endswith('.php'):
                httpseeds.append(webseed)
            else:
                url_list.append(webseed)

    if url_list:
        data['url-list'] = url_list
    if httpseeds:
        data['httpseeds'] = httpseeds
    if created_by:
        data['created by'] = created_by.encode('utf8')

    if trackers and (len(trackers[0]) > 1 or len(trackers) > 1):
        data['announce-list'] = trackers

    data['encoding'] = 'UTF-8'
    with open(f, 'wb') as file_:
        file_.write(bencode(utf8_encode_structure(data)))


def calcsize(path):
    total = 0
    for s in subfiles(os.path.abspath(path)):
        total += os.path.getsize(s[1])
    return total


def makeinfo(path, piece_length, progress, name=None, content_type=None, private=False):
    # HEREDAVE. If path is directory, how do we assign content type?
    path = os.path.abspath(path)
    piece_count = 0
    if os.path.isdir(path):
        subs = sorted(subfiles(path))
        pieces = []
        sh = sha()
        done = 0
        fs = []
        totalsize = 0.0
        totalhashed = 0
        for p, f in subs:
            totalsize += os.path.getsize(f)
        if totalsize >= piece_length:
            import math

            num_pieces = math.ceil(totalsize / piece_length)
        else:
            num_pieces = 1

        for p, f in subs:
            pos = 0
            size = os.path.getsize(f)
            p2 = [n.encode('utf8') for n in p]
            if content_type:
                fs.append(
                    {'length': size, 'path': p2, 'content_type': content_type}
                )  # HEREDAVE. bad for batch!
            else:
                fs.append({'length': size, 'path': p2})
            with open(f, 'rb') as file_:
                while pos < size:
                    a = min(size - pos, piece_length - done)
                    sh.update(file_.read(a))
                    done += a
                    pos += a
                    totalhashed += a

                    if done == piece_length:
                        pieces.append(sh.digest())
                        piece_count += 1
                        done = 0
                        sh = sha()
                        progress(piece_count, num_pieces)
        if done > 0:
            pieces.append(sh.digest())
            piece_count += 1
            progress(piece_count, num_pieces)

        if not name:
            name = os.path.split(path)[1]

        return {
            'pieces': b''.join(pieces),
            'piece length': piece_length,
            'files': fs,
            'name': name.encode('utf8'),
            'private': private,
        }
    else:
        size = os.path.getsize(path)
        if size >= piece_length:
            num_pieces = size // piece_length
        else:
            num_pieces = 1

        pieces = []
        p = 0
        with open(path, 'rb') as _file:
            while p < size:
                x = _file.read(min(piece_length, size - p))
                pieces.append(sha(x).digest())
                piece_count += 1
                p += piece_length
                if p > size:
                    p = size
                progress(piece_count, num_pieces)
        name = os.path.split(path)[1].encode('utf8')
        if content_type is not None:
            return {
                'pieces': b''.join(pieces),
                'piece length': piece_length,
                'length': size,
                'name': name,
                'content_type': content_type,
                'private': private,
            }
        return {
            'pieces': b''.join(pieces),
            'piece length': piece_length,
            'length': size,
            'name': name,
            'private': private,
        }


def subfiles(d):
    r = []
    stack = [([], d)]
    while stack:
        p, n = stack.pop()
        if os.path.isdir(n):
            for s in os.listdir(n):
                if s not in ignore and not s.startswith('.'):
                    stack.append((p + [s], os.path.join(n, s)))
        else:
            r.append((p, n))
    return r
