#<pycode(py_kernwin_viewhooks)>
# -----------------------------------------------------------------------
#                           CustomIDAMemo
# -----------------------------------------------------------------------
class CustomIDAMemo(View_Hooks):
    def __init__(self):
        View_Hooks.__init__(self)

    def _graph_item_tuple(self, ve):
        item = None
        if ve.rtype in [TCCRT_GRAPH, TCCRT_PROXIMITY]:
            item = ve.location.item
        if item is not None:
            if item.is_node:
                return (item.node,)
            else:
                return (item.elp.e.src, item.elp.e.dst)
        else:
            return ()

    @staticmethod
    def _dummy_cb(*args):
        pass

    def _get_cb(self, view, cb_name):
        cb = CustomIDAMemo._dummy_cb
        if view == self.GetWidget():
            cb = getattr(self, cb_name, cb)
        return cb

    def _get_cb_arity(self, cb):
        import sys
        import inspect
        if sys.version_info.major >= 3:
            return len(inspect.getfullargspec(cb).args)
        else:
            return len(inspect.getargspec(cb).args)

    def view_activated(self, view):
        return self._get_cb(view, "OnViewActivated")()

    def view_deactivated(self, view):
        return self._get_cb(view, "OnViewDeactivated")()

    def view_keydown(self, view, key, state):
        return self._get_cb(view, "OnViewKeydown")(key, state)

    def view_click(self, view, ve):
        cb = self._get_cb(view, "OnViewClick")
        if cb != CustomIDAMemo._dummy_cb:
            arity = self._get_cb_arity(cb)
            args = [ve.x, ve.y, ve.state]
            if arity >= 5:
                args.append(ve.button)
                if arity >= 6:
                    args.append(ve.renderer_pos)
            return cb(*tuple(args))

    def view_dblclick(self, view, ve):
        cb = self._get_cb(view, "OnViewDblclick")
        if cb != CustomIDAMemo._dummy_cb:
            arity = self._get_cb_arity(cb)
            args = [ve.x, ve.y, ve.state]
            if arity >= 5:
                args.append(ve.renderer_pos)
            return cb(*tuple(args))

    def view_curpos(self, view, *args):
        return self._get_cb(view, "OnViewCurpos")()

    def view_close(self, view, *args):
        rc = self._get_cb(view, "OnClose")()
        if view == self.GetWidget():
            ida_idaapi.pycim_view_close(self)
        return rc

    def view_switched(self, view, rt):
        return self._get_cb(view, "OnViewSwitched")(rt)

    def view_mouse_over(self, view, ve):
        cb = self._get_cb(view, "OnViewMouseOver")
        if cb != CustomIDAMemo._dummy_cb:
            arity = self._get_cb_arity(cb)
            gitpl = self._graph_item_tuple(ve)
            args = [ve.x, ve.y, ve.state, len(gitpl), gitpl]
            if arity >= 7:
                args.append(ve.renderer_pos)
            return cb(*tuple(args))

    def view_loc_changed(self, view, now, was):
        return self._get_cb(view, "OnViewLocationChanged")(now, was)

    def view_mouse_moved(self, view, ve):
        cb = self._get_cb(view, "OnViewMouseMoved")
        if cb != CustomIDAMemo._dummy_cb:
            gitpl = self._graph_item_tuple(ve)
            return cb(ve.x, ve.y, ve.state, len(gitpl), gitpl, ve.renderer_pos)

    def _OnBind(self, hook):
        if hook:
            self.hook()
        else:
            self.unhook()

    # End of hooks->wrapper trampolines


    def Refresh(self):
        """
        Refreshes the view. This causes the OnRefresh() to be called
        """
        ida_idaapi.pygc_refresh(self)

    def GetCurrentRendererType(self):
        return get_view_renderer_type(self.GetWidget())

    def SetCurrentRendererType(self, rtype):
        """
        Set the current view's renderer.

        :param rtype: The renderer type. Should be one of the idaapi.TCCRT_* values.
        """
        return set_view_renderer_type(self.GetWidget(), rtype)

    def SetNodeInfo(self, node_index, node_info, flags):
        """
        Set the properties for the given node.

        Example usage (set second nodes's bg color to red):
          inst = ...
          p = idaapi.node_info_t()
          p.bg_color = 0x00ff0000
          inst.SetNodeInfo(1, p, idaapi.NIF_BG_COLOR)

        :param node_index: The node index.
        :param node_info: An idaapi.node_info_t instance.
        :param flags: An OR'ed value of NIF_* values.
        """
        import ida_graph
        return ida_graph.viewer_set_node_info(self.GetWidget(), node_index, node_info, flags)

    def SetNodesInfos(self, values):
        """
        Set the properties for the given nodes.

        Example usage (set first three nodes's bg color to purple):
          inst = ...
          p = idaapi.node_info_t()
          p.bg_color = 0x00ff00ff
          inst.SetNodesInfos({0 : p, 1 : p, 2 : p})

        :param values: A dictionary of 'int -> node_info_t' objects.
        """
        import ida_graph
        for node_index, node_info in values.items():
            ida_graph.viewer_set_node_info(self.GetWidget(), node_index, node_info, ida_graph.NIF_ALL)

    def GetNodeInfo(self, *args):
        """
        Get the properties for the given node.

        :param ni: A node_info_t instance
        :param node: The index of the node.
        :returns: success
        """
        import ida_graph
        if len(args) < 2:
            # bw-compat
            ni, node = ida_graph.node_info_t(), args[0]
            if ida_graph.viewer_get_node_info(self.GetWidget(), ni, node):
                return (ni.bg_color, ni.frame_color, ni.ea, ni.text)
            else:
                return None
        else:
            ni, node = args[0], args[1]
            return ida_graph.viewer_get_node_info(self.GetWidget(), ni, node)

    def DelNodesInfos(self, *nodes):
        """
        Delete the properties for the given node(s).

        :param nodes: A list of node IDs
        """
        import ida_graph
        for n in nodes:
            ida_graph.viewer_del_node_info(self.GetWidget(), n)

    def CreateGroups(self, groups_infos):
        """
        Send a request to modify the graph by creating a
        (set of) group(s), and perform an animation.

        Each object in the 'groups_infos' list must be of the format:
        {
          "nodes" : [<int>, <int>, <int>, ...] # The list of nodes to group
          "text" : <string>                    # The synthetic text for that group
        }

        :param groups_infos: A list of objects that describe those groups.
        :returns: A [<int>, <int>, ...] list of group nodes, or None (failure).
        """
        return ida_idaapi.pygc_create_groups(self, groups_infos)

    def DeleteGroups(self, groups, new_current = -1):
        """
        Send a request to delete the specified groups in the graph,
        and perform an animation.

        :param groups: A list of group node numbers.
        :param new_current: A node to focus on after the groups have been deleted
        :returns: True on success, False otherwise.
        """
        return ida_idaapi.pygc_delete_groups(self, groups, new_current)

    def SetGroupsVisibility(self, groups, expand, new_current = -1):
        """
        Send a request to expand/collapse the specified groups in the graph,
        and perform an animation.

        :param groups: A list of group node numbers.
        :param expand: True to expand the group, False otherwise.
        :param new_current: A node to focus on after the groups have been expanded/collapsed.
        :returns: True on success, False otherwise.
        """
        return ida_idaapi.pygc_set_groups_visibility(self, groups, expand, new_current)

    def GetWidget(self):
        """
        Return the TWidget underlying this view.

        :returns: The TWidget underlying this view, or None.
        """
        return ida_idaapi.pycim_get_widget(self)

    def GetWidgetAsGraphViewer(self):
        """
        Return the graph_viewer_t underlying this view.

        :returns: The graph_viewer_t underlying this view, or None.
        """
        return ida_idaapi.pycim_get_widget_as_graph_viewer(self)

# ----------------------------------------------------------------------
# bw-compat/deprecated. You shouldn't rely on this in new code
import ida_idaapi
ida_idaapi.CustomIDAMemo = CustomIDAMemo

#</pycode(py_kernwin_viewhooks)>
