content: /*
   * Copyright (C) 2013 The Android Open Source Project
   *
   * 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.amnesica.kryptey.inputmethod.latin.utils;
  
  import com.amnesica.kryptey.inputmethod.latin.common.StringUtils;
  
  import java.util.Locale;
  
  /**
   * The status of the current recapitalize process.
   */
  public class RecapitalizeStatus {
    public static final int NOT_A_RECAPITALIZE_MODE = -1;
    public static final int CAPS_MODE_ORIGINAL_MIXED_CASE = 0;
    public static final int CAPS_MODE_ALL_LOWER = 1;
    public static final int CAPS_MODE_FIRST_WORD_UPPER = 2;
    public static final int CAPS_MODE_ALL_UPPER = 3;
  
    private static final int[] ROTATION_STYLE = {
        CAPS_MODE_ORIGINAL_MIXED_CASE,
        CAPS_MODE_ALL_LOWER,
        CAPS_MODE_FIRST_WORD_UPPER,
        CAPS_MODE_ALL_UPPER
    };
  
    private static final int getStringMode(final String string) {
      if (StringUtils.isIdenticalAfterUpcase(string)) {
        return CAPS_MODE_ALL_UPPER;
      } else if (StringUtils.isIdenticalAfterDowncase(string)) {
        return CAPS_MODE_ALL_LOWER;
      } else if (StringUtils.isIdenticalAfterCapitalizeEachWord(string)) {
        return CAPS_MODE_FIRST_WORD_UPPER;
      } else {
        return CAPS_MODE_ORIGINAL_MIXED_CASE;
      }
    }
  
    public static String modeToString(final int recapitalizeMode) {
      switch (recapitalizeMode) {
        case NOT_A_RECAPITALIZE_MODE:
          return "undefined";
        case CAPS_MODE_ORIGINAL_MIXED_CASE:
          return "mixedCase";
        case CAPS_MODE_ALL_LOWER:
          return "allLower";
        case CAPS_MODE_FIRST_WORD_UPPER:
          return "firstWordUpper";
        case CAPS_MODE_ALL_UPPER:
          return "allUpper";
        default:
          return "unknown<" + recapitalizeMode + ">";
      }
    }
  
    /**
     * We store the location of the cursor and the string that was there before the recapitalize
     * action was done, and the location of the cursor and the string that was there after.
     */
    private int mCursorStartBefore;
    private String mStringBefore;
    private int mCursorStartAfter;
    private int mCursorEndAfter;
    private int mRotationStyleCurrentIndex;
    private boolean mSkipOriginalMixedCaseMode;
    private Locale mLocale;
    private String mStringAfter;
    private boolean mIsStarted;
    private boolean mIsEnabled = true;
  
    public RecapitalizeStatus() {
      // By default, initialize with dummy values that won't match any real recapitalize.
      start(-1, -1, "", Locale.getDefault());
      stop();
    }
  
    public void start(final int cursorStart, final int cursorEnd, final String string, final Locale locale) {
      if (!mIsEnabled) {
        return;
      }
      mCursorStartBefore = cursorStart;
      mStringBefore = string;
      mCursorStartAfter = cursorStart;
      mCursorEndAfter = cursorEnd;
      mStringAfter = string;
      final int initialMode = getStringMode(mStringBefore);
      mLocale = locale;
      if (CAPS_MODE_ORIGINAL_MIXED_CASE == initialMode) {
        mRotationStyleCurrentIndex = 0;
        mSkipOriginalMixedCaseMode = false;
      } else {
        // Find the current mode in the array.
        int currentMode;
        for (currentMode = ROTATION_STYLE.length - 1; currentMode > 0; --currentMode) {
          if (ROTATION_STYLE[currentMode] == initialMode) {
            break;
          }
        }
        mRotationStyleCurrentIndex = currentMode;
        mSkipOriginalMixedCaseMode = true;
      }
      mIsStarted = true;
    }
  
    public void stop() {
      mIsStarted = false;
    }
  
    public boolean isStarted() {
      return mIsStarted;
    }
  
    public void enable() {
      mIsEnabled = true;
    }
  
    public void disable() {
      mIsEnabled = false;
    }
  
    public boolean mIsEnabled() {
      return mIsEnabled;
    }
  
    public boolean isSetAt(final int cursorStart, final int cursorEnd) {
      return cursorStart == mCursorStartAfter && cursorEnd == mCursorEndAfter;
    }
  
    /**
     * Rotate through the different possible capitalization modes.
     */
    public void rotate() {
      final String oldResult = mStringAfter;
      int count = 0; // Protection against infinite loop.
      do {
        mRotationStyleCurrentIndex = (mRotationStyleCurrentIndex + 1) % ROTATION_STYLE.length;
        if (CAPS_MODE_ORIGINAL_MIXED_CASE == ROTATION_STYLE[mRotationStyleCurrentIndex]
            && mSkipOriginalMixedCaseMode) {
          mRotationStyleCurrentIndex =
              (mRotationStyleCurrentIndex + 1) % ROTATION_STYLE.length;
        }
        ++count;
        switch (ROTATION_STYLE[mRotationStyleCurrentIndex]) {
          case CAPS_MODE_ORIGINAL_MIXED_CASE:
            mStringAfter = mStringBefore;
            break;
          case CAPS_MODE_ALL_LOWER:
            mStringAfter = mStringBefore.toLowerCase(mLocale);
            break;
          case CAPS_MODE_FIRST_WORD_UPPER:
            mStringAfter = StringUtils.capitalizeEachWord(mStringBefore, mLocale);
            break;
          case CAPS_MODE_ALL_UPPER:
            mStringAfter = mStringBefore.toUpperCase(mLocale);
            break;
          default:
            mStringAfter = mStringBefore;
        }
      } while (mStringAfter.equals(oldResult) && count < ROTATION_STYLE.length + 1);
      mCursorEndAfter = mCursorStartAfter + mStringAfter.length();
    }
  
    /**
     * Remove leading/trailing whitespace from the considered string.
     */
    public void trim() {
      final int len = mStringBefore.length();
      int nonWhitespaceStart = 0;
      for (; nonWhitespaceStart < len;
           nonWhitespaceStart = mStringBefore.offsetByCodePoints(nonWhitespaceStart, 1)) {
        final int codePoint = mStringBefore.codePointAt(nonWhitespaceStart);
        if (!Character.isWhitespace(codePoint)) break;
      }
      int nonWhitespaceEnd = len;
      for (; nonWhitespaceEnd > 0;
           nonWhitespaceEnd = mStringBefore.offsetByCodePoints(nonWhitespaceEnd, -1)) {
        final int codePoint = mStringBefore.codePointBefore(nonWhitespaceEnd);
        if (!Character.isWhitespace(codePoint)) break;
      }
      // If nonWhitespaceStart >= nonWhitespaceEnd, that means the selection contained only
      // whitespace, so we leave it as is.
      if ((0 != nonWhitespaceStart || len != nonWhitespaceEnd)
          && nonWhitespaceStart < nonWhitespaceEnd) {
        mCursorEndAfter = mCursorStartBefore + nonWhitespaceEnd;
        mCursorStartBefore = mCursorStartAfter = mCursorStartBefore + nonWhitespaceStart;
        mStringAfter = mStringBefore =
            mStringBefore.substring(nonWhitespaceStart, nonWhitespaceEnd);
      }
    }
  
    public String getRecapitalizedString() {
      return mStringAfter;
    }
  
    public int getNewCursorStart() {
      return mCursorStartAfter;
    }
  
    public int getNewCursorEnd() {
      return mCursorEndAfter;
    }
  
    public int getCurrentMode() {
      return ROTATION_STYLE[mRotationStyleCurrentIndex];
    }
  }
  