from __future__ import print_function
from __future__ import absolute_import
from __future__ import division

import ast
import rhinoscriptsyntax as rs


__all__ = [
    'mesh_select_vertex',
    'mesh_select_vertices',
    'mesh_select_face',
    'mesh_select_faces',
    'mesh_select_edge',
    'mesh_select_edges',
    'network_select_node',
    'network_select_nodes',
    'network_select_edge',
    'network_select_edges',
]


def mesh_select_vertex(mesh, message="Select a vertex."):
    """Select a single vertex of a mesh.

    Parameters
    ----------
    mesh: :class:`compas.datastructures.Mesh`
    message: str, optional

    Returns
    -------
    int or None
    """
    guid = rs.GetObject(message, preselect=True, filter=rs.filter.point | rs.filter.textdot)
    if guid:
        prefix = mesh.attributes['name']
        name = rs.ObjectName(guid).split('.')
        if 'vertex' in name:
            if not prefix or prefix in name:
                key = name[-1]
                return ast.literal_eval(key)
    return None


def mesh_select_vertices(mesh, message="Select vertices."):
    """Select multiple vertices of a mesh.

    Parameters
    ----------
    mesh: :class:`compas.datastructures.Mesh`
    message: str, optional

    Returns
    -------
    list of int
    """
    keys = []
    guids = rs.GetObjects(message, preselect=True, filter=rs.filter.point | rs.filter.textdot)
    if guids:
        prefix = mesh.attributes['name']
        seen = set()
        for guid in guids:
            name = rs.ObjectName(guid).split('.')
            if 'vertex' in name:
                if not prefix or prefix in name:
                    key = name[-1]
                    if not seen.add(key):
                        key = ast.literal_eval(key)
                        keys.append(key)
    return keys


def mesh_select_face(mesh, message="Select a face."):
    """Select a single face of a mesh.

    Parameters
    ----------
    mesh: :class:`compas.datastructures.Mesh`
    message: str, optional

    Returns
    -------
    int or None
    """
    guid = rs.GetObject(message, preselect=True, filter=rs.filter.mesh | rs.filter.textdot)
    if guid:
        prefix = mesh.attributes['name']
        name = rs.ObjectName(guid).split('.')
        if 'face' in name:
            if not prefix or prefix in name:
                key = name[-1]
                key = ast.literal_eval(key)
                return key
    return None


def mesh_select_faces(mesh, message="Select faces."):
    """Select multiple faces of a mesh.

    Parameters
    ----------
    mesh: :class:`compas.datastructures.Mesh`
    message: str, optional

    Returns
    -------
    list of int
    """
    keys = []
    guids = rs.GetObjects(message, preselect=True, filter=rs.filter.mesh | rs.filter.textdot)
    if guids:
        prefix = mesh.attributes['name']
        seen = set()
        for guid in guids:
            name = rs.ObjectName(guid).split('.')
            if 'face' in name:
                if not prefix or prefix in name:
                    key = name[-1]
                    if not seen.add(key):
                        key = ast.literal_eval(key)
                        keys.append(key)
    return keys


def mesh_select_edge(mesh, message="Select an edge."):
    """Select a single edge of a mesh.

    Parameters
    ----------
    mesh: :class:`compas.datastructures.Mesh`
    message: str, optional

    Returns
    -------
    tuple of int, or None
    """
    guid = rs.GetObject(message, preselect=True, filter=rs.filter.curve | rs.filter.textdot)
    if guid:
        prefix = mesh.attributes['name']
        name = rs.ObjectName(guid).split('.')
        if 'edge' in name:
            if not prefix or prefix in name:
                key = name[-1]
                u, v = key.split('-')
                u = ast.literal_eval(u)
                v = ast.literal_eval(v)
                return u, v
    return None


def mesh_select_edges(mesh, message="Select edges."):
    """Select multiple edges of a mesh.

    Parameters
    ----------
    mesh: :class:`compas.datastructures.Mesh`
    message: str, optional

    Returns
    -------
    list of tuple of int
    """
    keys = []
    guids = rs.GetObjects(message, preselect=True, filter=rs.filter.curve | rs.filter.textdot)
    if guids:
        prefix = mesh.attributes['name']
        seen = set()
        for guid in guids:
            name = rs.ObjectName(guid).split('.')
            if 'edge' in name:
                if not prefix or prefix in name:
                    key = name[-1]
                    if not seen.add(key):
                        u, v = key.split('-')
                        u = ast.literal_eval(u)
                        v = ast.literal_eval(v)
                        keys.append((u, v))
    return keys


