# -*- coding: utf-8 -*-
"""
    profiling.sampling.samplers
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
from __future__ import absolute_import
import functools
import signal
import sys
import threading
import time
import weakref

import six.moves._thread as _thread

from ..utils import Runnable


__all__ = ['Sampler', 'ItimerSampler', 'ThreadSampler']


DEFAULT_INTERVAL = 1e-3  # 1ms


class Sampler(Runnable):
    """The base class for samplers."""

    #: Sampling interval.
    interval = DEFAULT_INTERVAL

    def __init__(self, interval=DEFAULT_INTERVAL):
        self.interval = interval

    @staticmethod
    def current_frames():
        return sys._current_frames()


class ItimerSampler(Sampler):

    # keep the Id of the math thread.
    main_thread_id = _thread.get_ident()

    def handle_signal(self, profiler, signum, frame):
        frames = self.current_frames()
        # replace frame of the main thread with the interrupted frame.
        frames[self.main_thread_id] = frame
        for frame_ in frames.values():
            profiler.sample(frame_)

    def run(self, profiler):
        interval = self.interval
        handle = functools.partial(self.handle_signal, weakref.proxy(profiler))
        prev_handler = signal.signal(signal.SIGPROF, handle)
        prev_itimer = signal.setitimer(signal.ITIMER_PROF, interval, interval)
        yield
        signal.setitimer(signal.ITIMER_PROF, *prev_itimer)
        signal.signal(signal.SIGPROF, prev_handler)


class ThreadSampler(Sampler):

    def sample_periodically(self, profiler):
        sampling_thread_id = _thread.get_ident()
        while profiler.is_running():
            time.sleep(self.interval)
            frames = self.current_frames()
            # remove here the sampling thread.
            del frames[sampling_thread_id]
            for frame in frames.values():
                profiler.sample(frame)

    def run(self, profiler):
        t = threading.Thread(target=self.sample_periodically, args=(profiler,))
        t.start()
        yield
        t.join()

@@ -324,21 +324,22 @@
 ler', 'T
-hread
+racing
 Sampler'
@@ -1478,21 +1478,22 @@
 %0Aclass T
-hread
+racing
 Sampler(
@@ -1511,158 +1511,135 @@
     
-def 
 sample
-_periodically(self, profiler):%0A        sampling_thread_id = _thread.get_ident()%0A        while profiler.is_running():%0A            time.sleep(
+d_at = 0%0A%0A    def _profile(self, profiler, frame, event, arg):%0A        t = time.clock()%0A        if t - self.sampled_at %3C 
 self
@@ -1639,33 +1639,33 @@
  %3C self.interval
-)
+:
 %0A            fra
@@ -1665,133 +1665,126 @@
     
-frames = self.current_frames()%0A            # remove here the sampling thread.%0A            del frames%5Bsampling_thread_id%5D%0A    
+return%0A        self.sampled_at = t%0A        frames = self.current_frames()%0A        frames%5B_thread.get_ident()%5D = frame%0A
     
@@ -1809,36 +1809,32 @@
 rames.values():%0A
-    
             prof
@@ -1894,125 +1894,205 @@
     
-t = threading.Thread(target=self.sample_periodically, args=(profiler,))%0A        t.start()%0A        yield%0A        t.join(
+profile = functools.partial(self._profile, profiler)%0A        sys.setprofile(profile)%0A        threading.setprofile(profile)%0A        yield%0A        threading.setprofile(None)%0A        sys.setprofile(None
 )%0A

Remove ThreadSampler, Implement TracingSampler