import os
import time
import fcntl
import pickle
import stat
import os
import re

from errno import ENOENT
from urllib import quote_plus

DEFAULT_TTL = 60 #minutes

DEFAULT_CACHE_PATH = "/tmp"
SUFFIX = "_cache.pck"

def to_filename(id, path=DEFAULT_CACHE_PATH):
    id = quote_plus(id)
    return os.path.join(path, "%s%s" % (id, SUFFIX))

class Cache(object):
    def __init__(self, id):
        self.id = id

    def __enter__(self):
        fcntl.flock(self.cachefile, fcntl.LOCK_EX)
        return self

    def __exit__(self, type, value, traceback):
        self.cachefile.close()

    def __str__(self):
        return self.data

    def _load_cache(self):
        self._ttl,self._data = pickle.load(self.cachefile)

    @property
    def mtime(self):
        try:
            return self._mtime
        except AttributeError:
            self._mtime = os.stat(self.path)[stat.ST_MTIME]
            return self._mtime

    @property
    def ttl(self):
        try:
            return self._ttl
        except AttributeError:
            self._load_cache();
            return self._ttl


    @property
    def data(self):
        try:
            return self._data
        except AttributeError:
            self._load_cache()
            return self._data

    @property
    def path(self):
        try:
            return self._path
        except AttributeError:
            self._path = to_filename(self.id)
            return self._path

    @property
    def cachefile(self):
        try:
            return self._cachefile
        except AttributeError:
            try:
                self._cachefile = open(self.path, "r+")
            except IOError, (errno,strerror):
                if errno == 2:
                    self._cachefile = open(self.path, "w+")
                else:
                    raise
            return self._cachefile

    def alive(self):
        try:
            return self.mtime + self.ttl > time.time()
        except:
            return False

    def remember(self, data, ttl=DEFAULT_TTL):
        self.cachefile.seek(0, os.SEEK_SET)
        pickle.dump((ttl, data), self.cachefile)
        self.cachefile.truncate()

        self._data = data
        self._ttl = ttl
        self._mtime = time.time()

    def clear(self):
        self._data = ""
        self._ttl = 0
        self._mtime = 0
        self.cachefile.close()

        try:
            os.unlink(self.path)
        except OSError, e:
            if e.errno == ENOENT: pass
            else: raise

