##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################

from BTrees.IIBTree import IIBucket
from BTrees.IIBTree import weightedIntersection, weightedUnion, difference
from BTrees.OOBTree import OOSet, union

class ResultList:

    def __init__(self, d, words, index, TupleType=type(())):
        self._index = index

        if type(words) is not OOSet: words=OOSet(words)
        self._words = words

        if (type(d) is TupleType):
            d = IIBucket((d,))
        elif type(d) is not IIBucket:
            d = IIBucket(d)

        self._dict=d
        self.__getitem__=d.__getitem__
        try: self.__nonzero__=d.__nonzero__
        except: pass
        self.get=d.get

    def __nonzero__(self):
        return not not self._dict

    def bucket(self): return self._dict

    def keys(self): return self._dict.keys()

    def has_key(self, key): return self._dict.has_key(key)

    def items(self): return self._dict.items()

    def __and__(self, x):
        return self.__class__(
            weightedIntersection(self._dict, x._dict)[1],
            union(self._words, x._words),
            self._index,
            )

    def and_not(self, x):
        return self.__class__(
            difference(self._dict, x._dict),
            self._words,
            self._index,
            )

    def __or__(self, x):
        return self.__class__(
            weightedUnion(self._dict, x._dict)[1],
            union(self._words, x._words),
            self._index,
            )
        # return self.__class__(result, self._words+x._words, self._index)

    def near(self, x):
        result = IIBucket()
        dict = self._dict
        xdict = x._dict
        xhas = xdict.has_key
        positions = self._index.positions
        for id, score in dict.items():
            if not xhas(id): continue
            p=(map(lambda i: (i,0), positions(id,self._words))+
               map(lambda i: (i,1), positions(id,x._words)))
            p.sort()
            d = lp = 9999
            li = None
            lsrc = None
            for i,src in p:
                if i is not li and src is not lsrc and li is not None:
                    d = min(d,i-li)
                li = i
                lsrc = src
            if d==lp: score = min(score,xdict[id]) # synonyms
            else: score = (score+xdict[id])/d
            result[id] = score

        return self.__class__(
            result, union(self._words, x._words), self._index)
