package games.strategy.engine.data;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import games.strategy.util.Match;

// TODO this class doesn't take movementcost into account... typically the shortest route is the fastest route, but not
// always...
class RouteFinder {
  private final GameMap m_map;
  private final Match<Territory> m_condition;
  private final Map<Territory, Territory> m_previous;

  RouteFinder(final GameMap map, final Match<Territory> condition) {
    m_map = map;
    m_condition = condition;
    m_previous = new HashMap<>();
  }

  Route findRoute(final Territory start, final Territory end) {
    final Set<Territory> startSet = m_map.getNeighbors(start, m_condition);
    for (final Territory t : startSet) {
      m_previous.put(t, start);
    }
    if (calculate(startSet, end)) {
      return getRoute(start, end);
    }
    return null;
  }

  private boolean calculate(final Set<Territory> startSet, final Territory end) {
    final Set<Territory> nextSet = new HashSet<>();
    for (final Territory t : startSet) {
      final Set<Territory> neighbors = m_map.getNeighbors(t, m_condition);
      for (final Territory neighbor : neighbors) {
        if (!m_previous.containsKey(neighbor)) {
          m_previous.put(neighbor, t);
          if (neighbor.equals(end)) {
            return true;
          }
          nextSet.add(neighbor);
        }
      }
    }
    if (nextSet.isEmpty()) {
      return false;
    }
    return calculate(nextSet, end);
  }

  private Route getRoute(final Territory start, final Territory destination) {
    final List<Territory> route = new ArrayList<>();
    Territory current = destination;
    while (current != start) {
      if (current == null) {
        return null;
      }
      route.add(current);
      current = m_previous.get(current);
    }
    route.add(start);
    Collections.reverse(route);
    return new Route(route);
  }
}
