import java.util.*;

/** Object that can be notified when a StyledWord word changes. */
interface WordChangeListener {
  public void onWordChange(WordChangeEvent evt);
}

/** Describes a change to a styled word. */
class WordChangeEvent {
  public final StyledWord target;   // word object that was changed
  public final int position;        // location where text was changed
  public final String textAdded;    // text inserted here
  public final String textRemoved;  // text removed from (after) here

  public WordChangeEvent(
      StyledWord target, int position, String textAdded, String textRemoved) {
    this.target = target;
    this.position = position;
    this.textAdded = textAdded;
    this.textRemoved = textRemoved;
  }
}

/**
 * Class that stores text along with a color in which to display it. Notifies a
 * list of listeners after any update.
 */
class StyledWord {
  private StringBuffer text  = new StringBuffer();
  private Color color = new Color("black");
  private List<WordChangeListener> listeners;
 
  public StyledWord() {
    listeners = new ArrayList<>();
  }

  public StyledWord(Collection<WordChangeListener> ls) {
    listeners = new ArrayList<>(ls);
  }

  public void addListener(WordChangeListener l) {
    listeners.add(l);
  }

  public void removeListener(WordChangeListener l) {
    listeners.remove(l);
  }

  public Color getColor() {
    return color;
  }

  public void setColor(Color c) {
    color = c;
  }

  public String getText() {
    return new String(text);
  }

  public void addLetter(char c, int position) { 
    assert 0 <= position && position <= text.length();
    text.insert(position, c); 
    notifyWordChange(new WordChangeEvent(this, position, "" + c, ""));
  }

  public void deleteLetter(int position) { 
    assert 0 <= position && position < text.length();
    String textRemoved = text.substring(position, position + 1);
    text.delete(position, position + 1); 
    notifyWordChange(new WordChangeEvent(this, position, "", textRemoved));
  }

  private void notifyWordChange(WordChangeEvent evt) {
    for (WordChangeListener listener : listeners) {
      listener.onWordChange(evt);
    }
  }
}


/** Removes any Qs that were added. */
class QRemover implements WordChangeListener {
  @Override
  public void onWordChange(WordChangeEvent evt) {
    if (evt.textAdded.length() > 0) {
      for (int i = evt.textAdded.length() - 1; i >= 0; i--) {
        if (evt.textAdded.charAt(i) == 'Q')
          evt.target.deleteLetter(evt.position + i);  // callback does nothing
      }
    }
  }
}

/** Changes the color of a word to red if it isn't found in the dictionary. */
class Spellchecker implements WordChangeListener {
  private Dictionary dictionary;

  public Spellchecker(String language) {
    dictionary = Dictionary.findDictionary(language);
  }

  @Override
  public void onWordChange(WordChangeEvent evt) {
    performSpellcheck(evt.target);
  }

  public void performSpellcheck(StyledWord word) {
    if (dictionary.contains(word.getText())) {
      word.setColor(new Color("black"));
    } else {
      word.setColor(new Color("red"));
    }
  }
}

/** Maintains a count of how many times the word has been changed. */
class ChangeCounter implements WordChangeListener { 
  private int count = 0;

  @Override
  public void onWordChange(WordChangeEvent evt) {
    count++;
  }

  public int getCount() {
    return count;
  }
}

class Main {
  public static void main(String[] args) {
    StyledWord w = new StyledWord();
    w.addListener(new Spellchecker("English"));
    w.addListener(new QRemover());
    w.addListener(new ChangeCounter());
    // ... edit the word ...
  }
}