import java.util.*;

public class Albero {
  private String info;
  private List figli;

  public Albero(String info) {
    this(info,new LinkedList());
  }

  public Albero(String info, List figli) {
    this.info = info;
    this.figli = figli;
  }

  public String radice() {
    return info;
  }

  public Albero primo() {
    if (figli.isEmpty()) return null;
    else return (Albero)figli.get(0);
  }

  public List resto() {
    if (figli.isEmpty()) 
      throw new RuntimeException("l'albero non ha figli!");
    
    List resto = (List)((LinkedList)figli).clone();
    resto.remove(0);
    return resto;

    //in alternativa si poteva scrivere
    //return figli.sublist(1,figli.size());
    //tuttavia questo modo di scrivere non e' corretto perche' la
    //lista restituita da sublist in generale condivide le stesse
    //strutture dati di figli, e quindi potenzialmente permettiamo al
    //cliente di fare interferenza!!!
  }

  //Ridefiniere equals non era indispensabile. Tuttavia
  //se non ridefinisco equals sto assumendo che 2 alberi che
  //contengono le stesse informazoni nello stesso ordine sono comunque
  //diversi. Anche se quasta assunzione e' possibile, qui ridefiniamo 
  //equals in modo che risultino uguali

  public boolean equals(Object o) {
    if (o!=null && getClass().equals(o.getClass())) {
      Albero a = (Albero)o;
      if (!info.equals(info)) return false;
      else {
        //scandisco contemporaneamente i figli
        // e per ogni figlio verifico se e' uguale al figlio
        // corrispondente nell'altra lista.
        Iterator it1 = figli.iterator();
        Iterator it2 = a.figli.iterator();
        while (it1.hasNext() && it2.hasNext()) {
          Albero f1 = (Albero)it1.next();
          Albero f2 = (Albero)it2.next();
          if (!f1.equals(f2)) return false;
          //nota il nostro equals e' ricorsivo!
        }
        //se una delle due liste di figli ha ancora elementi allora i
        //due alberi non sono uguali
        if (it1.hasNext()||it2.hasNext()) return false;
        else return true;
      }
    }
    else return false;
  }
  
  public int hashCode() {
    int hc = info.hashCode();
    Iterator it = figli.iterator();
    while(it.hasNext()) {
      hc = 31 * hc + it.next().hashCode();
      //Oppure per essere piu' espliciti
      //Albero a = (Albero)it.next; 
      //hc = 31 * hc + a.hashCode();
    }
    return hc;
  }
  //Si noti che uesto implementazione di hashCode() richiede di visitare tutto
  //l'albero!

}
      
