import os
import cPickle

from quixote import get_publisher

def lax_int(s):
    try:
        return int(s)
    except ValueError:
        return -1

def fix_key(k):
    # insure key can be inserted in filesystem
    if not k: return k
    return str(k).replace('/', '-')


class StorableObject(object):
    def __init__(self):
        if get_publisher():
            self.id = self.get_new_id()

    def get_table_name(cls):
        return cls._names
    get_table_name = classmethod(get_table_name)

    def get_objects_dir(cls):
        return os.path.join(get_publisher().app_dir, cls.get_table_name())
    get_objects_dir = classmethod(get_objects_dir)

    def keys(cls):
        if not os.path.exists(cls.get_objects_dir()):
            return []
        return [fix_key(x) for x in os.listdir(cls.get_objects_dir())]
    keys = classmethod(keys)

    def values(cls):
        return [cls.get(x) for x in cls.keys()]
    values = classmethod(values)

    def items(cls):
        return [(x, cls.get(x)) for x in cls.keys()]
    items = classmethod(items)
    
    def count(cls):
        return len(cls.keys())
    count = classmethod(count)

    def select(cls, clause = None, order_by = None):
        objects = [cls.get(k) for k in cls.keys()]
        if clause:
            objects = [x for x in objects if clause(x)]
        if order_by:
            order_by = str(order_by)
            if order_by[0] == '-':
                reverse = True
                order_by = order_by[1:]
            else:
                reverse = False
            objects.sort(lambda x,y: cmp(getattr(x, order_by), getattr(y, order_by)))
            if reverse:
                objects.reverse()
        return objects
    select = classmethod(select)
    
    def has_key(cls, id):
        return fix_key(id) in cls.keys()
    has_key = classmethod(has_key)

    def get_new_id(cls):
        keys = cls.keys()
        if not keys:
            id = 1
        else:
            id = max([lax_int(x) for x in keys]) + 1
            if id == 0:
                id = len(keys)+1
        return id
    get_new_id = classmethod(get_new_id)

    def get(cls, id):
        if id is None:
            raise KeyError()
        try:
            s = file(os.path.join(cls.get_objects_dir(), fix_key(id))).read()
        except IOError:
            raise KeyError()
        try:
            o = cPickle.loads(s)
        except EOFError:
            raise KeyError()
        o._names = cls._names
        if hasattr(cls, 'migrate'):
            o.migrate()
        return o
    get = classmethod(get)

    def store(self):
        if not os.path.exists(self.get_objects_dir()):
            os.mkdir(self.get_objects_dir())
        s = cPickle.dumps(self)
        file(os.path.join(self.get_objects_dir(), fix_key(self.id)), 'w').write(s)

    def volatile(cls):
        o = cls()
        o.id = None
        return o
    volatile = classmethod(volatile)

    def remove_object(cls, id):
        os.unlink(os.path.join(cls.get_objects_dir(), fix_key(id)))
    remove_object = classmethod(remove_object)

    def remove_self(self):
        os.unlink(os.path.join(self.get_objects_dir(), fix_key(self.id)))
