package javakurs.musterloesung.uebung08;

import java.util.ArrayList;
import java.util.List;

/**
 * {@link VertexPropertyMap} maps vertices to values.
 *
 * @param <ValueType>
 *          the kind of values that this map holds
 *
 * @author Bernd Kiefer, DFKI
 * @author Joerg Steffen, DFKI
 * @version $Id: VertexPropertyMap.java,v 1.1 2011/01/04 17:52:55 steffen Exp $
 */
public class VertexPropertyMap<ValueType> {

  /**
   * The graph to which the vertices belong.
   */
  private DirectedGraphBase<?> _graph;

  /**
   * The mapping of vertices, represented as ints, to their values
   */
  private ArrayList<ValueType> _map;


  /**
   * This creates a new instance of {@link VertexPropertyMap}.
   *
   * @param graph
   *          the graph to which the mapped vertices belong
   */
  public VertexPropertyMap(DirectedGraphBase<?> graph) {

    _map = new ArrayList<ValueType>();
    _graph = graph;
  }


  /**
   * Removes all current mappings.
   */
  public void clear() {

    _map.clear();
  }


  /**
   * Add a mapping of the given vertex to the given value.
   *
   * @param vertex
   *          the vertex
   * @param value
   *          the mapped value
   */
  public void put(int vertex, ValueType value) {

    // make sure the vertex belong to the graph of this map
    assert (_graph.isVertex(vertex));
    // fill map with nulls until the vertex index positions is reached
    while (_map.size() <= vertex) {
      _map.add(null);
    }
    _map.set(vertex, value);
  }


  /**
   * Returns the value mapped to the given vertex.
   *
   * @param vertex
   *          the vertex
   * @return the mapped value
   */
  public ValueType get(int vertex) {

    assert (_graph.isVertex(vertex));
    // if vertex is outside of the mapping range, there was no value assigned
    // yet
    if (_map.size() <= vertex) {
      return null;
    }
    return _map.get(vertex);
  }


  /**
   * Removes the mapping for the given vertex.
   *
   * @param vertex
   *          the vertex
   */
  public void remove(int vertex) {

    if (_map.size() > vertex) {
      _map.set(vertex, null);
    }
  }


  /**
   * Removes the mapping for all vertices in the given vertex range.
   *
   * @param from
   *          the start vertex
   * @param to
   *          the end vertex
   */
  public void removeRange(int from, int to) {

    if (_map.size() > from) {
      assert (_map.size() <= to);
      for (int i = Math.min(to, _map.size()) - 1; i >= from; --i) {
        _map.remove(i);
      }
    }
  }


  /**
   * Returns all vertices whose assigned value matches the given value using the
   * given predicate.
   *
   * @param val
   *          the value to compare against
   * @param pred
   *          the predicate used to compare
   * @return a list of matching vertices
   */
  public List<Integer>
      findVertices(ValueType val, BinaryPredicate<ValueType> pred) {

    List<Integer> result = new ArrayList<Integer>(_map.size());
    for (int i = 0; i < _map.size(); ++i) {
      if (_graph.isVertex(i) && pred.compare(_map.get(i), val)) {
        result.add(i);
      }
    }
    return result;
  }
}
