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

[((695, 781), 'rhinoscriptsyntax.GetObject', 'rs.GetObject', (['message'], {'preselect': '(True)', 'filter': '(rs.filter.point | rs.filter.textdot)'}), '(message, preselect=True, filter=rs.filter.point | rs.filter.\n    textdot)\n', (707, 781), True, 'import rhinoscriptsyntax as rs\n'), ((1327, 1414), 'rhinoscriptsyntax.GetObjects', 'rs.GetObjects', (['message'], {'preselect': '(True)', 'filter': '(rs.filter.point | rs.filter.textdot)'}), '(message, preselect=True, filter=rs.filter.point | rs.filter.\n    textdot)\n', (1340, 1414), True, 'import rhinoscriptsyntax as rs\n'), ((2090, 2175), 'rhinoscriptsyntax.GetObject', 'rs.GetObject', (['message'], {'preselect': '(True)', 'filter': '(rs.filter.mesh | rs.filter.textdot)'}), '(message, preselect=True, filter=rs.filter.mesh | rs.filter.textdot\n    )\n', (2102, 2175), True, 'import rhinoscriptsyntax as rs\n'), ((2736, 2822), 'rhinoscriptsyntax.GetObjects', 'rs.GetObjects', (['message'], {'preselect': '(True)', 'filter': '(rs.filter.mesh | rs.filter.textdot)'}), '(message, preselect=True, filter=rs.filter.mesh | rs.filter.\n    textdot)\n', (2749, 2822), True, 'import rhinoscriptsyntax as rs\n'), ((3507, 3593), 'rhinoscriptsyntax.GetObject', 'rs.GetObject', (['message'], {'preselect': '(True)', 'filter': '(rs.filter.curve | rs.filter.textdot)'}), '(message, preselect=True, filter=rs.filter.curve | rs.filter.\n    textdot)\n', (3519, 3593), True, 'import rhinoscriptsyntax as rs\n'), ((4238, 4325), 'rhinoscriptsyntax.GetObjects', 'rs.GetObjects', (['message'], {'preselect': '(True)', 'filter': '(rs.filter.curve | rs.filter.textdot)'}), '(message, preselect=True, filter=rs.filter.curve | rs.filter.\n    textdot)\n', (4251, 4325), True, 'import rhinoscriptsyntax as rs\n'), ((5112, 5198), 'rhinoscriptsyntax.GetObject', 'rs.GetObject', (['message'], {'preselect': '(True)', 'filter': '(rs.filter.point | rs.filter.textdot)'}), '(message, preselect=True, filter=rs.filter.point | rs.filter.\n    textdot)\n', (5124, 5198), True, 'import rhinoscriptsyntax as rs\n'), ((5756, 5843), 'rhinoscriptsyntax.GetObjects', 'rs.GetObjects', (['message'], {'preselect': '(True)', 'filter': '(rs.filter.point | rs.filter.textdot)'}), '(message, preselect=True, filter=rs.filter.point | rs.filter.\n    textdot)\n', (5769, 5843), True, 'import rhinoscriptsyntax as rs\n'), ((6551, 6637), 'rhinoscriptsyntax.GetObject', 'rs.GetObject', (['message'], {'preselect': '(True)', 'filter': '(rs.filter.curve | rs.filter.textdot)'}), '(message, preselect=True, filter=rs.filter.curve | rs.filter.\n    textdot)\n', (6563, 6637), True, 'import rhinoscriptsyntax as rs\n'), ((7305, 7392), 'rhinoscriptsyntax.GetObjects', 'rs.GetObjects', (['message'], {'preselect': '(True)', 'filter': '(rs.filter.curve | rs.filter.textdot)'}), '(message, preselect=True, filter=rs.filter.curve | rs.filter.\n    textdot)\n', (7318, 7392), True, 'import rhinoscriptsyntax as rs\n'), ((846, 865), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', (['guid'], {}), '(guid)\n', (859, 865), True, 'import rhinoscriptsyntax as rs\n'), ((1005, 1026), 'ast.literal_eval', 'ast.literal_eval', (['key'], {}), '(key)\n', (1021, 1026), False, 'import ast\n'), ((2240, 2259), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', (['guid'], {}), '(guid)\n', (2253, 2259), True, 'import rhinoscriptsyntax as rs\n'), ((2396, 2417), 'ast.literal_eval', 'ast.literal_eval', (['key'], {}), '(key)\n', (2412, 2417), False, 'import ast\n'), ((3658, 3677), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', (['guid'], {}), '(guid)\n', (3671, 3677), True, 'import rhinoscriptsyntax as rs\n'), ((3850, 3869), 'ast.literal_eval', 'ast.literal_eval', (['u'], {}), '(u)\n', (3866, 3869), False, 'import ast\n'), ((3890, 3909), 'ast.literal_eval', 'ast.literal_eval', (['v'], {}), '(v)\n', (3906, 3909), False, 'import ast\n'), ((5266, 5285), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', (['guid'], {}), '(guid)\n', (5279, 5285), True, 'import rhinoscriptsyntax as rs\n'), ((5423, 5444), 'ast.literal_eval', 'ast.literal_eval', (['key'], {}), '(key)\n', (5439, 5444), False, 'import ast\n'), ((6705, 6724), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', (['guid'], {}), '(guid)\n', (6718, 6724), True, 'import rhinoscriptsyntax as rs\n'), ((6897, 6916), 'ast.literal_eval', 'ast.literal_eval', (['u'], {}), '(u)\n', (6913, 6916), False, 'import ast\n'), ((6937, 6956), 'ast.literal_eval', 'ast.literal_eval', (['v'], {}), '(v)\n', (6953, 6956), False, 'import ast\n'), ((1532, 1551), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', (['guid'], {}), '(guid)\n', (1545, 1551), True, 'import rhinoscriptsyntax as rs\n'), ((2940, 2959), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', (['guid'], {}), '(guid)\n', (2953, 2959), True, 'import rhinoscriptsyntax as rs\n'), ((4443, 4462), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', (['guid'], {}), '(guid)\n', (4456, 4462), True, 'import rhinoscriptsyntax as rs\n'), ((5964, 5983), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', (['guid'], {}), '(guid)\n', (5977, 5983), True, 'import rhinoscriptsyntax as rs\n'), ((7513, 7532), 'rhinoscriptsyntax.ObjectName', 'rs.ObjectName', (['guid'], {}), '(guid)\n', (7526, 7532), True, 'import rhinoscriptsyntax as rs\n'), ((1752, 1773), 'ast.literal_eval', 'ast.literal_eval', (['key'], {}), '(key)\n', (1768, 1773), False, 'import ast\n'), ((3158, 3179), 'ast.literal_eval', 'ast.literal_eval', (['key'], {}), '(key)\n', (3174, 3179), False, 'import ast\n'), ((4705, 4724), 'ast.literal_eval', 'ast.literal_eval', (['u'], {}), '(u)\n', (4721, 4724), False, 'import ast\n'), ((4753, 4772), 'ast.literal_eval', 'ast.literal_eval', (['v'], {}), '(v)\n', (4769, 4772), False, 'import ast\n'), ((6182, 6203), 'ast.literal_eval', 'ast.literal_eval', (['key'], {}), '(key)\n', (6198, 6203), False, 'import ast\n'), ((7775, 7794), 'ast.literal_eval', 'ast.literal_eval', (['u'], {}), '(u)\n', (7791, 7794), False, 'import ast\n'), ((7823, 7842), 'ast.literal_eval', 'ast.literal_eval', (['v'], {}), '(v)\n', (7839, 7842), False, 'import ast\n')]