def network_select_node(network, message="Select a node."):
    """Select a single node of a network.

    Parameters
    ----------
    network: :class:`compas.datastructures.Network`
    message: str, optional

    Returns
    -------
    hashable or None
    """
    guid = rs.GetObject(message, preselect=True, filter=rs.filter.point | rs.filter.textdot)
    if guid:
        prefix = network.attributes['name']
        name = rs.ObjectName(guid).split('.')
        if 'node' in name:
            if not prefix or prefix in name:
                key = name[-1]
                return ast.literal_eval(key)
    return None


def network_select_nodes(network, message="Select nodes."):
    """Select multiple nodes of a network.

    Parameters
    ----------
    network: :class:`compas.datastructures.Network`
    message: str, optional

    Returns
    -------
    list of hashable
    """
    keys = []
    guids = rs.GetObjects(message, preselect=True, filter=rs.filter.point | rs.filter.textdot)
    if guids:
        prefix = network.attributes['name']
        seen = set()
        for guid in guids:
            name = rs.ObjectName(guid).split('.')
            if 'node' in name:
                if not prefix or prefix in name:
                    key = name[-1]
                    if not seen.add(key):
                        key = ast.literal_eval(key)
                        keys.append(key)
    return keys


def network_select_edge(network, message="Select an edge."):
    """Select a single edge of a network.

    Parameters
    ----------
    network: :class:`compas.datastructures.Network`
    message: str, optional

    Returns
    -------
    tuple of hashable, or None
    """
    guid = rs.GetObject(message, preselect=True, filter=rs.filter.curve | rs.filter.textdot)
    if guid:
        prefix = network.attributes['name']
        name = rs.ObjectName(guid).split('.')
        if 'edge' in name:
            if not prefix or prefix in name:
                key = name[-1]
                u, v = key.split('-')
                u = ast.literal_eval(u)
                v = ast.literal_eval(v)
                return u, v
    return None


def network_select_edges(network, message="Select edges."):
    """Select multiple edges of a network.

    Parameters
    ----------
    network: :class:`compas.datastructures.Network`
    message: str, optional

    Returns
    -------
    list of tuple of hashable
    """
    keys = []
    guids = rs.GetObjects(message, preselect=True, filter=rs.filter.curve | rs.filter.textdot)
    if guids:
        prefix = network.attributes['name']
        seen = set()
        for guid in guids:
            name = rs.ObjectName(guid).split('.')
            if 'edge' in name:
                if not prefix or prefix in name:
                    key = name[-1]
                    if not seen.add(key):
                        u, v = key.split('-')
                        u = ast.literal_eval(u)
                        v = ast.literal_eval(v)
                        keys.append((u, v))
    return keys


# ==============================================================================
# Main
# ==============================================================================

if __name__ == '__main__':
    pass

