# -*- coding: utf-8 -*-

"""
The postman project - storage.py

This file is released under the BSD license, see LICENSE for
more information.

Francisco de Borja Lopez Rio - <borja@codigo23.net>
Soluciones Informaticas Codigo23 S.L.U. - http://codigo23.net
"""

import os, errno, json


class JsonStorage():

    """
    Json-based storage. 
    """

    def __init__(self, path='storage.json'):
        if os.path.isdir(path):
            raise IOError(path, ' is a directory, exiting')
        self.path = path

    def exists(self):
        return os.path.exists(self.path)    

    def create(self):
        """
        Ensure all the subdirectories in the path to the storage file
        exist
        """
        try:
            os.makedirs(os.path.dirname(self.path))
        except OSError, e:
            # If the dir already exists do not complain, if it is
            # any other error, raise the exception
            if e.errno != errno.EEXIST:
                raise
    
    def jsonize(self, obj):
        """
        Convert objects to a dictionary of their representation
        Based on the exmplaes from Doyg Hellmann:
        http://www.doughellmann.com/PyMOTW/json/#working-with-your-own-types
        """
        jobj = { '__class__':obj.__class__.__name__, 
                 '__module__':obj.__module__,
                 }
        jobj.update(obj.__dict__)
        return jobj

    def dejsonize(self, jobj):
        """
        Convert some data that has been "jsonized" to the original
        python object. Again, based on the examples from Doug Hellmann
        """
        if '__class__' in jobj:
            class_name = jobj.pop('__class__')
            module_name = jobj.pop('__module__')
            module = __import__(module_name)
            class_ = getattr(module, class_name)
            args = dict((key.encode('ascii'), value) \
                        for key, value in jobj.items())
            return class_(**args)
        return jobj
        
    def write(self, data):
        if not self.exists():
            # ensure the path to the storage file exists
            self.create()
        with open(self.path, 'w') as storage:
            json.dump(data, storage, sort_keys=True, indent=4,
                      default=self.jsonize)
            return True 
        return False 

    def read(self):        
        with open(self.path, 'r') as storage:
            try:
                data = json.load(storage,object_hook=self.dejsonize)
            except ValueError:
                # if no json data could be imported, the file could be
                # damaged or perhaps it does not containg json-encoded
                # data, simply return an empty string
                #
                # FIXME: we should notify the user about the problem
                return ''
        return data

    def delete(self):
        """
        Remove the storage file
        """
        if self.exists():
            os.remove(self.path)
            return True
        return False
