content: /*
   * Copyright (C) 2015-2023 Emanuel Moecklin
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.onegravity.rteditor.effects;
  
  import android.text.Spannable;
  import android.text.Spanned;
  
  import com.onegravity.rteditor.spans.RTSpan;
  import com.onegravity.rteditor.utils.Selection;
  
  import java.util.ArrayList;
  import java.util.List;
  
  class ParagraphSpanCollector<V> extends SpanCollector<V> {
  
      ParagraphSpanCollector(Class<? extends RTSpan<V>> spanClazz) {
          super(spanClazz);
      }
  
      @Override
      final protected List<RTSpan<V>> getSpans(Spannable str, Selection selection, SpanCollectMode mode) {
          List<RTSpan<V>> result = new ArrayList<RTSpan<V>>();
  
          RTSpan<V>[] spans = getSpansAndroid(str, selection.start(), selection.end());
          for (RTSpan<V> span : spans) {
              if (isAttached(str, selection, span, mode)) {
                  result.add(span);
              }
          }
  
          return result;
      }
  
      /**
       * Note: a ParagraphSpan is always applied to a paragraph (including the crlf)
       * --> it will never be a point unless the cursor is in the last empty line!
       */
      private boolean isAttached(Spannable str, Selection selection, Object span, SpanCollectMode mode) {
          int spanStart = str.getSpanStart(span);
          int spanEnd = str.getSpanEnd(span);
          int selStart = selection.start();
          int selEnd = selection.end();
  
          // [start, end] define the intersection of span and selection
          int start = Math.max(spanStart, selStart);
          int end = Math.min(spanEnd, selEnd);
  
          if (start > end) {
              // 1) no character in common and not adjacent
              // [span]...|selection| or |selection|...[span]
              return false;
          }
          else if (start < end) {
              // 2) at least one character in common:
              // [span]
              //  [     span    ]
              //    |selection|
              //      [span]
              //            [span]
              return true;
          }
          else if ((spanStart > selStart && spanEnd < selEnd) ||   // point span within selection
                  (selStart > spanStart && selEnd < spanEnd)) {    // point selection within span
              // 3) point span within selection or point selection within span (within, not adjacent)
              //    |selection|
              //        []
              //    [span     ]
              //        ||
              return true;
          }
          else if (mode == SpanCollectMode.EXACT) {
              // 4) adjacent SpanCollectMode.EXACT
              // 4.1) point span + point selection --> match
              // 4.2) else --> no match
              return spanStart == selStart && spanEnd == selEnd && selStart == selEnd;
          }
          else {
              // 5) adjacent SpanCollectMode.SPAN_FLAGS
              int flags = str.getSpanFlags(span) & Spanned.SPAN_POINT_MARK_MASK;
              if (spanEnd == selStart) {
                  // 5.1) [span][selection] -> span must include at the end
                  return isOneFlagSet(flags, Spanned.SPAN_EXCLUSIVE_INCLUSIVE, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
              }
              else {
                  // 5.2) [selection][span] -> span must include at the start
                  return isOneFlagSet(flags, Spanned.SPAN_INCLUSIVE_EXCLUSIVE, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
              }
          }
      }
  
  }
  