# -*- coding: utf-8 -*-
"""
Created on Aug 8, 2013

@author: noob
"""

from .plots_base import TimelinePlot
from collections import OrderedDict
from common.util.decorators import Memoize
import logging


class QuantilesTimelinePlot(TimelinePlot):
    title = u'Quantiles'
    graphs = 'avg', '50', '75', '80', '85', '90', '95', '98', '99', '100'

    @staticmethod
    def color_mapping(quantile):
        color_map = {
            'avg': '#303030',
            '50': '#f85750',
            '75': 'Coral',
            '80': 'DarkOrange',
            '85': 'Orange',
            '90': 'gold',
            '95': '#b8e13d',
            '98': '#66af5f',
            '99': '#7cb3f1',
            '100': '#b2b8c8',
        }
        try:
            color = color_map[quantile]
            return color
        except KeyError:
            logging.warning('Unexpected quantile: %s', quantile)
            return None

    @property
    @Memoize
    def quantiles_data(self):
        """
        retrieves monitoring data from database
        """
        sql = '''
            select mq50, mq75, mq80, mq85, mq90, mq95, mq98, mq99, mq100 from 
            (
            select intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.rt_microsecond_details_buffer
            where job_id=%(job)s
            and job_date = toDate(%(job_date)s)
            and tag = ''
            and time > toDateTime(%(latest_second)s) 
            group by t
            order by t
            limit %(interval)s
            ) all left join
            (
            select 
            round(max(q50), 3) as mq50,
            round(max(q75), 3) as mq75,
            round(max(q80), 3) as mq80,
            round(max(q85), 3) as mq85,
            round(max(q90), 3) as mq90,
            round(max(q95), 3) as mq95,
            round(max(q98), 3) as mq98,
            round(max(q99), 3) as mq99,
            round(max(q100), 3) as mq100,
            intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.rt_quantiles_buffer
            where job_id=%(job)s
            and job_date = toDate(%(job_date)s)
            '''
        if self.job_obj.multitag and self.tag:
            sql += 'and tag in (%(cases_with_tag)s) '
        else:
            sql += '''and tag='%(tag)s'  '''
        sql += '''
            and time > toDateTime(%(latest_second)s) 
            group by t
            order by t
            limit %(interval)s
            )
            using t'''
        query_params = self.job_obj.basic_query_params.copy()
        query_params.update({
            'interval': self.interval,
            'latest_second': self.latest_second,
            'compress_ratio': self.compress_ratio,
            'cases_with_tag': ','.join(
                ["'" + case + "'" for case in self.job_obj.cases if self.tag in case.split('|')]),
            'tag': self.tag,
        })
        fetched_data = self.ch_client.select(sql, query_params=query_params)
        transponed_data = zip(*fetched_data)
        quantiles = ('50', '75', '80', '85', '90', '95', '98', '99', '100')
        data = {quantile: transponed_data[quantiles.index(quantile)] if transponed_data else [] for quantile in
                quantiles}
        return data

    @property
    def avg_data(self):
        """
        retrieves monitoring data from database
        """
        sql = '''
            select data from 
            (
            select intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.rt_microsecond_details_buffer
            where job_id=%(job)s
            and tag = ''
            and time > toDateTime(%(latest_second)s) 
            and job_date = toDate(%(job_date)s)
            group by t
            order by t
            limit %(interval)s
            ) all left join
            (
            select 
            round(avg(toFloat64((connect_time_sum + send_time_sum + latency_sum + receive_time_sum)/1000/resps)), 3) as data, 
            intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.rt_microsecond_details_buffer
            where job_id=%(job)s
        '''
        if self.job_obj.multitag and self.tag:
            sql += 'and tag in (%(cases_with_tag)s) '
        else:
            sql += '''and tag='%(tag)s'  '''
        sql += '''
                and time > toDateTime(%(latest_second)s) 
                and job_date = toDate(%(job_date)s)
                group by t
                order by t
                limit %(interval)s
                )
                using t'''
        data = {'avg': [v[0] for v in self.ch_client.select(sql, query_params=self.query_params)]}
        return data

    @property
    @Memoize
    def data(self):
        self.quantiles_data.update(self.avg_data)
        self.quantiles_data[self.scheme_type['type']] = {
            'values': self.scheme_data,
            'zIndex': 2,
            'title': self.scheme_type['type'],
            'name': self.scheme_type['type'],
            'color': self.scheme_type['color'],
            'yAxis': 0,
        }
        return self.quantiles_data

    @property
    @Memoize
    def chunk(self):
        chunk = OrderedDict()
        chunk[self.scheme_type['type']] = {'values': self.scheme_data,
                                           'name': self.scheme_type['type'],
                                           'type': 'line',
                                           'color': self.scheme_type['color'],
                                           }
        for graph in ('100', '99'):
            chunk[graph + '%'] = {'values': self.data[graph],
                                  'name': str(graph) + '%',
                                  'type': 'line',
                                  'visible': False,
                                  'color': self.color_mapping(graph),
                                  'yAxis': 1,
                                  }
        for graph in ('98', '95', '90', '85', '80', '75', '50'):
            chunk[graph + '%'] = {'values': self.data[graph],
                                  'name': str(graph) + '%',
                                  'type': 'area',
                                  'color': self.color_mapping(graph),
                                  'yAxis': 1,
                                  }
        chunk['avg'] = {'values': self.data['avg'],
                        'name': 'avg',
                        'type': 'line',
                        'visible': False,
                        'color': self.color_mapping('avg'),
                        'yAxis': 1,
                        }
        return chunk

    @property
    def yaxis(self):
        return [
            {
                'label': self.scheme_type['type'],
                'overrides': {'gridLineWidth': 0, 'min': 0, 'allowDecimals': False},
                'position': 'right',
                'type': 'line',
            },
            {
                'label': 'ms',
                'overrides': {'min': 0, 'allowDecimals': False},
                'type': 'area',
                'position': 'left',
            },
        ]


