#!/usr/bin/env python
# License: GPLv3 Copyright: 2008, Kovid Goyal kovid@kovidgoyal.net

"""
Miscelleaneous utilities.
"""

from time import time

from polyglot.builtins import as_bytes


def join_with_timeout(q, timeout=2):
    """Join the queue q with a specified timeout. Blocks until all tasks on
    the queue are done or times out with a runtime error."""
    q.all_tasks_done.acquire()
    try:
        endtime = time() + timeout
        while q.unfinished_tasks:
            remaining = endtime - time()
            if remaining <= 0.0:
                raise RuntimeError('Waiting for queue to clear timed out')
            q.all_tasks_done.wait(remaining)
    finally:
        q.all_tasks_done.release()


def unpickle_binary_string(data):
    # Maintains compatibility with python's pickle module protocol version 2
    import struct

    PROTO, SHORT_BINSTRING, BINSTRING = b'\x80', b'U', b'T'
    if data.startswith(PROTO + b'\x02'):
        offset = 2
        which = data[offset : offset + 1]
        offset += 1
        if which == BINSTRING:
            (sz,) = struct.unpack_from('<i', data, offset)
            offset += struct.calcsize('<i')
        elif which == SHORT_BINSTRING:
            sz = ord(data[offset : offset + 1])
            offset += 1
        else:
            return
        return data[offset : offset + sz]


def pickle_binary_string(data):
    # Maintains compatibility with python's pickle module protocol version 2
    import struct

    PROTO, STOP, BINSTRING = b'\x80', b'.', b'T'
    data = as_bytes(data)
    return PROTO + b'\x02' + BINSTRING + struct.pack(b'<i', len(data)) + data + STOP


def kill_parent_if_needed(parent_process_handle: int, timeout: float = 1.0, exit_code: int = 0) -> None:
    import ctypes

    WAIT_TIMEOUT = 0x00000102

    kernel32 = ctypes.windll.kernel32
    try:
        if kernel32.WaitForSingleObject(parent_process_handle, int(timeout * 1000)) == WAIT_TIMEOUT:
            kernel32.TerminateProcess(parent_process_handle, exit_code)
    finally:
        kernel32.CloseHandle(parent_process_handle)
