import snappy
import regina
import snappy.snap.t3mlite as t3m
import snappy.snap.t3mlite.spun as spun


def hash_t3m_surface(surface):
    ans = [surface.EulerCharacteristic]
    ans += sorted(surface.EdgeWeights)
    ans += sorted(surface.Quadvector)
    return ans


def hash_regina_surface(S):
    T = S.getTriangulation()
    t = T.getNumberOfTetrahedra()
    ans = [S.getEulerCharacteristic()]
    ans += sorted([S.getEdgeWeight(i) for i in range(T.getNumberOfEdges())])
    ans += sorted([S.getQuadCoord(i, j) for i in range(t) for j in range(3)])
    return ans


def to_regina(snappy_manifold):
    return regina.NTriangulation(snappy_manifold._to_string())


def vertex_surfaces(regina_triangulation):
    """
    Enumerate the vertex surfaces of the given triangulation
    in quad coordinates.
    """
    surfaces = regina.NNormalSurfaceList.enumerate(
        regina_triangulation, regina.NS_QUAD)
    for i in range(surfaces.getNumberOfSurfaces()):
        yield surfaces.getSurface(i)


def compare_closed(snappy_manifold):
    N = snappy_manifold.filled_triangulation()

    T = t3m.Mcomplex(N)
    T.find_normal_surfaces()
    t_hashes = sorted( hash_t3m_surface(S) for S in T.NormalSurfaces )

    R = to_regina(N)
    r_hashes = sorted( hash_regina_surface(S) for S in vertex_surfaces(R))

    all_together = sum(t_hashes, [])
    return t_hashes == r_hashes, len(all_together), sum(all_together)


def regina_boundary_slope(surface):
    slope = surface.boundaryIntersections()
    a = int(slope.entry(0,0).stringValue())
    b = int(slope.entry(0,1).stringValue())
    return (b, -a)


def compare_cusped(snappy_manifold):
    tri_data = snappy_manifold._to_string()
    T = spun.Manifold(tri_data)
    t_hashes = sorted(sorted(S.quad_vector()) for S in T.normal_surfaces())
    t_slopes = sorted(tuple(S.boundary_slopes()) for S in T.normal_surfaces())

    R = regina.NSnapPeaTriangulation(tri_data)
    t = R.getNumberOfTetrahedra()
    regina_surfaces = list(vertex_surfaces(R))
    r_hashes = sorted(
        sorted(int(S.getQuadCoord(i, j).stringValue())
                      for i in range(t) for j in range(3))
        for S in regina_surfaces)
    r_slopes = sorted(map(regina_boundary_slope, regina_surfaces))

    assert t_hashes == r_hashes and t_slopes == r_slopes


def closed_test(N=10):
    for M in snappy.OrientableClosedCensus[:N]:
        print(M, compare_closed(M))


def cusped_test(N=100):
    for census in [snappy.CensusKnots, snappy.OrientableCuspedCensus(cusps=1)]:
        for M in census:
            print(M)
            compare_cusped(M)
