# -*- coding: utf8 -*-

"""
Copyright (C) 2012-2014 Andreas Würl

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.

"""

from injector import inject
import time
from twisted.internet.defer import gatherResults
from twisted.python import log

from .. import db

from .general import create_time_interval, TimingState


class StrikeGridState(TimingState):

    __slots__ = ['grid_parameters', 'time_interval']

    def __init__(self, statsd_client, grid_parameters, time_interval):
        super(StrikeGridState, self).__init__("strikes_grid", statsd_client)
        self.grid_parameters = grid_parameters
        self.time_interval = time_interval


class StrikeGridQuery(object):

    __slots__ = ['strike_query_builder']

    @inject(strike_query_builder=db.query_builder.Strike)
    def __init__(self, strike_query_builder):
        self.strike_query_builder = strike_query_builder

    def create(self, grid_parameters, minute_length, minute_offset, count_threshold, connection, statsd_client):
        time_interval = create_time_interval(minute_length, minute_offset)

        state = StrikeGridState(statsd_client, grid_parameters, time_interval)

        query = self.strike_query_builder.grid_query(db.table.Strike.TABLE_NAME, grid_parameters,
                                                     time_interval=time_interval, count_threshold=count_threshold)

        grid_query = connection.runQuery(str(query), query.get_parameters())
        grid_query.addCallback(self.build_strikes_grid_result, state=state)
        grid_query.addErrback(log.err)
        return grid_query, state

    @staticmethod
    def build_strikes_grid_result(results, state):
        state.add_info_text("query %.03fs #%d %s" % (state.get_seconds(), len(results), state.grid_parameters))
        state.log_timing('strikes_grid.query')

        reference_time = time.time()
        x_bin_count = state.grid_parameters.x_bin_count
        y_bin_count = state.grid_parameters.y_bin_count
        end_time = state.time_interval.end
        strikes_grid_result = tuple(
            (
                result['rx'],
                y_bin_count - result['ry'],
                result['strike_count'],
                -(end_time - result['timestamp']).seconds
            ) for result in results if 0 <= result['rx'] < x_bin_count and 0 < result['ry'] <= y_bin_count
        )
        state.add_info_text(", result %.03fs" % state.get_seconds(reference_time))
        state.log_timing('strikes_grid.build_result', reference_time)

        return strikes_grid_result

    def combine_result(self, strike_grid_result, histogram_result, state):
        combined_result = gatherResults([strike_grid_result, histogram_result], consumeErrors=True)
        combined_result.addCallback(self.build_grid_response, state=state)
        combined_result.addErrback(log.err)

        return combined_result

    @staticmethod
    def build_grid_response(results, state):
        state.log_timing('strikes_grid.results')

        grid_data = results[0]
        histogram_data = results[1]

        state.log_gauge('strikes_grid.size', len(grid_data))
        state.log_incr('strikes_grid')

        grid_parameters = state.grid_parameters
        end_time = state.time_interval.end
        duration = state.time_interval.duration
        response = {'r': grid_data, 'xd': round(grid_parameters.x_div, 6),
                    'yd': round(grid_parameters.y_div, 6),
                    'x0': round(grid_parameters.x_min, 4), 'y1': round(grid_parameters.y_max + grid_parameters.y_div, 4),
                    'xc': grid_parameters.x_bin_count,
                    'yc': grid_parameters.y_bin_count,
                    't': end_time.strftime("%Y%m%dT%H:%M:%S"),
                    'dt': duration.seconds,
                    'h': histogram_data}
        state.add_info_text(", total %.03fs" % state.get_seconds())
        state.log_timing('strikes_grid.total')
        print(state.info_text)

        return response

@@ -868,17 +868,16 @@
 State):%0A
-%0A
     __sl
@@ -1197,51 +1197,8 @@
 t):%0A
-%0A    __slots__ = %5B'strike_query_builder'%5D%0A%0A
     
@@ -2534,18 +2534,26 @@
         
-(%0A
+    (%0A    
         
@@ -2570,24 +2570,28 @@
 sult%5B'rx'%5D,%0A
+    
             
@@ -2630,32 +2630,36 @@
                 
+    
 result%5B'strike_c
@@ -2662,24 +2662,28 @@
 ke_count'%5D,%0A
+    
             
@@ -2728,16 +2728,20 @@
 seconds%0A
+    
         
@@ -3913,32 +3913,32 @@
 ters.y_div, 6),%0A
-
                 
@@ -3979,16 +3979,36 @@
 min, 4),
+%0A                   
  'y1': r

remove __slots__ declaration to fix DI