#
#  $Id: Directory.py,v 1.12 1999/12/11 12:35:12 rob Exp $
#
#  Copyright 1999 Rob Tillotson <robt@debian.org>
#  All Rights Reserved
#
#  Permission to use, copy, modify, and distribute this software and
#  its documentation for any purpose and without fee or royalty is
#  hereby granted, provided that the above copyright notice appear in
#  all copies and that both the copyright notice and this permission
#  notice appear in supporting documentation or portions thereof,
#  including modifications, that you you make.
#
#  THE AUTHOR ROB TILLOTSON DISCLAIMS ALL WARRANTIES WITH REGARD TO
#  THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
#  AND FITNESS.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
#  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
#  RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
#  CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
#  CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE!
#
"""Store in a local directory.  (Pure version)
"""

__version__ = '$Id: Directory.py,v 1.12 1999/12/11 12:35:12 rob Exp $'

__copyright__ = 'Copyright 1999 Rob Tillotson <robt@debian.org>'

import os, time

import Pyrite
import Pyrite.Store
from Pyrite import protect_name
from Pyrite import pdbfile, Database
from Pyrite import _

from Pyrite.prc import File

class DirectoryStore(Pyrite.Store.BaseStore):
    properties = ('read','create','delete','list')
    db_properties = ('id-unique', 'id-replace')
    
    def __init__(self, path='.'):
	Pyrite.Store.BaseStore.__init__(self)

	self.path = path

    def _open(self, name, mode='rs', properties=()):
	# this will be another inner API that we can put in a distributed object
	# return value is (inner-db-object, info-structure, mode, properties)
	# suitable for directly passing to the dbclass for instantiation
	if 'w' in mode:
	    raise RuntimeError, _("cannot open an existing database for write")
	t = self._find_db(name)
	if t is None: raise IOError, _("no such database: %s") % name
	return (t[0], t[1], mode, self.db_properties)
    
    def _create(self, name, creator, type, flags=0, version=1, filename=None,
		info=None):
	if flags is None: flags = 0
	i = { 'name': name,
	      'creator': creator,
	      'type': type,
	      'index': 0,
	      'more': 0,
	      'modnum': 0,
	      'version': version,
	      'createDate': int(time.time()),
	      'modifyDate': int(time.time()),
	      'backupDate': 0,
	      }
	i.update(pdbfile.flags_to_info(flags))
	if info is not None: i.update(info)
	if len(i['name']) > 31: i['name'] = i['name'][:31]

	if not filename:
	    filename = protect_name(name)+(flags & 0x0001 and '.prc' or '.pdb')
	f = File(os.path.join(self.path, filename), 0, 1, i)
	info = f.getDBInfo()
	return (f, info, 'rws', self.db_properties)
    
    def delete(self, name):
	db, i, n = self._find_db(name)
	if db is None: raise IOError, _("no such database: %s") % name
	db.close()
	os.unlink(os.path.join(self.path, n))

    def info(self, name):
	db, i, n = self._find_db(name)
	if db is None: raise IOError, _("no such database: %s") % name
	return db.info

    def list(self):
	return map(lambda x: x[1]['name'], pdbfile.listdir(self.path))

    def listinfo(self, name=None, creator=None, type=None):
	l = []
	for i in map(lambda x: x[1], pdbfile.listdir(self.path)):
	    if name is not None and i['name'] != name: continue
	    if creator is not None and i['creator'] != creator: continue
	    if type is not None and i['type'] != type: continue
	    l.append(i)

	return l	    

    def getpref(self, creator, id, saved=1):
	if saved: db, i, n = self._find_db('Saved Preferences')
	else: db, i, n = self._find_db('Unsaved Preferences')
	if db is None: raise RuntimeError, _("preferences database not found")

	for r in db:
	    if r.type == creator and r.id == id:
		v = struct.unpack('>H',r.raw[:2])[0]
		return r.raw[2:], v

	raise RuntimeError, _("preference '%s' %s not found") % (creator, id)

    # new stuff in preparation for dynamic objects
    def _try_open_db(self, fname, dbname=None):
	try:
	    f = File(fname)
	    i = f.getDBInfo()

	    if dbname is None or i['name'] == dbname: return (f, i)
	    else: return None
	except:
	    return None

    def _find_db(self, name):
	# %(name).pdb
	n = protect_name(name)+'.pdb'
	t = self._try_open_db(os.path.join(self.path,n), name)
	if t is not None: return t+(n,)
	# %(name).prc
	n = protect_name(name)+'.prc'
	t = self._try_open_db(os.path.join(self.path,n), name)
	if t is not None: return t+(n,)
	# %(name)
	n = protect_name(name)
	t = self._try_open_db(os.path.join(self.path,n), name)
	if t is not None: return t+(n,)
	# other arbitrary files
	for n, i in pdbfile.listdir(self.path):
	    if i['name'] == name:
		t = self._try_open_db(os.path.join(self.path,n), name)
		if t is not None: return t+(n,)
	return None
    # end new stuff
	

class Store(Pyrite.Store.Store):
    name = 'Directory'
    author = Pyrite.author
    version = Pyrite.version
    description = _("PRC/PDB files in a directory.")
    properties = ['read','create','delete','list']

    store_class = DirectoryStore