class TimesDistTimelinePlot(TimelinePlot):
    title = u'Response time distribution'

    @staticmethod
    def color_mapping(interval):
        color_map = {
            u'0-0.\u2089\u2089\u2089': '#66af5f',  # подстрочные девятки
            u'1-9': '#b8e13d',
            u'10-99': '#ffd43f',  # '#e9f66e',
            u'100-999': '#fca43f',
            u'1000+': '#f85750',
        }
        try:
            color = color_map[interval]
            return color
        except KeyError:
            logging.warning('Unexpected interval: %s', interval)
            return None

    @property
    def graphs(self):
        return u'0-0.\u2089\u2089\u2089', u'1-9', u'10-99', u'100-999', u'1000+'

    @property
    @Memoize
    def chunk(self):
        chunk = OrderedDict()
        chunk[self.scheme_type['type']] = {'values': self.scheme_data,
                                           'name': self.scheme_type['type'],
                                           'type': 'line',
                                           'color': self.scheme_type['color'],
                                           'yAxis': 0 if self.scheme_type['type'] == 'rps' else 1,
                                           }
        for graph in self.graphs:
            chunk[graph] = {'values': self.data[graph],
                            'name': unicode(graph),
                            'type': 'area',
                            'color': self.color_mapping(graph),
                            }
        return chunk

    @property
    @Memoize
    def data(self):
        """
        dict with graphs as keys and values as arrays
        """
        data = {}
        graphs_mapping = {
            u'0-0.\u2089\u2089\u2089': 0,
            u'1-9': 1,
            u'10-99': 2,
            u'100-999': 3,
            u'1000+': 4
        }
        sql = '''
            select data from 
            (
            select intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.rt_microsecond_details_buffer
            where job_id=%(job)s
            and tag = ''
            and time > toDateTime(%(latest_second)s) 
            and job_date = toDate(%(job_date)s)
            group by t
            order by t
            limit %(interval)s
            ) all left join
            (
            select 
            round(toUInt32(sum(cnt))/%(compress_ratio)s, 3) as data, 
            intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.rt_microsecond_histograms_buffer
            where job_id=%(job)s
            '''
        if self.job_obj.multitag and self.tag:
            sql += 'and tag in (%(cases_with_tag)s) '
        else:
            sql += '''and tag='%(tag)s'  '''
        sql += '''
            and time > toDateTime(%(latest_second)s) 
            and %(length)s
            and job_date = toDate(%(job_date)s)
            group by t
            order by t
            limit %(interval)s
            )
            using t'''
        query_params = self.query_params.copy()
        for length in graphs_mapping.keys():
            if graphs_mapping[length] == 4:
                query_params['length'] = 'toInt8(length(toString(bin)))>=7'
            elif graphs_mapping[length] == 0:
                query_params['length'] = 'toInt8(length(toString(bin)))<=3'
            else:
                # microseconds
                query_params['length'] = 'toInt8(length(toString(bin)))=%s' % (int(graphs_mapping[length]) + 3)
            data[length] = [v[0] for v in self.ch_client.select(sql, query_params=query_params)]
        return data

    @property
    def yaxis(self):
        yaxis = []
        if self.scheme_type['type'] == 'rps':
            yaxis = [
                {
                    'stacking': 'normal',
                    'overrides': {'min': 0, 'allowDecimals': False},
                    'label': self.scheme_type['type'],
                    'position': 'right',
                    'type': 'area',
                },
            ]
        elif self.scheme_type['type'] == 'instances':
            yaxis = [
                {
                    'stacking': 'normal',
                    'overrides': {'min': 0},
                    'label': '',
                    'type': 'area',
                    'position': 'left',
                },
                {
                    'label': self.scheme_type['type'],
                    'labels': {'format': '"{value:,f}"'},
                    'overrides': {'gridLineWidth': 0, 'min': 0, 'labels': {'enabled': True, }, 'allowDecimals': False},
                    'position': 'right',
                    'type': 'line',
                },
            ]
        return yaxis


