import win32com
import win32com.client

if type(__path__) == type(""):
    # For freeze to work!
    import sys

    try:
        import adsi

        sys.modules["win32com.adsi.adsi"] = adsi
    except ImportError:
        pass
else:
    # See if we have a special directory for the binaries (for developers)
    win32com.__PackageSupportBuildPath__(__path__)


# Some helpers
# We want to _look_ like the ADSI module, but provide some additional
# helpers.

# Of specific note - most of the interfaces supported by ADSI
# derive from IDispatch - thus, you get the custome methods from the
# interface, as well as via IDispatch.
import pythoncom
from .adsi import *

LCID = 0

IDispatchType = pythoncom.TypeIIDs[pythoncom.IID_IDispatch]
IADsContainerType = pythoncom.TypeIIDs[adsi.IID_IADsContainer]


def _get_good_ret(
    ob,
    # Named arguments used internally
    resultCLSID=None,
):
    assert resultCLSID is None, "Now have type info for ADSI objects - fix me!"
    # See if the object supports IDispatch
    if hasattr(ob, "Invoke"):
        import win32com.client.dynamic

        name = "Dispatch wrapper around %r" % ob
        return win32com.client.dynamic.Dispatch(ob, name, ADSIDispatch)
    return ob


class ADSIEnumerator:
    def __init__(self, ob):
        # Query the object for the container interface.
        self._cont_ = ob.QueryInterface(IID_IADsContainer)
        self._oleobj_ = ADsBuildEnumerator(self._cont_)  # a PyIADsEnumVARIANT
        self.index = -1

    def __getitem__(self, index):
        return self.__GetIndex(index)

    def __call__(self, index):
        return self.__GetIndex(index)

    def __GetIndex(self, index):
        if type(index) != type(0):
            raise TypeError("Only integer indexes are supported for enumerators")
        if index != self.index + 1:
            # Index requested out of sequence.
            raise ValueError("You must index this object sequentially")
        self.index = index
        result = ADsEnumerateNext(self._oleobj_, 1)
        if len(result):
            return _get_good_ret(result[0])
        # Failed - reset for next time around.
        self.index = -1
        self._oleobj_ = ADsBuildEnumerator(self._cont_)  # a PyIADsEnumVARIANT
        raise IndexError("list index out of range")


class ADSIDispatch(win32com.client.CDispatch):
    def _wrap_dispatch_(
        self, ob, userName=None, returnCLSID=None, UnicodeToString=None
    ):
        assert UnicodeToString is None, "this is deprectated and will be removed"
        if not userName:
            userName = "ADSI-object"
        olerepr = win32com.client.dynamic.MakeOleRepr(ob, None, None)
        return ADSIDispatch(ob, olerepr, userName)

    def _NewEnum(self):
        try:
            return ADSIEnumerator(self)
        except pythoncom.com_error:
            # doesnt support it - let our base try!
            return win32com.client.CDispatch._NewEnum(self)

    def __getattr__(self, attr):
        try:
            return getattr(self._oleobj_, attr)
        except AttributeError:
            return win32com.client.CDispatch.__getattr__(self, attr)

    def QueryInterface(self, iid):
        ret = self._oleobj_.QueryInterface(iid)
        return _get_good_ret(ret)


# We override the global methods to do the right thing.
_ADsGetObject = ADsGetObject  # The one in the .pyd


def ADsGetObject(path, iid=pythoncom.IID_IDispatch):
    ret = _ADsGetObject(path, iid)
    return _get_good_ret(ret)


_ADsOpenObject = ADsOpenObject


def ADsOpenObject(path, username, password, reserved=0, iid=pythoncom.IID_IDispatch):
    ret = _ADsOpenObject(path, username, password, reserved, iid)
    return _get_good_ret(ret)
