import time
import threading

def sleep(sec):
    """High-precision sleep function"""
    require = time.perf_counter_ns() + sec * 1000000000
    while time.perf_counter_ns() < require:
        time.sleep(0)

def waitDo(func, sec):
    """Waiting and running function in another thread, perfect for timings"""
    sleep(sec)
    threading.Thread(target=func, daemon=True).start()

def schedule(func, sec, daemon=True):
    """Schedule an action after a specified time. Doesn't block the thread"""
    working = True
    do = True
    require = time.perf_counter_ns() + sec * 1000000000
    def thread():
        nonlocal working, do, require
        while time.perf_counter_ns() < require and working:
            time.sleep(0)
        if do:
            func()
    class ManageSchedule:
        @staticmethod
        def cancel():
            """Cancel scheduled action"""
            nonlocal working, do
            do = False
            working = False

        @staticmethod
        def skip():
            """Do scheduled action now"""
            nonlocal working
            working = False

        @staticmethod
        def setTime(sec):
            """Change schedule time"""
            nonlocal require
            require = time.perf_counter_ns() + sec * 1000000000

        @staticmethod
        def remaining():
            """Get remaining time"""
            nonlocal require
            return (require - time.perf_counter_ns()) / 1000000000

    threading.Thread(target=thread, daemon=daemon).start()
    return ManageSchedule

def createPoint():
    """Creates time point and returns manage functions"""
    class ManagePoint:
        _pointNs = time.perf_counter_ns()
        _point = time.perf_counter()
        _pointTime = time.time()

        @staticmethod
        def getPoint():
            """Returns UNIX datestamp point create date"""
            return ManagePoint._pointTime

        @staticmethod
        def placePoint():
            """Changes point create time to current"""
            ManagePoint.pointTime = time.time()
            ManagePoint.pointNs = time.perf_counter_ns()
            ManagePoint.point = time.perf_counter()

        @staticmethod
        def elapsed():
            """Return diff of current time and point create time in seconds"""
            return time.perf_counter() - ManagePoint._point

        @staticmethod
        def elapsedFloat():
            """Return diff of current time and point create time in float seconds"""
            return (time.perf_counter_ns() - ManagePoint._pointNs) / 1000000000

        @staticmethod
        def elapsedNs():
            """Returns diff of current time and point create time in nanoseconds"""
            return time.perf_counter_ns() - ManagePoint._pointNs

    return ManagePoint