class HTTPCodesTimelinePlot(TimelinePlot):
    title = u'HTTP codes'

    @staticmethod
    def color_mapping(http_code):
        color_map = {0: '#ccc',
                     2: '#66af5f',
                     3: '#60becc',
                     4: '#ffd43f',
                     5: '#ff3f3f', }
        try:
            color = color_map[http_code / 100]
            return color
        except KeyError:
            logging.warning('Unexpected http_code: %s', http_code)
            return None

    @property
    @Memoize
    def graphs(self):
        sql = '''
            select distinct toUInt32(code) 
            from loaddb.proto_codes_buffer
            where job_id=%(job)s
            and job_date = toDate(%(job_date)s)
            '''
        if self.job_obj.multitag and self.tag:
            sql += 'and tag in (%(cases_with_tag)s) '
        else:
            sql += '''and tag='%(tag)s'  '''
        sql += '''
            and time > toDateTime(%(latest_second)s) 
            '''
        query_params = self.job_obj.basic_query_params.copy()
        query_params.update({
            'interval': self.interval,
            'latest_second': self.latest_second,
            'cases_with_tag': ','.join(
                ["'" + case + "'" for case in self.job_obj.cases if self.tag in case.split('|')]),
            'tag': self.tag,
        })
        return [c[0] for c in self.ch_client.select(sql, query_params=query_params)]

    @property
    @Memoize
    def chunk(self):
        chunk = OrderedDict()
        chunk[self.scheme_type['type']] = {'values': self.scheme_data,
                                           'name': self.scheme_type['type'],
                                           'type': 'line',
                                           'color': self.scheme_type['color'],
                                           }
        for graph in self.graphs:
            chunk[graph] = {'values': self.data[graph],
                            'name': str(graph),
                            'type': 'area',
                            'color': self.color_mapping(graph),
                            'yAxis': 0 if len(self.graphs) == 1 and self.scheme_type['type'] == 'rps' else 1,
                            }
        return chunk

    @property
    @Memoize
    def data(self):
        """
        retrieves monitoring data from database
        """
        data = {}
        sql = '''
            select data from 
            (
            select intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.rt_microsecond_details_buffer
            where job_id=%(job)s
            and tag = ''
            and time > toDateTime(%(latest_second)s) 
            and job_date = toDate(%(job_date)s)
            group by t
            order by t
            limit %(interval)s
            ) all left join
            (
            select 
            round(sum(cnt)/%(compress_ratio)s, 3) as data,
            intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.proto_codes_buffer
            where job_id=%(job)s
            '''
        if self.job_obj.multitag and self.tag:
            sql += 'and tag in (%(cases_with_tag)s) '
        else:
            sql += '''and tag='%(tag)s'  '''
        sql += '''
            and code=%(code)s
            and time > toDateTime(%(latest_second)s) 
            and job_date = toDate(%(job_date)s)
            group by t
            order by t
            limit %(interval)s
            ) 
            using t
            '''
        for code in self.graphs:
            query_params = self.job_obj.basic_query_params.copy()
            query_params.update({
                'interval': self.interval,
                'latest_second': self.latest_second,
                'compress_ratio': self.compress_ratio,
                'code': code,
                'cases_with_tag': ','.join(["'" + case + "'" for case in self.job_obj.cases if
                                            self.tag in case.split('|')]),
                'tag': self.tag,
            })
            data[code] = [v[0] for v in self.ch_client.select(sql, query_params=query_params)]
        return data

    @property
    def yaxis(self):
        if len(self.graphs) == 1 and self.scheme_type['type'] == 'rps':
            yaxis = [{
                'stacking': 'normal',
                'overrides': {'min': 0, 'allowDecimals': False},
                'label': self.scheme_type['type'],
                'position': 'right',
                'type': 'area',
            },
            ]
        elif self.scheme_type['type'] == 'instances':
            yaxis = [
                {
                    'label': self.scheme_type['type'],
                    'overrides': {'gridLineWidth': 0, 'min': 0, 'labels': {'enabled': True}, 'allowDecimals': False},
                    'position': 'right',
                    'type': 'line',
                },
                {
                    'stacking': 'normal',
                    'overrides': {'allowDecimals': False, 'min': 0},
                    'label': '',
                    'type': 'area',
                    'position': 'left',
                },
            ]
        else:
            yaxis = [
                {
                    'label': self.scheme_type['type'],
                    'overrides': {'min': 0, 'allowDecimals': False},
                    'position': 'right',
                    'type': 'line',
                },
                {
                    'stacking': 'normal',
                    'overrides': {'gridLineWidth': 0, 'min': 0, 'labels': {'enabled': True}, 'allowDecimals': False},
                    'label': '',
                    'type': 'area',
                    'position': 'left',
                },
            ]
        return yaxis


