"""Find an available uidNumber/gidNumber/other similar number."""

from OPSI.ldaptor.protocols import pureldap

class freeNumberGuesser:
    def __init__(self, makeAGuess, min=None, max=None):
        self.makeAGuess=makeAGuess
        self.min=min
        if self.min is None:
            self.min=0
        self.max=max

    def startGuessing(self):
        d=self.makeAGuess(self.min)
        d.addCallback(self._nextGuess, self.min)
        return d

    def _nextGuess(self, found, lastGuess):
        if found:
            self.min=lastGuess
        else:
            self.max=lastGuess

        if self.max==self.min \
           or self.max==self.min+1:
            return self.max

        max=self.max
        if max is None:
            max=self.min+1000

        guess=(max+self.min)/2
        d=self.makeAGuess(guess)
        d.addCallback(self._nextGuess, guess)
        return d

class ldapGuesser:
    def __init__(self, ldapObject, numberType):
        self.numberType=numberType
        self.ldapObject=ldapObject

    def guess(self, num):
        d=self.ldapObject.search(
            filterObject=pureldap.LDAPFilter_equalityMatch(
            attributeDesc=pureldap.LDAPAttributeDescription(value=self.numberType),
            assertionValue=pureldap.LDAPAssertionValue(value=str(num))),
            sizeLimit=1)
        d.addCallback(lambda results: len(results))
        return d

def getFreeNumber(ldapObject, numberType, min=None, max=None):
    g=freeNumberGuesser(ldapGuesser(ldapObject, numberType).guess,
                        min=min, max=max)
    return g.startGuessing()
