import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;

/**
 * ein Objekt, das Hauptstaedte repraesentiert und das man z. B. nach
 * der Nummer oder dem Namen einer dieser Staedte oder dem Abstand
 * zweier solcher Staedte befragen kann.
 * Erzeugt wird ein solches Objekt aus einer Datei mit einer
 * Adjazenzmatrix zu allen Hauptstaedten.
 */
public class Hauptstaedte {

  /** Zuordnung Stadtname -> ID */
  private HashMap<String, Integer> names = new HashMap<>();

  /** Zuordnung ID -> Stadtname */
  private String[] indexToName;

  /** Adjazenzmatrix mit den Distanzen zwischen zwei Staedten */
  private int[][] distance;

  /**
   * erzeugt dieses Objekt aus dem Inhalt einer Datei
   *
   * @param  filename  Name der Datei mit den Staedtenamen und der
   *                   Adjazenzmatrix, die die Abstaende aller Staedte
   *                   enthaelt
   */
  public Hauptstaedte(String filename) {
    readFile(filename);
  }

  /** Liest die uebergebene Textdatei ein */
  private void readFile(String filename) {
    ArrayList<String> list = new ArrayList<>();
    try (Scanner sc = new Scanner(new File(filename))) {
      while (sc.hasNextLine()) {
        list.add(sc.nextLine());
      }
      int size = list.size();
      this.indexToName = new String[size];
      this.distance = new int[size][size];
      for (int i = 0; i < size; i++) {
        String s = list.get(i).trim();
        String[] field = s.split("\t");
        this.names.put(field[0], i);
        this.indexToName[i] = field[0];
        for (int j = 1; j < field.length; j++) {
          this.distance[i][j - 1] = Integer.parseInt(field[j]);
        }
      }

    } catch (FileNotFoundException e) {
      throw new IllegalArgumentException("Datei `" + filename + "' nicht gefunden!");
    }
  }

  /**
   * Gibt die Distanz zwischen den beiden angegebenen Orten zurueck
   *
   * @param  from  Nummer des Startorts
   * @param  to    Nummer des Zielorts
   * @return       Distanz zwischen den beiden Orten
   */
  public int getDistance(int from, int to) {
    if (from < 0 || to < 0 ||
        from >= this.distance.length || to >= this.distance.length) {
      throw new IllegalArgumentException();
    }
    return this.distance[from][to];
  }

  /**
   * Gibt den zur `id' gehoerenden Stadtnamen zurueck
   *
   * @param  id  Nummer der Stadt
   * @return     Name der Stadt
   */
  public String getName(int id) {
    if (id < 0 || id >= this.distance.length) {
      throw new IllegalArgumentException();
    }
    return this.indexToName[id];
  }

  /**
   * Gibt die ID zum uebergebenen Stadtnamen zurueck
   * 
   * @param  name  Name der Stadt
   * @return       ID der Stadt
   */
  public int getId(String name) {
    if (!this.names.containsKey(name)) {
      throw new IllegalArgumentException();
    }
    return this.names.get(name).intValue();
  }

  /**
   * Prueft, ob der uebergebene Stadtname existiert
   * 
   * @param  name  Name der Stadt
   * @return       `true', falls die Stadt existiert, sonst `false'
   */
  public boolean nameExists(String name) {
    return this.names.containsKey(name);
  }

  /**
   * Gibt die Anzahl der Staedte zurueck
   * 
   * @return  Anzahl der Staedte
   */
  public int getCount() {
    return this.distance.length;
  }
}