#!/usr/bin/env python
# coding=utf-8

from operator import itemgetter

from .websockets import BinanceSocketManager


class DepthCache(object):

    def __init__(self, symbol):
        """Intialise the DepthCache

        :param symbol: Symbol to create depth cache for
        :type symbol: string

        """
        self.symbol = symbol
        self._bids = {}
        self._asks = {}

    def add_bid(self, bid):
        """Add a bid to the cache

        :param bid:
        :return:

        """
        self._bids[bid[0]] = float(bid[1])
        if bid[1] == "0.00000000":
            del self._bids[bid[0]]

    def add_ask(self, ask):
        """Add an ask to the cache

        :param ask:
        :return:

        """
        self._asks[ask[0]] = float(ask[1])
        if ask[1] == "0.00000000":
            del self._asks[ask[0]]

    def get_bids(self):
        """Get the current bids

        :return: list of bids with price and quantity as floats

        .. code-block:: python

            [
                [
                    0.0001946,  # Price
                    45.0        # Quantity
                ],
                [
                    0.00019459,
                    2384.0
                ],
                [
                    0.00019158,
                    5219.0
                ],
                [
                    0.00019157,
                    1180.0
                ],
                [
                    0.00019082,
                    287.0
                ]
            ]

        """
        return DepthCache.sort_depth(self._bids, reverse=True)

    def get_asks(self):
        """Get the current asks

        :return: list of asks with price and quantity as floats

        .. code-block:: python

            [
                [
                    0.0001955,  # Price
                    57.0'       # Quantity
                ],
                [
                    0.00019699,
                    778.0
                ],
                [
                    0.000197,
                    64.0
                ],
                [
                    0.00019709,
                    1130.0
                ],
                [
                    0.0001971,
                    385.0
                ]
            ]

        """
        return DepthCache.sort_depth(self._asks, reverse=False)

    @staticmethod
    def sort_depth(vals, reverse=False):
        """Sort bids or asks by price
        """
        lst = [[float(price), quantity] for price, quantity in vals.items()]
        lst = sorted(lst, key=itemgetter(0), reverse=reverse)
        return lst


class DepthCacheManager(object):

    def __init__(self, client, symbol, callback=None):
        """Initialise the DepthCacheManager

        :param client: Binance API client
        :type client: binance.Client
        :param symbol: Symbol to create depth cache for
        :type symbol: string
        :param callback: Optional function to receive depth cache updates
        :type callback: function

        """
        self._client = client
        self._symbol = symbol
        self._callback = callback
        self._first_update_id = None
        self._depth_message_buffer = []
        self._bm = None
        self._depth_cache = DepthCache(self._symbol)

        self._start_socket()
        self._init_cache()

    def _init_cache(self):
        """Initialise the depth cache calling REST endpoint

        :return:
        """
        self._first_update_id = None
        self._depth_message_buffer = []

        res = self._client.get_order_book(symbol=self._symbol, limit=500)

        # process bid and asks from the order book
        for bid in res['bids']:
            self._depth_cache.add_bid(bid)
        for ask in res['asks']:
            self._depth_cache.add_ask(ask)

        # set first update id
        self._first_update_id = res['lastUpdateId']

        # Apply any updates from the websocket
        for msg in self._depth_message_buffer:
            self._process_depth_message(msg)

        # clear the depth buffer
        del self._depth_message_buffer

    def _start_socket(self):
        """Start the depth cache socket

        :return:
        """
        self._bm = BinanceSocketManager(self._client)

        self._bm.start_depth_socket(self._symbol, self._depth_event)

        self._bm.start()

    def _depth_event(self, msg):
        """Handle a depth event

        :param msg:
        :return:

        """

        if self._first_update_id is None:
            # Initial depth snapshot fetch not yet performed, buffer messages
            self._depth_message_buffer.append(msg)
        else:
            self._process_depth_message(msg)

    def _process_depth_message(self, msg):
        """Process a depth event message.

        :param msg: Depth event message.
        :return:

        """
        # ignore any updates before the initial update id
        if msg['u'] <= self._first_update_id:
            return

        # add any bid or ask values
        for bid in msg['b']:
            self._depth_cache.add_bid(bid)
        for ask in msg['a']:
            self._depth_cache.add_ask(ask)

        # call the callback with the updated depth cache
        if self._callback:
            self._callback(self._depth_cache)

    def get_depth_cache(self):
        """Get the current depth cache

        :return: DepthCache object

        """
        return self._depth_cache

    def close(self):
        """Close the open socket for this manager

        :return:
        """
        self._bm.close()

@@ -62,16 +62,28 @@
 emgetter
+%0Aimport time
 %0A%0Afrom .
@@ -2662,32 +2662,78 @@
 nager(object):%0A%0A
+    _default_refresh = 60 * 30  # 30 minutes%0A%0A
     def __init__
@@ -2768,16 +2768,51 @@
 ack=None
+, refresh_interval=_default_refresh
 ):%0A     
@@ -3121,16 +3121,160 @@
 function
+%0A        :param refresh_interval: Optional number of seconds between cache refresh, use 0 or None to disable%0A        :type refresh_interval: int
 %0A%0A      
@@ -3526,16 +3526,66 @@
 _symbol)
+%0A        self._refresh_interval = refresh_interval
 %0A%0A      
@@ -4190,16 +4190,175 @@
 teId'%5D%0A%0A
+        # set a time to refresh the depth cache%0A        if self._refresh_interval:%0A            self._refresh_time = int(time.time()) + self._refresh_interval%0A%0A
         
@@ -5706,16 +5706,16 @@
 llback:%0A
-
         
@@ -5749,24 +5749,208 @@
 pth_cache)%0A%0A
+        # after processing event see if we need to refresh the depth cache%0A        if self._refresh_interval and int(time.time()) %3E self._refresh_time:%0A            self._init_cache()%0A%0A
     def get_

Add parameter to refresh depth cache periodically