@Override
  public void afterTextChanged(Editable s) {
    int position = Selection.getSelectionStart(mContentEditText.getText());
    if ((mIsBackspace && position != 1) || mLastPosition == position || !mIsLocalDraft) return;

    if (position < 0) {
      position = 0;
    }
    mLastPosition = position;
    if (position > 0) {
      if (mStyleStart > position) {
        mStyleStart = position - 1;
      }

      boolean shouldBold = mBoldToggleButton.isChecked();
      boolean shouldEm = mEmToggleButton.isChecked();
      boolean shouldUnderline = mUnderlineToggleButton.isChecked();
      boolean shouldStrike = mStrikeToggleButton.isChecked();
      boolean shouldQuote = mBquoteToggleButton.isChecked();

      Object[] allSpans = s.getSpans(mStyleStart, position, Object.class);
      for (Object span : allSpans) {
        if (span instanceof StyleSpan) {
          StyleSpan styleSpan = (StyleSpan) span;
          if (styleSpan.getStyle() == Typeface.BOLD) shouldBold = false;
          else if (styleSpan.getStyle() == Typeface.ITALIC) shouldEm = false;
        } else if (span instanceof WPUnderlineSpan) {
          shouldUnderline = false;
        } else if (span instanceof StrikethroughSpan) {
          shouldStrike = false;
        } else if (span instanceof QuoteSpan) {
          shouldQuote = false;
        }
      }

      if (shouldBold)
        s.setSpan(
            new StyleSpan(android.graphics.Typeface.BOLD),
            mStyleStart,
            position,
            Spannable.SPAN_INCLUSIVE_INCLUSIVE);
      if (shouldEm)
        s.setSpan(
            new StyleSpan(android.graphics.Typeface.ITALIC),
            mStyleStart,
            position,
            Spannable.SPAN_INCLUSIVE_INCLUSIVE);
      if (shouldUnderline)
        s.setSpan(new WPUnderlineSpan(), mStyleStart, position, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
      if (shouldStrike)
        s.setSpan(
            new StrikethroughSpan(), mStyleStart, position, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
      if (shouldQuote)
        s.setSpan(new QuoteSpan(), mStyleStart, position, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
    }
  }
  @Override
  public void onSelectionChanged() {
    if (!mIsLocalDraft) {
      return;
    }

    final Spannable s = mContentEditText.getText();
    if (s == null) return;
    // set toggle buttons if cursor is inside of a matching span
    mStyleStart = mContentEditText.getSelectionStart();
    Object[] spans =
        s.getSpans(
            mContentEditText.getSelectionStart(),
            mContentEditText.getSelectionStart(),
            Object.class);

    mBoldToggleButton.setChecked(false);
    mEmToggleButton.setChecked(false);
    mBquoteToggleButton.setChecked(false);
    mUnderlineToggleButton.setChecked(false);
    mStrikeToggleButton.setChecked(false);
    for (Object span : spans) {
      if (span instanceof StyleSpan) {
        StyleSpan ss = (StyleSpan) span;
        if (ss.getStyle() == android.graphics.Typeface.BOLD) {
          mBoldToggleButton.setChecked(true);
        }
        if (ss.getStyle() == android.graphics.Typeface.ITALIC) {
          mEmToggleButton.setChecked(true);
        }
      }
      if (span instanceof QuoteSpan) {
        mBquoteToggleButton.setChecked(true);
      }
      if (span instanceof WPUnderlineSpan) {
        mUnderlineToggleButton.setChecked(true);
      }
      if (span instanceof StrikethroughSpan) {
        mStrikeToggleButton.setChecked(true);
      }
    }
  }
  /**
   * Applies formatting to selected text, or marks the entry for a new text style at the current
   * cursor position
   *
   * @param toggleButton button from formatting bar
   * @param tag HTML tag name for text style
   */
  private void onFormatButtonClick(ToggleButton toggleButton, String tag) {
    Spannable s = mContentEditText.getText();
    if (s == null) return;
    int selectionStart = mContentEditText.getSelectionStart();
    mStyleStart = selectionStart;
    int selectionEnd = mContentEditText.getSelectionEnd();

    if (selectionStart > selectionEnd) {
      int temp = selectionEnd;
      selectionEnd = selectionStart;
      selectionStart = temp;
    }

    Class styleClass = null;
    if (tag.equals(TAG_FORMAT_BAR_BUTTON_STRONG) || tag.equals(TAG_FORMAT_BAR_BUTTON_EM))
      styleClass = StyleSpan.class;
    else if (tag.equals(TAG_FORMAT_BAR_BUTTON_UNDERLINE)) styleClass = WPUnderlineSpan.class;
    else if (tag.equals(TAG_FORMAT_BAR_BUTTON_STRIKE)) styleClass = StrikethroughSpan.class;
    else if (tag.equals(TAG_FORMAT_BAR_BUTTON_QUOTE)) styleClass = QuoteSpan.class;

    if (styleClass == null) return;

    Object[] allSpans = s.getSpans(selectionStart, selectionEnd, styleClass);
    boolean textIsSelected = selectionEnd > selectionStart;
    if (mIsLocalDraft) {
      // Local drafts can use the rich text editor. Yay!
      boolean shouldAddSpan = true;
      for (Object span : allSpans) {
        if (span instanceof StyleSpan) {
          StyleSpan styleSpan = (StyleSpan) span;
          if ((styleSpan.getStyle() == Typeface.BOLD && !tag.equals(TAG_FORMAT_BAR_BUTTON_STRONG))
              || (styleSpan.getStyle() == Typeface.ITALIC
                  && !tag.equals(TAG_FORMAT_BAR_BUTTON_EM))) {
            continue;
          }
        }
        if (!toggleButton.isChecked() && textIsSelected) {
          // If span exists and text is selected, remove the span
          s.removeSpan(span);
          shouldAddSpan = false;
          break;
        } else if (!toggleButton.isChecked()) {
          // Remove span at cursor point if button isn't checked
          Object[] spans = s.getSpans(mStyleStart - 1, mStyleStart, styleClass);
          for (Object removeSpan : spans) {
            selectionStart = s.getSpanStart(removeSpan);
            selectionEnd = s.getSpanEnd(removeSpan);
            s.removeSpan(removeSpan);
          }
        }
      }

      if (shouldAddSpan) {
        if (tag.equals(TAG_FORMAT_BAR_BUTTON_STRONG)) {
          s.setSpan(
              new StyleSpan(android.graphics.Typeface.BOLD),
              selectionStart,
              selectionEnd,
              Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        } else if (tag.equals(TAG_FORMAT_BAR_BUTTON_EM)) {
          s.setSpan(
              new StyleSpan(android.graphics.Typeface.ITALIC),
              selectionStart,
              selectionEnd,
              Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        } else {
          try {
            s.setSpan(
                styleClass.newInstance(),
                selectionStart,
                selectionEnd,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
          } catch (java.lang.InstantiationException e) {
            AppLog.e(T.POSTS, e);
          } catch (IllegalAccessException e) {
            AppLog.e(T.POSTS, e);
          }
        }
      }
    } else {
      // Add HTML tags when editing an existing post
      String startTag = "<" + tag + ">";
      String endTag = "</" + tag + ">";
      Editable content = mContentEditText.getText();
      if (textIsSelected) {
        content.insert(selectionStart, startTag);
        content.insert(selectionEnd + startTag.length(), endTag);
        toggleButton.setChecked(false);
        mContentEditText.setSelection(selectionEnd + startTag.length() + endTag.length());
      } else if (toggleButton.isChecked()) {
        content.insert(selectionStart, startTag);
        mContentEditText.setSelection(selectionEnd + startTag.length());
      } else if (!toggleButton.isChecked()) {
        content.insert(selectionEnd, endTag);
        mContentEditText.setSelection(selectionEnd + endTag.length());
      }
    }
  }