import logging
import os
import sys

logging.basicConfig()
##logging.basicConfig(level=logging.DEBUG)
##logger = logging.getLogger(__name__)

sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), r"..\..")))

import comtypes
import comtypes.client
import comtypes.connectionpoints
import comtypes.errorinfo
import comtypes.server
import comtypes.server.connectionpoints
import comtypes.typeinfo
from comtypes.hresult import S_OK

################################################################

# Create the wrapper in the comtypes.gen package, it will be named
# TestComServerLib; the name is derived from the 'library ' statement
# in the IDL file
if not hasattr(sys, "frozen"):
    # pathname of the type library file
    tlbfile = os.path.join(os.path.dirname(__file__), "TestComServer.tlb")
    # if running as frozen app (dll or exe), the wrapper should be in
    # the library archive, so we don't need to generate it.
    comtypes.client.GetModule(tlbfile)

# Import the wrapper
from comtypes.gen import TestComServerLib
from comtypes.gen.TestComServerLib import ITestComServer  # noqa

################################################################


# Implement the CoClass.  Use the coclass from the wrapper as base
# class, and use DualDispMixin as base class which provides default
# implementations of IDispatch, IProvideClassInfo, IProvideClassInfo2
# interfaces.  ISupportErrorInfo is implemented by the COMObject base
# class.
class TestComServer(
    TestComServerLib.TestComServer,  # the coclass from the typelib wrapper
    comtypes.server.connectionpoints.ConnectableObjectMixin,
):
    # The default interface from the typelib MUST be the first
    # interface, other interfaces can follow

    _com_interfaces_ = TestComServerLib.TestComServer._com_interfaces_ + [
        comtypes.typeinfo.IProvideClassInfo2,
        comtypes.errorinfo.ISupportErrorInfo,
        comtypes.connectionpoints.IConnectionPointContainer,
    ]

    # registry entries
    _reg_threading_ = "Both"
    _reg_progid_ = "TestComServerLib.TestComServer.1"
    _reg_novers_progid_ = "TestComServerLib.TestComServer"
    _reg_desc_ = "comtypes COM server sample for testing"
    _reg_clsctx_ = comtypes.CLSCTX_INPROC_SERVER | comtypes.CLSCTX_LOCAL_SERVER

    ################################
    # ITestComServer methods

    def ITestComServer__get_array(self, this, parray):
        # Hm, why is assignment to value needed?

        # these leak
        # parray[0].value = (1, "2", None, 3.14)
        # parray[0].value = (1, "2", None)

        # parray[0].value = ((1, 2, 3), (4, 5, 6), (7, 8, 9))
        # parray[0].value = (1,), (4,)

        # parray[0].value = (), ()
        # parray[0].value = (), 0

        # leakage
        # parray[0].value = (((127900.0, None, 2620),
        #                     (127875.0, None, 2335),
        #                     (127675.0, 1071, None)),
        #                     127800.0)

        # reported *no* leakage, but leaks anyway
        # parray[0].value = ((128000.0, None, 2576),
        #                     (127975.0, None, 1923),
        #                     (127950.0, None, 1734))

        # these don't leak
        # parray[0].value = (1, 2, 3)
        # parray[0].value = (1, 2, None)
        # parray[0].value = (1, 3.14)
        # parray[0].value = [1, "(1, 2, 3)"]
        # parray[0].value = (1, "2")
        # parray[0].value = [1, "2"]
        # parray[0].value = (None, None, None)

        # parray[0].value = (),

        return S_OK

    def ITestComServer_eval(self, this, what, presult):
        self.Fire_Event(0, "EvalStarted", what)
        presult[0].value = eval(what)
        self.Fire_Event(0, "EvalCompleted", what, presult[0].value)
        return S_OK

    def ITestComServer__get_id(self, this, pid):
        pid[0] = id(self)
        return S_OK

    def ITestComServer_Exec(self, this, what):
        exec(what)
        return S_OK

    def ITestComServer_Exec2(self, what):
        exec(what)

    _name = "spam, spam, spam"

    def _get_name(self):
        return self._name

    def ITestComServer__set_name(self, this, name):
        self._name = name
        return S_OK

    # def ITestComServer_SetName(self, this, name):
    #     self._name = name
    #     return S_OK

    def ITestComServer_sEtNaMe(self, this, name):
        # the method is spelled in a funny way to check case
        # insensitivity when implementing COM methods.
        self._name = name
        return S_OK

    # [id(18), helpstring("a method with [in] and [out] args in mixed order")]
    # HRESULT MixedInOut([in] int a, [out] int *b, [in] int c, [out] int *d);
    def MixedInOut(self, a, c):
        return a + 1, c + 1


if __name__ == "__main__":
    try:
        from comtypes.server.register import UseCommandLine

        # logging.basicConfig(level=logging.DEBUG)
        UseCommandLine(TestComServer)
    except Exception:
        import traceback

        traceback.print_exc()
        input()
