import collections
import time
import pygooglechart


DEFAULT_BUCKETS = [
    2, 5,
    10, 20, 50,
    100, 200, 500,
    ]


def _percent(counts):
    tot = float(sum(counts))
    return [(x, 100 * x / tot) for x in counts]


class LatencyProfilerMiddleware(object):

    def __init__(self, app, urls=None, buckets=None):
        self._app = app
        self._buckets = buckets or DEFAULT_BUCKETS
        self._n_buckets = len(self._buckets) + 1
        self._urls = sorted(urls or [],
                            key=lambda x: len(x), reverse=True)
        def _build_buckets():
            return [0] * self._n_buckets
        self._data = collections.defaultdict(_build_buckets)

    def __call__(self, environ, start_response):
        start = time.time()
        url = environ['PATH_INFO']
        if url.endswith('/__latency__'):
            return self.handler(environ, start_response)

        try:
            return self._app(environ, start_response)
        finally:
            elapsed_ms = 1000 * (time.time() - start)
            for url_prefix in self._urls:
                if url.startswith(url_prefix):
                    url = url_prefix
                    break
            for bkt, threshold in enumerate(self._buckets):
                if elapsed_ms < threshold:
                    break
            else:
                bkt = self._n_buckets - 1
            self._data[url][bkt] += 1

    def handler(self, environ, start_response):
        headers = [('Content-type', 'text/html')]
        start_response('200 OK', headers)

        result = [
            '<!doctype html>\n'
            '<html><head><title>Latency Breakdown</title>\n'
            '<style type="text/css">\n'
            'body { background: white; font-family: sans-serif; }\n'
            'tbody td { text-align: left; padding-right: 10px; }\n'
            'thead th { font-weight: bold; text-align: left; color: white; '
            'background-color: #666; }\n'
            'td.url { font-weight: bold; border-right: 1px solid #666; }\n'
            'tbody tr { border-bottom: 1px solid #ccc; }\n'
            '</style></head><body>\n'
            '<h3>Latency report by URL</h3>\n'
            '<table cellspacing="0" cellpadding="0" border="0"><thead><tr>'
            '<th rowspan="2">URL</th>',
            '<th rowspan="2">Total</th>',
            '<th colspan="%d">Latencies (ms)</th>' % self._n_buckets,
            '<th rowspan="2"></th>',
            '</tr><tr>'
            ]

        for ms in self._buckets:
            result.append('<th>&lt;%d</th>' % ms)
        result.append('<th>&gt;%d</th>' % ms)
        result.append('</tr></thead><tbody>')

        for url in sorted(self._data.keys()):
            values = self._data[url]
            result.append('<tr><td class="url">%s</td><td>%d</td>' % (
                    url, sum(values)))
            chart = pygooglechart.SparkLineChart(80, 25)
            chart.set_data(values)
            for count, pct in _percent(values):
                result.append('<td>%d (%.2g%%)</td>' % (count, pct))
            result.append('<td><img src="%s" width="80" height="25"></td>' % 
                          chart.get_url())
            result.append('</tr>')

        result.append('</tbody></table>')
        result.append('</body></html>\n')
        return result