import os
import pylibmc
import hashlib
import logging
from cPickle import UnpickleableError

from totalimpact.utils import Retry

# set up logging
logger = logging.getLogger("ti.cache")

class CacheException(Exception):
    pass

class Cache(object):
    """ Maintains a cache of URL responses in memcached """

    def __init__(self, max_cache_age=86400):
        self.max_cache_age = max_cache_age

    @Retry(3, pylibmc.Error, 0.1)
    def get_cache_entry(self, url):
        """ Get an entry from the cache, returns None if not found """
        key = hashlib.md5(url.encode("utf-8")).hexdigest()
        mc = pylibmc.Client(
		    servers=[os.environ.get('MEMCACHE_SERVERS')],
		    username=os.environ.get('MEMCACHE_USERNAME'),
		    password=os.environ.get('MEMCACHE_PASSWORD'),
		    binary=True)
        return mc.get(key)

    @Retry(3, pylibmc.Error, 0.1)
    def set_cache_entry(self, url, data):
        """ Store a cache entry """
        key = hashlib.md5(url.encode("utf-8")).hexdigest()
        mc = pylibmc.Client(
		    servers=[os.environ.get('MEMCACHE_SERVERS')],
		    username=os.environ.get('MEMCACHE_USERNAME'),
		    password=os.environ.get('MEMCACHE_PASSWORD'),
		    binary=True)
        try:
            set_response = mc.set(key, data, time=self.max_cache_age)
            if not set_response:
                raise CacheException("Unable to store into Memcached. Make sure memcached server is running.")
        except UnpickleableError:
            # This happens when trying to cache a thread.lock object, for example.  Just don't cache.
            logger.debug("In set_cache_entry with " + url + " but got Error")
            set_response = None
        return (set_response)
  
        
        

@@ -48,16 +48,28 @@
 logging%0A
+import json%0A
 from cPi
@@ -331,152 +331,29 @@
 ef _
-_init__(self, max_cache_age=86400):%0A        self.max_cache_age = max_cache_age%0A%0A    @Retry(3, pylibmc.Error, 0.1)%0A    def get_cache_entr
+build_hash_ke
 y(self, 
 url)
@@ -348,19 +348,19 @@
 y(self, 
-url
+key
 ):%0A     
@@ -366,70 +366,34 @@
     
-%22%22%22 Get an entry from the cache, returns None if not found %22%22%22
+json_key = json.dumps(key)
 %0A   
@@ -389,32 +389,37 @@
 ps(key)%0A        
+hash_
 key = hashlib.md
@@ -412,35 +412,40 @@
 y = hashlib.md5(
-url
+json_key
 .encode(%22utf-8%22)
@@ -450,32 +450,94 @@
 %22)).hexdigest()%0A
+        return hash_key%0A%0A    def _get_memcached_client(self):%0A
         mc = pyl
@@ -541,34 +541,40 @@
 pylibmc.Client(%0A
-%09%09
+        
     servers=%5Bos.
@@ -599,34 +599,40 @@
 CHE_SERVERS')%5D,%0A
-%09%09
+        
     username=os.
@@ -657,34 +657,40 @@
 CHE_USERNAME'),%0A
-%09%09
+        
     password=os.
@@ -715,34 +715,40 @@
 CHE_PASSWORD'),%0A
-%09%09
+        
     binary=True)
@@ -769,16 +769,224 @@
 n mc
-.get(key
+%0A %0A    def __init__(self, max_cache_age=86400):%0A        self.max_cache_age = max_cache_age%0A%0A        # uncomment if you want to flush the cache%0A        #mc = self._get_memcached_client()        %0A        #mc.flush_all(
 )%0A%0A 
@@ -1026,17 +1026,17 @@
     def 
-s
+g
 et_cache
@@ -1052,17 +1052,11 @@
 lf, 
-url, data
+key
 ):%0A 
@@ -1070,293 +1070,384 @@
 %22%22%22 
-Store a cache entry %22%22%22%0A        key = hashlib.md5(url.encode(%22utf-8%22)).hexdigest()%0A        mc = pylibmc.Client(%0A%09%09    servers=%5Bos.environ.get('MEMCACHE_SERVERS')%5D,%0A%09%09    username=os.environ.get('MEMCACHE_USERNAME'),%0A%09%09    password=os.environ.get('MEMCACHE_PASSWORD'),%0A%09%09    binary=True
+Get an entry from the cache, returns None if not found %22%22%22%0A        mc = self._get_memcached_client()%0A        hash_key = self._build_hash_key(key)%0A        return mc.get(hash_key)%0A%0A    @Retry(3, pylibmc.Error, 0.1)%0A    def set_cache_entry(self, key, data):%0A        %22%22%22 Store a cache entry %22%22%22%0A        mc = self._get_memcached_client()%0A        hash_key = self._build_hash_key(key
 )%0A  
@@ -1491,16 +1491,21 @@
  mc.set(
+hash_
 key, dat

change url caching to include follow_redirect info