////////////////// class Graf //////////////////////////////

package hjelpeklasser;

import java.util.*;                           // Map og List
import java.io.*;                             // graf fra fil
import java.net.URL;                          // graf fra internett

public final class Graf implements Iterable<String>  // final: skal ikke arves
{
  private static final class Node             // en indre nodeklasse
  {
    private final String navn;                // navn/identifikator
    private final List<Node> kanter;          // nodens kanter
    private byte innkanter = 0;               // antall innkanter
    private boolean besøkt = false;           // hjelpevariabel til senere bruk
    private Node forrige = null;              // hjelpevariabel til senere bruk

    private Node(String navn)                 // nodekonstruktør
    {
      this.navn = navn;                       // nodens navn
      kanter = new LinkedList<>();            // oppretter kantlisten
    }

    @Override
    public String toString()                  // navnet
    {
      return navn;
    }

  } // Node

  private final Map<String, Node> noder;      // en map til å lagre nodene

  public Graf()                               // standardkonstruktør
  {
    noder = new HashMap<>();                  // oppretter en HashMap
  }

  public boolean leggInnNode(String navn)     // ny node
  {
    if (navn == null || navn.length() == 0)
      throw new IllegalArgumentException("Noden må ha et navn!");

    if (noder.get(navn) != null) return false;
    return noder.put(navn, new Node(navn)) == null;
  }

  public boolean nodeFinnes(String navn)      // finnes denne noden?
  {
    return noder.get(navn) != null;
  }

  @Override
  public Iterator<String> iterator()          // klassen er iterable
  {
    return noder.keySet().iterator();
  }

  public String[] nodenavn()                  // navnene som en tabell
  {
    return noder.keySet().toArray(new String[0]);
  }

  public void leggInnKant(String franode, String tilnode)
  {
    if (franode.equals(tilnode)) throw    // sjekker om de er like
      new IllegalArgumentException(franode + " er lik " + tilnode + "!");

    Node fra = noder.get(franode);  // henter franode
    if (fra == null) throw new NoSuchElementException(franode + " er ukjent!");

    Node til = noder.get(tilnode);  // henter tilnode
    if (til == null) throw new NoSuchElementException(tilnode + " er ukjent!");

    if(fra.kanter.contains(til)) throw
      new IllegalArgumentException("Kanten finnes fra før!");

    til.innkanter++;      // en ny innkant
    fra.kanter.add(til);  // legger til i kantlisten
  }

  public void leggInnKanter(String franode, String... tilnoder)
  {
    for (String tilnode : tilnoder) leggInnKant(franode, tilnode);
  }

  public String kanterFra(String node)
  {
    Node fra = noder.get(node);
    if (fra == null) return null;
    return fra.kanter.toString();
  }

  public Graf(String url) throws IOException  // konstruktør - henter fra fil
  {
    this();   // standardkonstruktør

    try (BufferedReader inn = new BufferedReader  // leser fra fil
        (new InputStreamReader((new URL(url)).openStream())))
    {
      String linje;
      while ((linje = inn.readLine()) != null)
      {
        String[] navn = linje.split(" ");      // deler opp linjen

        leggInnNode(navn[0]);                  // noden kommer først

        for (int i = 1; i < navn.length; i++)  // så nodene det går kant til
        {
          leggInnNode(navn[i]);                // navnet på naboen
          leggInnKant(navn[0], navn[i]);       // legges inn som nabo
        }
      }
    }
  }

} // Graf