import itertools
import pathlib
from pathlib import Path
from typing import Union

import gdspy

from gdsfactory.component import Component
from gdsfactory.import_gds import import_gds

COUNTER = itertools.count()


def xor_polygons(A: Component, B: Component, hash_geometry: bool = True):
    """Given two devices A and B, performs a layer-by-layer XOR diff between
    A and B, and returns polygons representing the differences between A and B.
    Adapted from lytest/kdb_xor.py
    """

    # first do a geometry hash to vastly speed up if they are equal
    if hash_geometry and (A.hash_geometry() == B.hash_geometry()):
        return Component()

    D = Component()
    A_polys = A.get_polygons(by_spec=True)
    B_polys = B.get_polygons(by_spec=True)
    A_layers = A_polys.keys()
    B_layers = B_polys.keys()
    all_layers = set()
    all_layers.update(A_layers)
    all_layers.update(B_layers)
    for layer in all_layers:
        if (layer in A_layers) and (layer in B_layers):
            p = gdspy.fast_boolean(
                A_polys[layer],
                B_polys[layer],
                operation="xor",
                precision=0.001,
                max_points=4000,
                layer=layer[0],
                datatype=layer[1],
            )
        elif layer in A_layers:
            p = A_polys[layer]
        elif layer in B_layers:
            p = B_polys[layer]
        if p is not None:
            D.add_polygon(p, layer=layer)
    return D


def gdsdiff(
    component1: Union[Path, Component, str],
    component2: Union[Path, Component, str],
    name: str = "TOP",
    xor: bool = True,
) -> Component:
    """Compare two Components.

    Args:
        component1: Component or path to gds file
        component2: Component or path to gds file
        name: name of the top cell
        xor: makes boolean operation

    Returns:
        Component with both cells (xor, common and diffs)
    """
    if isinstance(component1, pathlib.Path):
        component1 = str(component1)
    if isinstance(component2, pathlib.Path):
        component2 = str(component2)
    if isinstance(component1, str):
        component1 = import_gds(component1, flatten=True)
    if isinstance(component2, str):
        component2 = import_gds(component2, flatten=True)

    top = Component(name=f"{name}_diffs")

    if component1.name.startswith("Unnamed"):
        component1.name = f"{name}_old"
    if component2.name.startswith("Unnamed"):
        component2.name = f"{name}_new"

    ref1 = top << component1
    ref2 = top << component2

    ref1.xmin = 0
    ref1.ymin = 0
    ref2.xmin = 0
    ref2.ymin = 0

    if xor:
        diff = xor_polygons(ref1, ref2, hash_geometry=False)
        diff.name = f"{name}_xor"
        top.add_ref(diff)

    return top


if __name__ == "__main__":
    import sys

    if len(sys.argv) != 3:
        print("Usage: gdsdiff <mask_v1.gds> <mask_v2.gds>")
        print("Note that you need to have KLayout opened with klive running")
        sys.exit()
    c = gdsdiff(sys.argv[1], sys.argv[2])
    c.show()

import itertools
import pathlib
from pathlib import Path
from typing import Union

import gdspy

from gdsfactory.component import Component
from gdsfactory.import_gds import import_gds

COUNTER = itertools.count()


def xor_polygons(A: Component, B: Component, hash_geometry: bool = True):
    """Given two devices A and B, performs a layer-by-layer XOR diff between
    A and B, and returns polygons representing the differences between A and B.
    Adapted from lytest/kdb_xor.py
    """

    # first do a geometry hash to vastly speed up if they are equal
    if hash_geometry and (A.hash_geometry() == B.hash_geometry()):
        return Component()

    D = Component()
    A_polys = A.get_polygons(by_spec=True)
    B_polys = B.get_polygons(by_spec=True)
    A_layers = A_polys.keys()
    B_layers = B_polys.keys()
    all_layers = set()
    all_layers.update(A_layers)
    all_layers.update(B_layers)
    for layer in all_layers:
        if (layer in A_layers) and (layer in B_layers):
            p = gdspy.fast_boolean(
                A_polys[layer],
                B_polys[layer],
                operation="xor",
                precision=0.001,
                max_points=4000,
                layer=layer[0],
                datatype=layer[1],
            )
        elif layer in A_layers:
            p = A_polys[layer]
        elif layer in B_layers:
            p = B_polys[layer]
        if p is not None:
            D.add_polygon(p, layer=layer)
    return D


def gdsdiff(
    component1: Union[Path, Component, str],
    component2: Union[Path, Component, str],
    name: str = "TOP",
    xor: bool = True,
) -> Component:
    """Compare two Components.

    Args:
        component1: Component or path to gds file
        component2: Component or path to gds file
        name: name of the top cell
        xor: makes boolean operation

    Returns:
        Component with both cells (xor, common and diffs)
    """
    if isinstance(component1, pathlib.Path):
        component1 = str(component1)
    if isinstance(component2, pathlib.Path):
        component2 = str(component2)
    if isinstance(component1, str):
        component1 = import_gds(component1, flatten=True)
    if isinstance(component2, str):
        component2 = import_gds(component2, flatten=True)

    top = Component(name=f"{name}_diffs")

    if component1.name.startswith("Unnamed"):
        component1.name = f"{name}_old"
    if component2.name.startswith("Unnamed"):
        component2.name = f"{name}_new"

    ref1 = top << component1
    ref2 = top << component2

    ref1.xmin = 0
    ref1.ymin = 0
    ref2.xmin = 0
    ref2.ymin = 0

    if xor:
        diff = xor_polygons(ref1, ref2, hash_geometry=False)
        diff.name = f"{name}_xor"
        top.add_ref(diff)

    return top


if __name__ == "__main__":
    import sys

    if len(sys.argv) != 3:
        print("Usage: gdsdiff <mask_v1.gds> <mask_v2.gds>")
        print("Note that you need to have KLayout opened with klive running")
        sys.exit()
    c = gdsdiff(sys.argv[1], sys.argv[2])
    c.show()

Given two devices A and B, performs a layer-by-layer XOR diff between     A and B, and returns polygons representing the differences between A and B.     Adapted from lytest/kdb_xor.py # first do a geometry hash to vastly speed up if they are equal Compare two Components.      Args:         component1: Component or path to gds file         component2: Component or path to gds file         name: name of the top cell         xor: makes boolean operation      Returns:         Component with both cells (xor, common and diffs)