import asyncio
import os
import signal
import threading
import traceback
import sys

PYMPLER_ENABLED = False

if PYMPLER_ENABLED:
    try:
        import pympler
        import pympler.muppy
        import pympler.summary
        import pympler.tracker
    except ImportError:
        pympler = None
else:
    pympler = None
try:
    import objgraph
except ImportError:
    objgraph = None

from cloudbot import hook
from cloudbot.util import web


def get_name(thread_id):
    current_thread = threading.current_thread()
    if thread_id == current_thread._ident:
        is_current = True
        thread = current_thread
    else:
        is_current = False
        thread = threading._active.get(thread_id)

    if thread is not None:
        if thread.name is not None:
            name = thread.name
        else:
            name = "Unnamed thread"
    else:
        name = "Unknown thread"

    name = "{} ({})".format(name, thread_id)
    if is_current:
        name += " - Current thread"

    return name


def get_thread_dump():
    code = []
    threads = [(get_name(thread_id), traceback.extract_stack(stack))
               for thread_id, stack in sys._current_frames().items()]
    for thread_name, stack in threads:
        code.append("# {}".format(thread_name))
        for filename, line_num, name, line in stack:
            code.append("{}:{} - {}".format(filename, line_num, name))
            if line:
                code.append("    {}".format(line.strip()))
        code.append("")  # new line
    return web.paste("\n".join(code), ext='txt')


@asyncio.coroutine
@hook.command("threaddump", autohelp=False, permissions=["botcontrol"])
def threaddump_command():
    return get_thread_dump()


@hook.command("objtypes", autohelp=False, permissions=["botcontrol"])
def show_types():
    if objgraph is None:
        return "objgraph not installed"
    objgraph.show_most_common_types(limit=20)
    return "Printed to console"


@hook.command("objgrowth", autohelp=False, permissions=["botcontrol"])
def show_growth():
    if objgraph is None:
        return "objgraph not installed"
    objgraph.show_growth(limit=10)
    return "Printed to console"


@hook.command("pymsummary", autohelp=False, permissions=["botcontrol"])
def pympler_summary():
    if pympler is None:
        return "pympler not installed / not enabled"
    all_objects = pympler.muppy.get_objects()
    summ = pympler.summary.summarize(all_objects)
    pympler.summary.print_(summ)
    return "Printed to console"


@hook.on_start()
def create_tracker():
    if pympler is None:
        return
    global tr
    tr = pympler.tracker.SummaryTracker()


@hook.command("pymdiff", autohelp=False, permissions=["botcontrol"])
def pympler_diff():
    if pympler is None:
        return "pympler not installed / not enabled"
    tr.print_diff()
    return "Printed to console"

# # Provide an easy way to get a threaddump, by using SIGUSR1 (only on POSIX systems)
if os.name == "posix":
    # The handler is called with two arguments: the signal number and the current stack frame
    # These parameters should NOT be removed
    def debug(sig, frame):
        print(get_thread_dump())

    signal.signal(signal.SIGUSR1, debug)  # Register handler