package esprreali;

// dato che usiamo le liste...
import java.util.*;

public class Prodotto extends EsprReale {

	// questa e' la lista; la dichiariamo protected
	// perche' ci serve all'interno della classe
	// iteratore
  protected List<EsprReale> m;

	// il testo non specifica come va creato un prodotto;
	// si capisce, d'altra parte, che deve essere in qualche
	// modo possibile creare un prodotto fatto di una sequenza
	// qualsiasi di espressioni
  public Prodotto() {
    m=new LinkedList<EsprReale>();
  }
	// dal momento che il parametro e' EsprReale, siamo
	// sicuri che il tipo degli oggetti della lista saranno
	// tutti di tipo EsprReale; d'altra parte, va controllato
	// che non vengano inseriti valori null; la presenza di
	// null in una lista non e' un errore a priori; lo e'
	// perche' il testo esclude (anche se non esplicitamente)
	// che una espressione possa valere null
  public void addEspressione(EsprReale e) {
    if(e==null)
      throw new RuntimeException("Le espressioni non possono valere null");
    m.add(e);
  }

	// deve esistere un modo per determinare gli elementi che
	// fanno parte di un prodotto; rendere public la lista m
	// e' una soluzione non ideale; meglio definire un metodo
	// che trova il singolo elemento della lista; ma la
	// soluzione migliore di tutte e' definire un
	// iteratore, che e' il modo piu' efficiente per
	// scandire una lista
  public IteratorProdotto iterator() {
    return new IteratorProdotto(this);
  }

	// serve anche un metodo per determinare la lunghezza
	// della lista; una alternativa migliore a questo metodo e
	// al precedente e' la definizione di un iteratore per il
	// prodotto
  public int size() {
    return m.size();
  }

	// il metodo toString deve restituire la concatenazione
	// delle espressioni, con * in mezzo; c'e' una piccola
	// complicazione: il fatto che + non va messo dopo
	// l'ultima espressione; usare un ciclo for con
	// m.get() andava bene, ma era meno efficiente
  public String toString() {
    String r="";
    Iterator i;

    i=m.iterator();

    while(i.hasNext()) {
      r=r+i.next().toString();
      if(i.hasNext())
        r=r+"*";
    }

    return r;
  }

	// il metodo equals di LinkedList fa il confronto degli
	// oggetti delle due liste, usando equals per fare questo
	// confronto; si puo' quindi definire equals di Prodotto
	// semplicemente invocando equals delle LinkedList; non e'
	// sbagliato fare un ciclo e confrontare gli elementi
  public boolean equals(Object o) {
    if(!this.stessaClasse(o))
      return false;

    Prodotto p=(Prodotto) o;

    return this.m.equals(p.m);
  }

	// il metodo hashCode si ottiene come somma pesata; vedere
	// anche il commento nella classe Somma; non serve
	// fare il cast di i.next(), dato che hashCode e'
	// definito pubblico in Object
  public int hashCode() {
    int ris=5;

    Iterator i=m.iterator();

    while(i.hasNext())
      ris=ris*7+i.next().hashCode();

    return ris;
  }

	// la clonazione profonda di una lista prevede la
	// creazione di una nuova lista in cui vanno messe
	// le copie di tutti gli oggetti della lista di
	// partenza; usiamo comunque super.clone() per i
	// motivi spiegati nella classe Somma; notare che il
	// cast di i.next() e' necessario, dato che clone e'
	// protetto in Object
  public Object clone() {
    Prodotto p=(Prodotto) super.clone();
    p.m=new LinkedList<EsprReale>();

    Iterator i=m.iterator();
    while(i.hasNext()) {
      EsprReale e=(EsprReale) i.next();
      p.m.add((EsprReale) e.clone());
    }

    return p;
  }
}


