import string, mmap, os, cPickle
from utils import *
from searching import loop_in_C
import dictzip, sgmllib

from stat import ST_MTIME

execfile("config.py")

def unique_strings(l):
    dict = {}
    for s in l:
       dict[s] = 1
    return dict.keys()


class EmptyDb:
    def __init__(self, name):
        self.info = "empty database"
        self.name = name
        
    def match(self, strat, word):
        return []

    def define(self, word):
        return []

class FullDb:
    def __init__(self, name):
        self.info = "full database"
        self.name = name
        
    def match(self, strat, word):
        return [ (self.name, "one"), (self.name, "two") ]

    def define(self, word):
        return [ (self.name, "bla bla blablabla") ]


def dbargs(name, data=None, inx=None):
    """return tuple of: database name, database info, file object for data, positions of lines in index file
    """
    if not data:
        data = name+".dict"
    sep = os.sep
    sep1 = os.altsep or os.sep
    if not( (sep in data) or (sep1 in data) ):
        data = "/usr/share/dictd/%s" % data
    if not inx:
        inx = name+".index"
    if not( (sep in inx) or (sep1 in inx) ):
        inx = os.path.normpath("/usr/share/dictd/"+inx)
    if data[-3:]=='.dz':
        datafo = dictzip.DictzipFile(data)
    else:
        try:
            datafo = open(data)
        except IOError:
            datafo = dictzip.DictzipFile(data+".dz")
        
    cache_is_good = 0
    if caching:
        inx_cachename = os.path.join(cachedir, string.replace(inx, os.sep, '_'))
        if os.path.isfile(inx_cachename):
            s = os.stat(inx_cachename)
            ctimestamp = s[ST_MTIME]
            s = os.stat(inx)
            itimestamp = s[ST_MTIME]
            if ctimestamp > itimestamp:
                cache_is_good = 1

    if cache_is_good:
        try:
            f = open(inx_cachename)
            positions = cPickle.load(f)
            f.close()
        except:
            cache_is_good = 0

    indexfo = open(inx)
    indexfo.seek(0, 2)
    indexlen = indexfo.tell()
    inx = mmap.mmap(indexfo.fileno(), indexlen, prot=mmap.PROT_READ)
    inx.seek(0)
        
    if not cache_is_good:
        indexpos = []
        while 1:
            p = inx.tell()
            l = inx.readline()
            if not l:
                break
            l = string.split(l, TAB, 1)[0]
            indexpos.append((l, p))
        indexpos.sort()
        positions = [x[1] for x in indexpos]
        del indexpos
        if caching:
            f = open(inx_cachename, 'w')
            cPickle.dump(positions, f, 1)
            f.close()

    return datafo, positions, inx


class FileDb:
    """Entries in index are in UTF8, sorted byte-after-byte
    """
    def __init__(self, name, data=None, inx=None, info=None):
        if not info:
            info = name
        self.name = name
        self.info = info
        self.data = data
        self.inx = inx
        self.initialized = 0

    def initialize(self):
        if not self.initialized:
            self.datafo, self.positions, self.index = dbargs(self.name, self.data, self.inx)
            self.initialized = 1
            

    def transformentry(self, s):
        # transforms read entry into plain text
        # or, in the future, into mime/html/sgml/whatever
        # to be overriden
        return s

    def readentry(self, arg):
        entry, st, ln = arg
        self.datafo.seek(st)
        r = self.transformentry(self.datafo.read(ln))
        return self.name, r

    def define(self, word):
        self.initialize()
        r = []
        poss = loop_in_C(self.index, self.positions, word, 0, 0)
        for i in poss:
            self.index.seek(self.positions[i])
            l = string.rstrip(self.index.readline())
            entry, st, ln = string.split(l, TAB)
            st, ln = b64dec(st), b64dec(ln)
            r.append( (entry,st,ln) )
        r = map(self.readentry, r)
        return r

                
    def match(self, strategy, word):
        self.initialize()
        r = []
        if strategy=='.':
            strategy = 'lev'
        if strategies.has_key(strategy):
            strategy = strategies[strategy][0]
        else:
            return []
        # mmap pointer, list of index entries, word, strat, max nr
        r1 = loop_in_C(self.index, self.positions, word, strategy, 20)
        for i in r1:
            self.index.seek(self.positions[i])
            l = self.index.readline()
            entry, st, ln = string.split(l, TAB, 2)
            st, ln = b64dec(st), b64dec(ln)
            r.append( (entry, st, ln) )
        for i in range(len(r)):
            r[i] = self.name, r[i][0]
        #r = kjbuckets.kjSet(r).items()
        r = unique_strings(r)
        return r

        
    def __del__(self):
        self.datafo.close()
        self.index.close()



class FileDbDict(FileDb):
    """Entries in index are in UTF8, sorted byte-after-byte
       Database file is raw dict file (with %h, %d)
    """

    def transformentry(self, s):
        # transforms read entry into plain text
        rs = string.split(s, '\n')
        reply = []
        i = 0
        while 1:
            srs = string.lstrip(rs[i])
            if srs[:2] == '%h':
                reply.append(srs[2:])
                i+=1
            else:
                break
        if string.strip(rs[i])<>'%d':
            return 'wrong entry, please check'
        i+=1
        reply.append("-----") # separating entry and body
        reply.extend(rs[i:])
        return string.join(reply, '\n')



class Parser(sgmllib.SGMLParser):

    def __init__(self):
        sgmllib.SGMLParser.__init__(self)
        self.inorth = self.intr = 0
        self.result = ""
    
    def start_entry(self, a):
        pass
    def end_entry(self):
        self.result = process_entry(self.header, self.translations)

    def start_form(self, a):
        self.header = []
    def end_form(self):
        pass

    def start_orth(self, a):
        self.inorth = 1
    def end_orth(self):
        self.inorth = 0

    def start_tr(self, a):
        self.intr = 1
    def end_tr(self):
        self.intr = 0
        
    def start_trans(self, a):
        self.translations = []
    def end_trans(self):
        pass
        
    def handle_data(self, d):
        if self.inorth:
            self.header.append(d)
        elif self.intr:
            self.translations.append(d)
        

def process_entry(orths, trs):
    r = string.join(orths, seporth)+"\n"
    r = r + "  "+string.join(trs, septrans)+"\n"
    return r

class FileDbTeit(FileDb):
    """Entries in index are in UTF8, sorted byte-after-byte
       Database file is raw tei file
    """

    def transformentry(self, s):
        # transforms read entry into plain text

        rs = string.split(s, '\n')
        p = Parser()

        f = open(teifile)
        for i in rs:
            p.feed(rs)
        f.close()

        return p.result
     