class NetCodesTimelinePlot(TimelinePlot):
    title = u"Net codes"

    @property
    @Memoize
    def graphs(self):
        sql = '''
            select distinct toUInt32(code) 
            from loaddb.net_codes_buffer
            where job_id=%(job)s
            '''
        if self.job_obj.multitag and self.tag:
            sql += 'and tag in (%(cases_with_tag)s) '
        else:
            sql += '''and tag='%(tag)s'  '''
        sql += '''
            and time > toDateTime(%(latest_second)s) 
            and job_date = toDate(%(job_date)s)
            limit %(interval)s
            '''
        query_params = self.job_obj.basic_query_params.copy()
        query_params.update({
            'interval': self.interval,
            'latest_second': self.latest_second,
            'cases_with_tag': ','.join(
                ["'" + case + "'" for case in self.job_obj.cases if self.tag in case.split('|')]),
            'tag': self.tag,
        })
        return [c[0] for c in self.ch_client.select(sql, query_params=query_params)]

    @property
    @Memoize
    def chunk(self):
        chunk = OrderedDict()
        chunk[self.scheme_type['type']] = {'values': self.scheme_data,
                                           'name': self.scheme_type['type'],
                                           'type': 'line',
                                           'color': self.scheme_type['color'],
                                           }
        for graph in self.graphs:
            chunk[str(graph) if graph else "OK"] = {'values': self.data[graph],
                                                    'name': str(graph) if graph else "OK",
                                                    'type': 'area',
                                                    'color': self.color_mapping(graph),
                                                    'yAxis': 0 if len(self.graphs) == 1 and self.scheme_type[
                                                                                                'type'] == 'rps' else 1
                                                    }
        return chunk

    @property
    @Memoize
    def data(self):
        """
        retrieves monitoring data from database
        """
        data = {}
        sql = '''
            select data from 
            (
            select intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.rt_microsecond_details_buffer
            where job_id=%(job)s
            and tag = ''
            and time > toDateTime(%(latest_second)s) 
            and job_date = toDate(%(job_date)s)
            group by t
            order by t
            limit %(interval)s
            ) all left join
            (
            select 
            round(sum(cnt)/%(compress_ratio)s, 3) as data,
            intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.net_codes_buffer
            where job_id=%(job)s
            '''
        if self.job_obj.multitag and self.tag:
            sql += 'and tag in (%(cases_with_tag)s) '
        else:
            sql += '''and tag='%(tag)s'  '''
        sql += '''
            and code=%(code)s
            and time > toDateTime(%(latest_second)s) 
            and job_date = toDate(%(job_date)s)
            group by t
            order by t
            limit %(interval)s
            )
            using t
            '''
        for code in self.graphs:
            query_params = self.job_obj.basic_query_params.copy()
            query_params.update({
                'interval': self.interval,
                'latest_second': self.latest_second,
                'code': code,
                'compress_ratio': self.compress_ratio,
                'cases_with_tag': ','.join(["'" + case + "'" for case in self.job_obj.cases if
                                            self.tag in case.split('|')]),
                'tag': self.tag,
            })
            data[code] = [v[0] for v in self.ch_client.select(sql, query_params=query_params)]
        return data

    @staticmethod
    def color_mapping(net_code):
        """

        :param net_code: int
        """
        if net_code:
            return None
        else:
            return '#66af5f'  # OK green

    @property
    def yaxis(self):
        if len(self.graphs) == 1 and self.scheme_type['type'] == 'rps':
            yaxis = [{
                'stacking': 'normal',
                'overrides': {'min': 0, 'allowDecimals': False},
                'label': self.scheme_type['type'],
                'position': 'right',
                'type': 'area',
            },
            ]
        elif self.scheme_type['type'] == 'instances':
            yaxis = [
                {
                    'label': self.scheme_type['type'],
                    'overrides': {'gridLineWidth': 0, 'min': 0, 'labels': {'enabled': True}, 'allowDecimals': False},
                    'position': 'right',
                    'type': 'line',
                },
                {
                    'stacking': 'normal',
                    'overrides': {'allowDecimals': False, 'min': 0},
                    'label': '',
                    'type': 'area',
                    'position': 'left',
                },
            ]
        else:
            yaxis = [
                {
                    'label': self.scheme_type['type'],
                    'overrides': {'min': 0, 'allowDecimals': False, },
                    'position': 'right',
                    'type': 'line',
                },
                {
                    'stacking': 'normal',
                    'overrides': {'gridLineWidth': 0, 'min': 0, 'labels': {'enabled': True}, 'allowDecimals': False, },
                    'label': '',
                    'type': 'area',
                    'position': 'left',
                },
            ]
        return yaxis


