import asyncio

from parat.services import ParaT, PipelineBuilder, DefinitionManager, PropertyManager

HAS_YAML = False
try:
    import yaml

    HAS_YAML = True
except ImportError:
    pass

import os


def write_definition(definition, filename):
    if HAS_YAML:
        base_path = os.getcwd()
        with open(base_path + "/" + filename, "w") as test:
            test.write(yaml.dump(definition.as_dict()))


async def listen_definitions(definitionManager, group_name=""):

    async for all_definitions in definitionManager.GetDefinitionsObservable(group_name):
        for group, name in all_definitions:
            print(f"{group} -  {name}")


async def main():
    App = ParaT()
    session = await App.initialize()

    builder = PipelineBuilder(session)

    sphere = await builder.CreateProxy(
        "sources", "SphereSource", ThetaResolution=80, Radius=2
    )
    wavelet = await builder.CreateProxy("sources", "RTAnalyticSource")

    shrink = await builder.CreateProxy(
        "filters", "ShrinkFilter", Input=sphere, ShrinkFactor=0.3
    )

    pm = PropertyManager()
    await pm.UpdatePipeline(shrink)
    await pm.UpdatePipeline(wavelet)

    definitionManager = DefinitionManager(session)

    shrinkDef = definitionManager.GetDefinition(shrink)
    sphereDef = definitionManager.GetDefinition(sphere)

    print(type(sphereDef))
    print(sphereDef.as_dict())

    write_definition(sphereDef, "sphere.yaml")
    write_definition(shrinkDef, "shrinkDef.yaml")

    definition = definitionManager.GetDefinition("sources", "RTAnalyticSource")

    write_definition(definition, "wavelet.yaml")

    definition = definitionManager.GetDefinition("filters", "Contour")

    write_definition(definition, "contour.yaml")

    definition = definitionManager.GetDefinition(
        "representations", "GeometryRepresentation"
    )

    write_definition(definition, "geometry.yaml")

    result = DefinitionManager.vtkPVXMLElement_to_string(
        definitionManager.GetLayout(sphere)
    )
    print(result)
    result = DefinitionManager.vtkPVXMLElement_to_string(
        definitionManager.GetLayout(wavelet)
    )
    print(result)

    result = DefinitionManager.vtkPVXMLElement_to_string(
        definitionManager.GetLayout("sources", "RTAnalyticSource")
    )
    print(result)
    result = DefinitionManager.vtkPVXMLElement_to_string(
        definitionManager.GetLayout("representations", "GeometryRepresentation")
    )
    print(result)

    # ===================== Decorators =====================

    point2cell = await builder.CreateProxy(
        "filters", "PointDataToCellData", Input=sphere
    )

    definition = definitionManager.GetDefinition(point2cell)
    write_definition(definition, "point2cell.yaml")

    for prop in definition.GetProperties():
        if len(prop.GetDecorators()) != 0:
            print(prop.GetDecorators())
            decorators = definitionManager.GetPropertyDecorators(
                point2cell, prop.GetName()
            )
            for decorator in decorators:
                print(
                    decorator.canShowWidget(False)
                )  # should we show widget (show_advanced = False) ?
                print(decorator.enableWidget())  # should we enable the widget ?

    #  ===================== Definition Lists =====================
    #  Iterate through all definitions
    asyncio.create_task(listen_definitions(definitionManager))
    #  Iterate through all definitions within a group
    asyncio.create_task(listen_definitions(definitionManager, "sources"))

    l = []
    for _, name in definitionManager.GetCompatibleDefinitions(wavelet, "filters"):
        l.append(name)
    assert all(filter in l for filter in ["ImageClip", "WarpScalar"])
    assert all(filter not in l for filter in ["CellDataToPointData", "WarpVector"])

    l = []
    for _, name in definitionManager.GetCompatibleDefinitions(sphere, "filters"):
        l.append(name)
    assert all(filter in l for filter in ["PointDataToCellData", "WarpVector"])
    assert all(filter not in l for filter in ["ImageClip", "WarpScalar"])

    l = []
    for _, name in definitionManager.GetCompatibleDefinitions(
        [sphere, shrink], "filters"
    ):
        l.append(name)
    l.sort()
    assert l == ["Append", "AppendAttributes", "GroupDataSets", "MergeTime"]

    l = []
    for _, name in definitionManager.GetCompatibleDefinitions(
        [sphere, wavelet], "filters"
    ):
        l.append(name)
    l.sort()
    assert l == ["Append", "AppendAttributes", "GroupDataSets", "MergeTime"]

    await asyncio.sleep(0.1)
    # The destructor of definitionManager will terminate the async loops.
    # If you need to terminate them earlier use
    definitionManager.UnsubscribeAll()


asyncio.run(main())
