/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * 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.intellij.codeInsight.editorActions;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;

/**
 * @author yole
 */
public abstract class ExtendWordSelectionHandlerBase implements ExtendWordSelectionHandler {
  private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.editorActions.ExtendWordSelectionHandlerBase");
  @Override
  public abstract boolean canSelect(PsiElement e);

  @Override
  public List<TextRange> select(PsiElement e, CharSequence editorText, int cursorOffset, Editor editor) {

    final TextRange originalRange = e.getTextRange();
    LOG.assertTrue(originalRange.getEndOffset() <= editorText.length(), getClass() + "; " + e);

    List<TextRange> ranges = expandToWholeLine(editorText, originalRange, true);

    if (ranges.size() == 1 && ranges.contains(originalRange)) {
      return expandToWholeLine(editorText, originalRange, false);
    }

    return ranges;
  }

  public static List<TextRange> expandToWholeLine(CharSequence text, @Nullable TextRange range, boolean isSymmetric) {
    int textLength = text.length();
    List<TextRange> result = new ArrayList<TextRange>();

    if (range == null) {
      return result;
    }

    LOG.assertTrue(range.getEndOffset() <= text.length());
    if (!StringUtil.contains(text, range.getStartOffset(), range.getEndOffset(), '\n')) {
      result.add(range);
    }


    int startOffset = range.getStartOffset();
    int endOffset = range.getEndOffset();
    int index1 = CharArrayUtil.shiftBackward(text, startOffset - 1, " \t");
    if (endOffset > startOffset && text.charAt(endOffset - 1) == '\n') {
      endOffset--;
    }
    int index2 = Math.min(textLength, CharArrayUtil.shiftForward(text, endOffset, " \t"));

    if (index1 < 0 || text.charAt(index1) == '\n' || index2 == textLength || text.charAt(index2) == '\n') {
      if (!isSymmetric) {
        if (index1 < 0 || text.charAt(index1) == '\n') {
          startOffset = index1 + 1;
        }

        if (index2 == textLength || text.charAt(index2) == '\n') {
          endOffset = index2;
          if (endOffset < textLength) {
            endOffset++;
          }
        }

        result.add(new TextRange(startOffset, endOffset));
      }
      else {
        if ((index1 < 0 || text.charAt(index1) == '\n') &&
            (index2 == textLength || text.charAt(index2) == '\n')) {
          startOffset = index1 + 1;
          endOffset = index2;
          if (endOffset < textLength) {
            endOffset++;
          }
          result.add(new TextRange(startOffset, endOffset));
        }
        else {
          result.add(range);
        }
      }
    }
    else {
      result.add(range);
    }

    return result;
  }

  public static List<TextRange> expandToWholeLine(CharSequence text, TextRange range) {
    return expandToWholeLine(text, range, true);
  }
}
@@ -1434,17 +1434,16 @@
 itor) %7B%0A
-%0A
     fina
@@ -1951,44 +1951,8 @@
 ) %7B%0A
-    int textLength = text.length();%0A
     
@@ -2239,16 +2239,323 @@
 %0A    %7D%0A%0A
+    TextRange expanded = getExpandedRange(text, range, isSymmetric);%0A    if (expanded != null) %7B%0A      result.add(expanded);%0A    %7D else %7B%0A      result.add(range);%0A    %7D%0A    return result;%0A  %7D%0A%0A  @Nullable%0A  private static TextRange getExpandedRange(CharSequence text, TextRange range, boolean isSymmetric) %7B
 %0A    int
@@ -2805,24 +2805,60 @@
 et--;%0A    %7D%0A
+    int textLength = text.length();%0A
     int inde
@@ -3366,33 +3366,29 @@
 %0A%0A        re
-sult.add(
+turn 
 new TextRang
@@ -3404,33 +3404,32 @@
 fset, endOffset)
-)
 ;%0A      %7D%0A      
@@ -3422,31 +3422,17 @@
       %7D%0A
-      else %7B%0A  
+%0A
       if
@@ -3490,18 +3490,16 @@
         
-  
 (index2 
@@ -3547,34 +3547,32 @@
 %5Cn')) %7B%0A        
-  
 startOffset = in
@@ -3581,34 +3581,32 @@
 x1 + 1;%0A        
-  
 endOffset = inde
@@ -3601,34 +3601,32 @@
 ffset = index2;%0A
-  
         if (endO
@@ -3639,34 +3639,32 @@
 %3C textLength) %7B%0A
-  
           endOff
@@ -3674,30 +3674,26 @@
 ++;%0A        
-  %7D%0A  
+%7D%0A
         resu
@@ -3690,25 +3690,21 @@
       re
-sult.add(
+turn 
 new Text
@@ -3732,21 +3732,18 @@
 dOffset)
-)
 ;%0A
-  
       %7D%0A
@@ -3750,132 +3750,26 @@
     
-    else %7B%0A          result.add(range);%0A        %7D%0A      %7D%0A    %7D%0A    else %7B%0A      result.add(range);%0A    %7D%0A%0A    return result
+%7D%0A%0A    return null
 ;%0A  

extract a method