class CasesTimelinePlot(TimelinePlot):
    title = u'Responses count per tag distribution'

    @property
    @Memoize
    def chunk(self):
        chunk = OrderedDict()
        chunk[self.scheme_type['type']] = {'values': self.scheme_data,
                                           'name': self.scheme_type['type'],
                                           'type': 'line',
                                           'color': self.scheme_type['color'],
                                           'yAxis': 0 if self.tag == '' and self.scheme_type['type'] == 'rps' else 1
                                           }
        for graph in self.graphs:
            chunk[graph or '__OVERALL__'] = {'values': self.data[graph],
                                             'name': graph or '__OVERALL__',
                                             'type': 'area',
                                             'color': None,
                                             }
        return chunk

    @property
    @Memoize
    def data(self):
        """
        dict with graphs as keys and values as arrays
        """
        data = {}
        sql = '''
            select data from 
            (
            select intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.rt_microsecond_details_buffer
            where job_id=%(job)s
            and tag = ''
            and time > toDateTime(%(latest_second)s) 
            and job_date = toDate(%(job_date)s)
            group by t
            order by t
            limit %(interval)s
            ) all left join
            (
            select 
            round(sum(resps)/%(compress_ratio)s, 3) as data,
            intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.rt_microsecond_details_buffer
            where job_id=%(job)s
            and tag = '%(tag)s'
            and time > toDateTime(%(latest_second)s) 
            and job_date = toDate(%(job_date)s)
            group by t
            order by t
            limit %(interval)s
            )
            using t'''
        for graph in self.graphs:
            query_params = self.job_obj.basic_query_params.copy()
            query_params.update({
                'interval': self.interval,
                'latest_second': self.latest_second,
                'compress_ratio': self.compress_ratio,
                'tag': graph,
            })
            data[graph] = [v[0] for v in self.ch_client.select(sql, query_params=query_params)]
        return data

    @property
    @Memoize
    def graphs(self):
        """
        self case or job cases and overall as empty string
        """

        if len(self.job_obj.tags) > self.series_limit and not self.tag:
            self.subtitle = u'Too many tags, choose one'
            return '',
        elif self.job_obj.tags and not self.tag:
            return self.job_obj.tags
        else:
            return self.tag,

    @property
    def yaxis(self):
        if self.tag == '' and self.scheme_type['type'] == 'rps':
            yaxis = [{
                'stacking': 'normal',
                'overrides': {'min': 0, 'allowDecimals': False},
                'label': self.scheme_type['type'],
                'position': 'right',
                'type': 'line',
            },
            ]
        else:
            yaxis = [
                {
                    'stacking': 'normal',
                    'overrides': {'min': 0, 'allowDecimals': False, },
                    'label': '',
                    'type': 'area',
                    'position': 'left',
                },
                {
                    'label': self.scheme_type['type'],
                    'overrides': {'gridLineWidth': 0, 'min': 0, 'labels': {'enabled': False}, 'allowDecimals': False, },
                    'position': 'right',
                    'type': 'line',
                },
            ]
        return yaxis


