public class SequenzaBinaria {

  // rappresentazione degli oggetti SequenzaBinaria
  private String seq;
  

  
  // costruisce l'oggetto SequenzaBinaria da una stringa
  public SequenzaBinaria(String x) { 
    seq = x;
  }
  

  // restituisce il primo carattere della sequenza
  public char primo() { 
    return seq.charAt(0);
  }

  // restituisce una nuova sequenza ottenuta dall'oggetto di
  // invocazione eliminando il primo carattere
  public SequenzaBinaria resto() { 
    return new SequenzaBinaria(seq.substring(1));
  }

  public SequenzaBinaria aggiungi(char c) {
    return new SequenzaBinaria(c + seq);
  }

  public boolean estVuota() {
    return seq.equals("");
  }
  
  // calcola la lunghezza della sequenza
  public int lunghezza() {
    if (estVuota()) return 0;
    else return 1 + resto().lunghezza();
  }

  // concatena la sequenza binaria t
  public SequenzaBinaria concatena (SequenzaBinaria t) { 
    if (estVuota()) return t;  // nota lo possiamo fare perche' non ci
                               // sono metodi che fanno side effect in
                               // SequenzaBinaria
    else return resto().concatena(t).aggiungi(primo());
  }

    

  // restituisce la posizione del primo carattere c nella sequenza
  // oppure -1 se esso non e' presente
  public int indiceDi (char c) { 
    return indiceDi(c,0);
  }

  private int indiceDi(char c, int i) {
    if (estVuota()) return -1;
    else {
      if (primo()== c) return i;
      else return resto().indiceDi(c,i+1);
    }
  }

  // verifica se la sequenza e' uguale a t
  public boolean uguale (SequenzaBinaria t) { 
    if (estVuota()) 
      return t.estVuota();
    else 
      return primo() == t.primo() && resto().uguale(t.resto());
  }
  
  // verifica se la sequenza binaria oggetto di invocazione e' un
  // prefisso di p
  public boolean prefisso (SequenzaBinaria p) { 
    if (estVuota()) return true;
    else if (p.estVuota()) return false;
    else return primo() == p.primo() && resto().prefisso(p.resto());
  }

  /*
  // restituisce la lunghezza della sequenza piu' lunga di 
  // caratteri c consecutivi
  public int lungSequenzaMassima (char c) {
    return lsm(c,0,0);
  }
  
  private int lsm(char c, int corr, int max) {
    if (estVuota()) {
      if (corr > max) max = corr;
      return max;
    }
    else 
      if (primo()==c) 
        return resto().lsm(c,corr+1,max);
    else {
      if (corr > max) max = corr;
      return resto().lsm(c,0,max);
    }
  }
  */

  public String toString() {
    return seq;
  }


  //Versione alternativa che fa uso di un oggetto Env per mantenere i valori
  //calcolati 
  
  public int lungSequenzaMassima (char c) { 
    Env e = new Env();
    lsm(c,e);
    return e.max;
  }

  private void lsm(char c, Env e) {
    if (estVuota()) {
      e.corr = 0;
      e.max = 0;
    } 
    else {
      resto().lsm(c,e);
      if (primo()==c) {
        e.corr++;
        if (e.corr > e.max) e.max = e.corr;
      }
      else 
        e.corr = 0;
    }
  }
}


class Env {
  public int corr;
  public int max;
}

