import abc
import grafon.constants as constants

class ReducerInterface(object):
  """!
  The interface for a reducer class.
  """
  __metaclass__ = abc.ABCMeta
  
  DATA_LABEL = 'label'
  DATA_WEIGHT = 'weight'
  DATA_CLUSTER = 'cluster'

  def __init__(self, options, reducer_name):
    """!
    The class in an abstract class. It isn't possible to create exactly it's 
    instance.

    @param options extra parameters read from the config file. Each reducer
      that is interested in any additional attributes should handle this object
      by itself.
    @type options: dict(str: str)
    @param reducer_name the name of the reducer that is actually created.
    @type reducer_name: str
    """
    self.reducer_name = reducer_name
  
  def __str__(self):
    """!
    String like representation based on the reducer name 
    given by the constructor.
    """
    return self.reducer_name

  @abc.abstractmethod
  def reduce(self, digraph, text_nodes):
    """!
    Return reduced representation of the graph containing all text's nodes.

    @param graph the directed graph to be reduced.
    @type graph: networkx.DiGraph()
    @param text_nodes the list of nodes' identifiers from a text.
    @type text_nodes: list
    """
    pass

  def _get_directed_edges_of_path(self, path, digraph):
    """!
    Return the directional edges that connects nodes of the path.

    The path may be, e.g. the shortest path between a pair of nodes in 
    a undirected graph. However, the edges should be directional. Thus, this 
    method checks the direction of each edge from the path in the original
    directional graph. Moreover, the label of an edge is copied.

    @param path the undirected path, the list of nodes to traverse.
    @type path: numpy.array
    @param digraph the original, directional graph.
    @type digraph: networkx.DiGraph

    @return the list of edges that can be added directly to any networkx graph.
      Each element of the list is a tuple of 3 elements: node_from, node_to and
      data. The data is a dictionary with only one key - the label of the edge.
    @rtype: list of tuple
    """
    edges = []
    for i in range(1, len(path)):
      node_from = path[i - 1]
      node_to = path[i]
      if node_to in digraph.predecessors(node_from):
        # n2 -> n1
        edges.append((
          node_from, 
          node_to, 
          digraph.get_edge_data(node_to, node_from)))
      else:
        # n1 -> n2
        edges.append((
          node_to, 
          node_from, 
          digraph.get_edge_data(node_from, node_to)))
    return edges