[((35, 11, 35, 92), 'rhinoscriptsyntax.GetObject', 'rs.GetObject', (), '', True, 'import rhinoscriptsyntax as rs\n'), ((59, 12, 59, 94), 'rhinoscriptsyntax.GetObjects', 'rs.GetObjects', (), '', True, 'import rhinoscriptsyntax as rs\n'), ((86, 11, 86, 91), 'rhinoscriptsyntax.GetObject', 'rs.GetObject', (), '', True, 'import rhinoscriptsyntax as rs\n'), ((111, 12, 111, 93), 'rhinoscriptsyntax.GetObjects', 'rs.GetObjects', (), '', True, 'import rhinoscriptsyntax as rs\n'), ((138, 11, 138, 92), 'rhinoscriptsyntax.GetObject', 'rs.GetObject', (), '', True, 'import rhinoscriptsyntax as rs\n'), ((165, 12, 165, 94), 'rhinoscriptsyntax.GetObjects', 'rs.GetObjects', (), '', True, 'import rhinoscriptsyntax as rs\n'), ((194, 11, 194, 92), 'rhinoscriptsyntax.GetObject', 'rs.GetObject', (), '', True, 'import rhinoscriptsyntax as rs\n'), ((218, 12, 218, 94), 'rhinoscriptsyntax.GetObjects', 'rs.GetObjects', (), '', True, 'import rhinoscriptsyntax as rs\n'), ((245, 11, 245, 92), 'rhinoscriptsyntax.GetObject', 'rs.GetObject', (), '', True, 'import rhinoscriptsyntax as rs\n'), ((272, 12, 272, 94), 'rhinoscriptsyntax.GetObjects', 'rs.GetObjects', (), '', True, 'import rhinoscriptsyntax as rs\n'), ((38, 15, 38, 34), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', ({(38, 29, 38, 33): 'guid'}, {}), '(guid)', True, 'import rhinoscriptsyntax as rs\n'), ((42, 23, 42, 44), 'ast.literal_eval', 'ast.literal_eval', ({(42, 40, 42, 43): 'key'}, {}), '(key)', False, 'import ast\n'), ((89, 15, 89, 34), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', ({(89, 29, 89, 33): 'guid'}, {}), '(guid)', True, 'import rhinoscriptsyntax as rs\n'), ((93, 22, 93, 43), 'ast.literal_eval', 'ast.literal_eval', ({(93, 39, 93, 42): 'key'}, {}), '(key)', False, 'import ast\n'), ((141, 15, 141, 34), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', ({(141, 29, 141, 33): 'guid'}, {}), '(guid)', True, 'import rhinoscriptsyntax as rs\n'), ((146, 20, 146, 39), 'ast.literal_eval', 'ast.literal_eval', ({(146, 37, 146, 38): 'u'}, {}), '(u)', False, 'import ast\n'), ((147, 20, 147, 39), 'ast.literal_eval', 'ast.literal_eval', ({(147, 37, 147, 38): 'v'}, {}), '(v)', False, 'import ast\n'), ((197, 15, 197, 34), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', ({(197, 29, 197, 33): 'guid'}, {}), '(guid)', True, 'import rhinoscriptsyntax as rs\n'), ((201, 23, 201, 44), 'ast.literal_eval', 'ast.literal_eval', ({(201, 40, 201, 43): 'key'}, {}), '(key)', False, 'import ast\n'), ((248, 15, 248, 34), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', ({(248, 29, 248, 33): 'guid'}, {}), '(guid)', True, 'import rhinoscriptsyntax as rs\n'), ((253, 20, 253, 39), 'ast.literal_eval', 'ast.literal_eval', ({(253, 37, 253, 38): 'u'}, {}), '(u)', False, 'import ast\n'), ((254, 20, 254, 39), 'ast.literal_eval', 'ast.literal_eval', ({(254, 37, 254, 38): 'v'}, {}), '(v)', False, 'import ast\n'), ((64, 19, 64, 38), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', ({(64, 33, 64, 37): 'guid'}, {}), '(guid)', True, 'import rhinoscriptsyntax as rs\n'), ((116, 19, 116, 38), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', ({(116, 33, 116, 37): 'guid'}, {}), '(guid)', True, 'import rhinoscriptsyntax as rs\n'), ((170, 19, 170, 38), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', ({(170, 33, 170, 37): 'guid'}, {}), '(guid)', True, 'import rhinoscriptsyntax as rs\n'), ((223, 19, 223, 38), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', ({(223, 33, 223, 37): 'guid'}, {}), '(guid)', True, 'import rhinoscriptsyntax as rs\n'), ((277, 19, 277, 38), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', ({(277, 33, 277, 37): 'guid'}, {}), '(guid)', True, 'import rhinoscriptsyntax as rs\n'), ((69, 30, 69, 51), 'ast.literal_eval', 'ast.literal_eval', ({(69, 47, 69, 50): 'key'}, {}), '(key)', False, 'import ast\n'), ((121, 30, 121, 51), 'ast.literal_eval', 'ast.literal_eval', ({(121, 47, 121, 50): 'key'}, {}), '(key)', False, 'import ast\n'), ((176, 28, 176, 47), 'ast.literal_eval', 'ast.literal_eval', ({(176, 45, 176, 46): 'u'}, {}), '(u)', False, 'import ast\n'), ((177, 28, 177, 47), 'ast.literal_eval', 'ast.literal_eval', ({(177, 45, 177, 46): 'v'}, {}), '(v)', False, 'import ast\n'), ((228, 30, 228, 51), 'ast.literal_eval', 'ast.literal_eval', ({(228, 47, 228, 50): 'key'}, {}), '(key)', False, 'import ast\n'), ((283, 28, 283, 47), 'ast.literal_eval', 'ast.literal_eval', ({(283, 45, 283, 46): 'u'}, {}), '(u)', False, 'import ast\n'), ((284, 28, 284, 47), 'ast.literal_eval', 'ast.literal_eval', ({(284, 45, 284, 46): 'v'}, {}), '(v)', False, 'import ast\n')]