class AvgTimesTimelinePlot(TimelinePlot):
    title = u'Response time fractions'

    @property
    @Memoize
    def chunk(self):
        chunk = OrderedDict()
        chunk[self.scheme_type['type']] = {'values': self.scheme_data,
                                           'name': self.scheme_type['type'],
                                           'type': 'line',
                                           'color': self.scheme_type['color'],
                                           }
        for graph in self.graphs:
            chunk[graph] = {'values': self.data[graph],
                            'name': str(graph),
                            'type': 'area',
                            'color': self.color_mapping(graph),
                            'yAxis': 1,
                            }
        return chunk

    @property
    @Memoize
    def data(self):
        """
        retrieves monitoring data from database
        """
        data = {}
        sql = '''
            select connect_time_data, send_time_data, latency_data, receive_time_data from 
            (
            select intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.rt_microsecond_details_buffer
            where job_id=%(job)s
            and tag = ''
            and time > toDateTime(%(latest_second)s) 
            and job_date = toDate(%(job_date)s)
            group by t
            order by t
            limit %(interval)s
            ) all left join
            (
            select 
            round(avg(connect_time_sum/1000/resps), 3) as connect_time_data, 
            round(avg(send_time_sum/1000/resps), 3) as send_time_data, 
            round(avg(latency_sum/1000/resps), 3) as latency_data, 
            round(avg(receive_time_sum/1000/resps), 3) as receive_time_data, 
            intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.rt_microsecond_details_buffer
            where job_id=%(job)s
        '''
        if self.job_obj.multitag and self.tag:
            sql += 'and tag in (%(cases_with_tag)s) '
        else:
            sql += '''and tag='%(tag)s'  '''
        sql += '''
                and time > toDateTime(%(latest_second)s) 
                and job_date = toDate(%(job_date)s)
                group by t
                order by t
                limit %(interval)s
                )
                using t'''
        fetched_data = self.ch_client.select(sql, query_params=self.query_params)
        for graph in self.graphs:
            data[graph] = [v[self.graphs.index(graph)] for v in fetched_data]
        return data

    @property
    def graphs(self):
        return 'connect_time', 'send_time', 'latency', 'receive_time'

    @staticmethod
    def color_mapping(time):
        color_map = {'connect_time': 'rgb(114,137,184)',
                     'send_time': 'rgb(117,193,79)',
                     'latency': 'rgb(255,94,82)',
                     'receive_time': 'rgb(255,230,132)'
                     }
        try:
            color = color_map[time]
            return color
        except KeyError:
            logging.warning('Unexpected time: %s', time)
            return None

    @property
    def yaxis(self):
        return [
            {
                'label': self.scheme_type['type'],
                'overrides': {'gridLineWidth': 0, 'min': 0, 'allowDecimals': False},
                'position': 'right',
                'type': 'line',
            },
            {
                'stacking': 'normal',
                'label': 'ms',
                'type': 'area',
                'position': 'left',
            },
        ]


