/** file: Flux.java - definizione degli oggetti connettibili */

import java.awt.*;

/** ========================
      OGGETTO CONNETTIBILE
    ======================== */
/** Questo "OGGETTO CONNETTIBILE" e' la classe astratta da cui
    derivano le successive classi.
    Ogni sottoclasse sara' un oggetto connettibile specializzato
    (che assolve una propria funzione).
    Grazie al collegamento ritardato (late-binding) un oggetto
    connettibile puo' chiedere dati a un'"oggetto d'input" che
    e' dichiarato come "OggConnet" ma che in realta' (durante 
    l'esecuzione) e' un'istanza di una qualsivoglia sottoclasse
    di "OggConnet". */
abstract class OggConnet {
  /** E' l'"oggetto connettibile" di input a cui questo "oggetto
      connettibile" (in realta' l'istanza di una sua sottoclasse
      specializzata) richiede di volta in volta i dati.
      Questo oggetto e' a sua volta un "oggetto connettibile" */
  protected OggConnet Input;
  /** Area per stampare i messaggi (di evoluzione dello stream) */
  protected TextArea ZonaMsg;

  public OggConnet() {
    this (null, null);
  }
  public OggConnet(OggConnet OggInput) {
    this (OggInput, null);
  }
  /** Costruisce un "oggetto connettibile" collegato a un certo
      oggetto (a cui richiedere l'"input" successivo).
      Sulla TextArea passata si scriveranno i messaggi          */
  public OggConnet(OggConnet OggInput,  TextArea AreaMsg) {
    Input   = OggInput;  // Salva oggetto da cui ricevere dati
    ZonaMsg = AreaMsg;
  }

  /** Rende il dato successivo.
      Viene specializzata nelle sottoclassi */
  public abstract int DammiSucc();
  
  /** Rende l'oggetto a cui questo oggetto connettibile
      chiede i dati d'ingresso */
  public OggConnet RendiOggInput() {
    return Input;
  }
  
  /** Stampa il messaggio nella TextArea definita (se c'e') */
  public void StampaMsg (String Messaggio) {
    if (ZonaMsg != null)
      ZonaMsg.appendText (Messaggio);
  }
  /** Rende la TextArea usata per la stampa dei messaggi */
  public TextArea RendiZonaMsg () {
    return ZonaMsg;
  }
}//OggConnet

/** ==============
      GENERATORE
    ============== */
/** E` il generatore di numeri interi */
class Generatore extends OggConnet {
  int Valore;
  
  public Generatore (int ValIniz) {
    this (ValIniz, null);
  }
  /** Costruisce un generatore di interi che comincia dall'
      intero ValIniz in avanti (stampa sulla TextArea data) */
  public Generatore (int ValIniz, TextArea A) {
    super (null, A);
    Valore = ValIniz;
  }
  
  /** Genera (e rende) il numero intero successivo */
  public int DammiSucc() {
    int Rendo=Valore;
    Valore=Valore+1;
    StampaMsg ("\nGen("+Rendo+")-->");  // Dice che num. genera
    return Rendo;
  }
}//Generatore

/** ==========
      FILTRO
    ========== */
/** Il filtro lascia passare solo una certa "categoria" di
    numeri interi. Viene chiesto all'oggetto d'ingresso di 
    dare un nuovo numero; se questo "soddisfa" il filtro,  
    viene reso; altrimenti si continua a chiedere          
    all'ingresso un nuovo numero.                          */
class Filtro extends OggConnet {
  int Valore;
  
  public Filtro (OggConnet OggInput, int ValIniz) {
    this (OggInput, ValIniz, null);
  }
  /** Costruisce un filtro che chiedera' dati all'oggetto di
      ingresso e fara' "passare" solo i dati che soddiferanno 
      alla "proprieta'" caratteristica del filtro.            
      Per la "proprieta'" il filtro usera' il dato "ValIniz". */
  public Filtro (OggConnet OggInput, int ValIniz, TextArea A) {
    super (OggInput, A);
    Valore = ValIniz;
  }
  
  /** Rende il dato successivo.
      La richiesta viene passata all'oggetto collegato all'   
      input del filtro (un generatore o un filtro).           
      La richiesta arrivera' fino al generatore che rendera'  
      l'intero successivo fino al filtro stesso ma per essere 
      reso da questo il dato deve soddisfare una "proprieta'" 
      (caratteristica del filtro).                            
      In caso negativo, viene automaticamente richiesto un    
      nuovo dato all'oggetto d'input, e cosi' via finche' non 
      si avra' un dato che "soddisfi" il filtro.              */
  public int DammiSucc() {
    int Num = 0;
    boolean Continua=true;
    while (Continua) {
      // Passa la chiamata all'oggetto precedente (filtro/gen.)
      Num=Input.DammiSucc();
      StampaMsg ("Filtro("+Valore+")");  //Dice cosa blocca
      // Controllo se filtrare o meno il numero reso
      if ((Num % Valore)!=0) {
        Continua=false;
        StampaMsg ("-->");
      }
      else
        StampaMsg (":BLOCCATO");
    }
    // Rende il numero (non e' stato fermato dal filtro)
    return Num;
  }
}//Filtro

/** ================
      ACCUMULATORE
    ================ */
/** L'accumulatore deve essere inizialmente collegato a un
    generatore (cioe' deve chiedere i dati al generatore).    
    Ogni volta che un dato reso dall'oggetto di ingresso      
    arriva all'accumulatore, viene creato un oggetto "filtro" 
    tra l'accumulatore e il suo oggetto d'input.              */
class Accumulatore extends OggConnet {
  
  public Accumulatore (OggConnet OggInput) {
    this (OggInput, null);
  }
  /** Crea un accumulatore connesso (inizialmente) al
      generatore passato (scrivera' sulla TextArea data) */
  public Accumulatore (OggConnet OggInput, TextArea A) {
    super (OggInput, A);
  }
  
  /** Rende il dato successivo.
      La richiesta viene passata all'oggetto collegato all' 
      input dell'accumulatore (inizialmente un generatore,  
      poi un filtro).   La richiesta arrivera' fino al      
      generatore ma per tornare fino all'accumulatore       
      dovra' passare (e quindi "andare bene") attraverso    
      tutti i filtri posti nel "flusso".                    */
  public int DammiSucc() {
    int Num=Input.DammiSucc();
    // Al ritorno un numero sara' arrivato all'Accumulatore:
    // creero' un nuovo filtro (basato su quel numero) tra
    // l'accumulatore e il filtro/generatore.
    Input=new Filtro (Input, Num, RendiZonaMsg());
    StampaMsg ("Accum("+Num+"). <CREO Filtro("+Num+")>");
    return Num;  // e rendo il numero trovato
  }
}//Accumulatore

//FINE FILE