
import os, sys, unittest, shutil, weakref
from threading import RLock
import test_PyLucene 

"""
The Directory Implementation here is for testing purposes only, not meant
as an example of writing one, the implementation here suffers from a lack
of safety when dealing with concurrent modifications as it does away with 
the file locking in the default lucene fsdirectory implementation.
"""

DEBUG = False

class DebugWrapper(object):

    def __init__(self, obj):
        self.obj = obj

    def __getattr__(self, name):
        print self.obj.__class__.__name__, self.obj.name, name
        sys.stdout.flush()
        return getattr(self.obj, name)
        
class DebugFactory(object):
    
    def __init__(self, klass):
        self.klass = klass
        
    def __call__(self, *args, **kw):
        instance = self.klass(*args, **kw)
        return DebugWrapper(instance)


class PythonDirLock(object):
    # only safe for a single process
    
    def __init__(self, name, path, lock):
        self.name = name
        self.lock_file = path
        self.lock = lock

    def isLocked(self):
        return self.lock.locked()

    def obtainTimeout(self, timeout):
        return self.lock.acquire(timeout)

    def obtain(self):
        return self.lock.acquire()

    def release(self):
        return self.lock.release()


class PythonFileStream(object):

    def __init__(self, name, fh, size=0L):
        self.name = name
        self.fh = fh
        self._length = size
        self.isOpen = True

    def close(self, isClone=False):
        if isClone or not self.isOpen:
            return
        self.isOpen = False
        self.fh.close()

    def seek(self, pos):
        self.fh.seek(pos)

    def read(self, length, pos):
        self.fh.seek(pos)
        return self.fh.read(length)

    def write(self, buffer):
        self.fh.write(buffer)
        self.fh.flush()
        self._length += len(buffer)

    def length(self):
        return self._length

        
class PythonFileDirectory(object):

    def __init__(self, path):
        self.name = path
        assert os.path.isdir(path)
        self.path = path
        self._locks = {}
        self._streams = []

    def close(self):
        for s in self._streams:
            s.close()

    def createOutput(self, name):
        file_path = os.path.join(self.path, name)
        fh = open(file_path, "w")
        stream = PythonFileStream(name, fh)
        self._streams.append(stream)
        return stream

    def deleteFile(self, name):
        if self.fileExists(name):
            os.unlink(os.path.join(self.path, name))

    def fileExists(self, name):
        return os.path.exists(os.path.join(self.path, name))

    def fileLength(self, name):
        file_path = os.path.join(self.path, name)
        return os.path.getsize(file_path)

    def fileModified(self, name):
        file_path = os.path.join(self.path, name)
        return os.path.getmtime(file_path)

    def list(self):
        return os.listdir(self.path)

    def makeLock(self, name):
        lock = self._locks.setdefault(name, RLock())
        return PythonDirLock(name, os.path.join(self.path, name), lock)

    def openInput(self, name):
        file_path = os.path.join(self.path, name)
        fh = open(file_path, 'r')
        stream = PythonFileStream(name, fh, os.path.getsize(file_path))
        self._streams.append(stream)
        return stream

    def renameFile(self, fname, tname):
        fromName = os.path.join(self.path, fname)
        toName = os.path.join(self.path, tname)
        if os.path.exists(toName):
            os.remove(toName)
        os.rename(fromName, toName)

    def touchFile(self, name):
        file_path = os.path.join(self.path, name)
        os.utime(file_path, None)


if DEBUG:
    _globals = globals()
    _globals['PythonFileDirectory'] = DebugFactory(PythonFileDirectory)
    _globals['PythonFileStream'] = DebugFactory(PythonFileStream)
    _globals['PythonDirLock'] = DebugFactory(PythonDirLock)
    del _globals

class PythonDirectoryTests(unittest.TestCase,
                            test_PyLucene.Test_PyLuceneBase):

    STORE_DIR = "testpyrepo"

    def setUp(self):
        if not os.path.exists(self.STORE_DIR):
            os.mkdir(self.STORE_DIR)

    def tearDown(self):
        if os.path.exists(self.STORE_DIR):
            shutil.rmtree(self.STORE_DIR)

    def openStore(self):
        return PythonFileDirectory(self.STORE_DIR)

    def closeStore(self, store, *args):
        for arg in args:
            if arg: arg.close()
        store.close()

    def test_IncrementalLoop(self):
        print "Testing Indexing Incremental Looping"
        for i in range(100):
            print "indexing ", i
            sys.stdout.flush()
            self.test_indexDocument()
                       

if __name__ == "__main__":
    import sys
    if '-loop' in sys.argv:
        sys.argv.remove('-loop')
        while True:
            try:
                unittest.main()
            except:
                pass
    else:
        unittest.main()