class InstancesTimelinePlot(TimelinePlot):
    """
    doesn't depend on case or multitag
    """
    title = u'Threads'
    graphs = 'threads',

    @property
    def graphs_settings(self):
        """
        settings for highcharts series
        """
        return [{'values': graph,
                 'title': u'threads',
                 'color': '#ff00ff'} for graph in self.graphs]

    @property
    @Memoize
    def chunk(self):
        chunk = OrderedDict()
        if self.scheme_type['type'] == 'rps':
            chunk[self.scheme_type['type']] = {'values': self.scheme_data,
                                               'name': self.scheme_type['type'],
                                               'type': 'line',
                                               'color': self.scheme_type['color'],
                                               'yAxis': 1,
                                               }
        for graph in self.graphs:
            chunk[graph] = {'values': self.data[graph],
                            'name': u'threads',
                            'type': 'line',
                            'color': '#ff00ff',
                            }
        return chunk

    @property
    @Memoize
    def data(self):
        """
        retrieves monitoring data from database
        """
        sql = '''select 
            round(avg(threads), 3)
            from loaddb.rt_microsecond_details_buffer
            where job_id=%(job)s
            and tag='' 
            and time > toDateTime(%(latest_second)s) 
            and job_date = toDate(%(job_date)s)
            group by intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s
            order by intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s
            limit %(interval)s
            '''
        query_params = self.job_obj.basic_query_params.copy()
        query_params.update({
            'interval': self.interval,
            'latest_second': self.latest_second,
            'compress_ratio': self.compress_ratio,
        })
        data = {'threads': [v[0] for v in self.ch_client.select(sql, query_params=query_params)]}
        return data

    @property
    def yaxis(self):
        yaxis = [
            {
                'label': 'instances',
                'overrides': {'min': 0, 'allowDecimals': False},
                'type': 'line',
                'position': 'left',
            }
        ]

        if self.scheme_type['type'] == 'rps':
            yaxis.append({
                'label': self.scheme_type['type'],
                'overrides': {'gridLineWidth': 0, 'min': 0, 'allowDecimals': False},
                'position': 'right',
                'type': 'line',
            })
        return yaxis


