from __future__ import unicode_literals

import six

from django import template
from django.conf import settings

try:
    from django.core.cache import caches
except:
    from django.core.cache import get_cache as caches

if caches.__module__.startswith('debug_toolbar'):
    try:
        from debug_toolbar.panels.cache import base_get_cache as caches
    except:
        from debug_toolbar.panels.cache import get_cache as caches

get_cache = lambda cache_name: caches(cache_name) if hasattr(caches, '__call__') else caches[cache_name]

register = template.Library()

class CacheStats(template.Node):
    """
    Reads the cache stats out of the memcached cache backend. Returns `None`
    if no cache stats supported.
    """
    def render(self, context):
        cache_stats = []
        for cache_backend_nm, cache_backend_attrs in six.iteritems(settings.CACHES):
            try:
                cache_backend = get_cache(cache_backend_nm)
                this_backend_stats = cache_backend._cache.get_stats()
                # returns list of (name, stats) tuples
                for server_name, server_stats in this_backend_stats:
                    cache_stats.append(("%s: %s" % (
                        cache_backend_nm, server_name), server_stats))
            except AttributeError: # this backend probably doesn't support that
                continue
        context['cache_stats'] = cache_stats
        return ''

@register.tag
def get_cache_stats(parser, token):
    return CacheStats()

@register.filter
def prettyname(name):
    return ' '.join([word.capitalize() for word in name.split('_')])

@register.filter
def prettyvalue(value, key):
    return PrettyValue().format(key, value)

class PrettyValue(object):
    """
    Helper class that reformats the value. Looks for a method named
    ``format_<key>_value`` and returns that value. Returns the value
    as is, if no format method is found.
    """

    def format(self, key, value):
        try:
            func = getattr(self, 'format_%s_value' % key.lower())
            return func(value)
        except AttributeError:
            return value

    def format_limit_maxbytes_value(self, value):
        return "%s (%s)" % (value, self.human_bytes(value))

    def format_bytes_read_value(self, value):
        return "%s (%s)" % (value, self.human_bytes(value))

    def format_bytes_written_value(self, value):
        return "%s (%s)" % (value, self.human_bytes(value))

    def format_uptime_value(self, value):
        return self.fract_timestamp(int(value))

    def format_time_value(self, value):
        from datetime import datetime
        return datetime.fromtimestamp(int(value)).strftime('%x %X')

    def fract_timestamp(self, s):
        years, s = divmod(s, 31556952)
        min, s = divmod(s, 60)
        h, min = divmod(min, 60)
        d, h = divmod(h, 24)
        return '%sy, %sd, %sh, %sm, %ss' % (years, d, h, min, s)

    def human_bytes(self, bytes):
        bytes = float(bytes)
        if bytes >= 1073741824:
            gigabytes = bytes / 1073741824
            size = '%.2fGB' % gigabytes
        elif bytes >= 1048576:
            megabytes = bytes / 1048576
            size = '%.2fMB' % megabytes
        elif bytes >= 1024:
            kilobytes = bytes / 1024
            size = '%.2fKB' % kilobytes
        else:
            size = '%.2fB' % bytes
        return size

@@ -34,16 +34,31 @@
 terals%0A%0A
+import logging%0A
 import s
@@ -171,24 +171,36 @@
 aches%0Aexcept
+ ImportError
 :%0A    from d
@@ -385,16 +385,28 @@
   except
+ ImportError
 :%0A      
@@ -467,16 +467,17 @@
 caches%0A%0A
+%0A
 get_cach
@@ -577,70 +577,145 @@
 me%5D%0A
-%0Aregister = template.Library()%0A%0Aclass C
+logger = logging.getLogger(__name__)%0Aregister = template.Library()%0A%0A%0A@register.simple_tag(takes_context=True)%0Adef get_c
 ache
-S
+_s
 tats(
-template.Node
+context
 ):%0A 
@@ -843,43 +843,8 @@
 %22%22%22%0A
-    def render(self, context):%0A    
     
@@ -860,20 +860,16 @@
 ts = %5B%5D%0A
-    
     for 
@@ -945,37 +945,29 @@
 S):%0A        
-    
 try:%0A
-    
             
@@ -1022,20 +1022,16 @@
         
-   
- 
 this_bac
@@ -1076,24 +1076,196 @@
 stats()%0A    
+        if not this_backend_stats:%0A                logger.warning('The memcached backend %22%25s%22 does not support or '%0A                    'provide stats.', cache_backend_nm)%0A
             
@@ -1315,20 +1315,16 @@
         
- 
-   
 for serv
@@ -1380,28 +1380,24 @@
             
-    
 cache_stats.
@@ -1417,20 +1417,16 @@
 %25s%22 %25 (%0A
-    
         
@@ -1488,28 +1488,24 @@
 s))%0A        
-    
 except Attri
@@ -1576,358 +1576,180 @@
     
-    continue%0A        context%5B'cache_stats'%5D = cache_stats%0A        return ''%0A%0A@register.tag%0Adef get_cache_stats(parser, token):%0A    return CacheStats()%0A%0A@register.filter%0Adef prettyname(name):%0A    return ' '.join(%5Bword.capitalize() for word in name.split('_')%5D)%0A%0A@register.filter%0Adef prettyvalue(value, key):%0A    return PrettyValue().format(key, value)
+logger.warning('The memcached backend %22%25s%22 does not support or '%0A                'provide stats.', cache_backend_nm)%0A    context%5B'cache_stats'%5D = cache_stats%0A    return ''%0A
 %0A%0Acl
@@ -3430,8 +3430,210 @@
 rn size%0A
+%0A%0A@register.filter%0Adef prettyname(name):%0A    return ' '.join(%5Bword.capitalize() for word in name.split('_')%5D)%0A%0A%0A@register.filter%0Adef prettyvalue(value, key):%0A    return PrettyValue().format(key, value)%0A

Use ‚new style‘ template tag coding style. Adds Django 1.11 compatibility.