class CasesAvgTimelinePlot(TimelinePlot):
    title = u'Response time average per tag'

    @property
    @Memoize
    def chunk(self):
        chunk = OrderedDict()
        chunk[self.scheme_type['type']] = {'values': self.scheme_data,
                                           'name': self.scheme_type['type'],
                                           'type': 'line',
                                           'color': self.scheme_type['color'],
                                           }
        for graph in self.graphs:
            chunk[graph or u'__OVERALL__'] = {'values': self.data[graph],
                                              'name': graph or u'__OVERALL__',
                                              'color': None,
                                              'yAxis': 1,
                                              }
        return chunk

    @property
    @Memoize
    def data(self):
        """
        dict with graphs as keys and values as arrays
        """
        data = {}
        sql = '''
            select data from 
            (
            select intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.rt_microsecond_details_buffer
            where job_id=%(job)s
            and tag = ''
            and time > toDateTime(%(latest_second)s) 
            and job_date = toDate(%(job_date)s)
            group by t
            order by t
            limit %(interval)s
            ) all left join
            (
            select 
            round(avg((connect_time_sum + send_time_sum + latency_sum + receive_time_sum)/1000/resps), 3) as data, 
            intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s as t
            from loaddb.rt_microsecond_details_buffer
            where job_id=%(job)s
            and tag = '%(tag)s'
            and time > toDateTime(%(latest_second)s) 
            and job_date = toDate(%(job_date)s)
            group by t
            order by t
            limit %(interval)s
            )
            using t
        '''
        for graph in self.graphs:
            self.query_params['tag'] = graph
            data[graph] = [v[0] for v in self.ch_client.select(sql, query_params=self.query_params)]
        return data

    @property
    @Memoize
    def graphs(self):
        """
        self case or job cases and overall as empty string
        """

        if len(self.job_obj.tags) > self.series_limit and not self.tag:
            self.subtitle = u'Too many tags, choose one'
            return '',
        elif self.job_obj.tags and not self.tag:
            return [''] + self.job_obj.tags
        else:
            return self.tag,

    @property
    def yaxis(self):
        return [
            {
                'label': self.scheme_type['type'],
                'overrides': {'gridLineWidth': 0, 'min': 0, 'allowDecimals': False},
                'position': 'right',
                'type': 'line',
            },
            {
                'label': 'ms',
                'overrides': {'min': 0, 'allowDecimals': False},
                'type': 'line',
                'position': 'left',
            },
        ]


class SentReceivedPlot(TimelinePlot):
    title = u'Tank egress/igress'
    graphs = 'igress', 'egress'

    @staticmethod
    def color_mapping(graph):
        color_map = {'igress': '#008000',
                     'egress': '#ff0000'}
        try:
            color = color_map[graph]
            return color
        except KeyError:
            logging.warning('Unexpected graph: %s', graph)
            return None

    @property
    @Memoize
    def chunk(self):
        chunk = OrderedDict()
        chunk[self.scheme_type['type']] = {'values': self.scheme_data,
                                           'name': self.scheme_type['type'],
                                           'type': 'line',
                                           'color': self.scheme_type['color'],
                                           }
        for graph in self.graphs:
            chunk[graph] = {'values': self.data[graph],
                            'name': str(graph),
                            'type': 'line',
                            'color': self.color_mapping(graph),
                            'yAxis': 1,
                            }
        return chunk

    @property
    @Memoize
    def data(self):
        """
        retrieves monitoring data from database
        """
        sql = '''select 
            round(avg(igress), 3),
            round(avg(egress), 3)
            from loaddb.rt_microsecond_details_buffer
            where job_id=%(job)s
            and tag=''
            and time > toDateTime(%(latest_second)s) 
            and job_date = toDate(%(job_date)s)
            group by intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s
            order by intDiv(toUInt32(time), %(compress_ratio)s)*%(compress_ratio)s
            limit %(interval)s
            '''
        query_params = self.job_obj.basic_query_params.copy()
        query_params.update({
            'interval': self.interval,
            'latest_second': self.latest_second,
            'compress_ratio': self.compress_ratio,
        })
        fetched_data = self.ch_client.select(sql, query_params=query_params)
        data = {'igress': [v[0] for v in fetched_data],
                'egress': [v[1] for v in fetched_data],
                }
        return data

    @property
    def yaxis(self):
        return [
            {
                'label': self.scheme_type['type'],
                'overrides': {'gridLineWidth': 0, 'min': 0, 'allowDecimals': False},
                'position': 'right',
                'type': 'line',
            },
            {
                'stacking': 'normal',
                'overrides': {'min': 0, },
                'label': 'bytes',
                'type': 'line',
                'position': 'left',
            },
        ]
