/* * This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT). * * Copyright (c) JCThePants (www.jcwhatever.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.jcwhatever.nucleus.utils.text; import com.jcwhatever.nucleus.utils.PreCon; /** * A {@link java.lang.CharSequence} implementation that allows the characters * to be rotated left or right. * * <p>Allows changing the string without changing the rotation.</p> */ public class CircularString implements CharSequence { protected char[] _string; protected char[] _result; protected boolean _hasResult; protected int _rotation; public CircularString() { _string = new char[0]; } /** * Constructor. * * @param characters The initial string characters. */ public CircularString(char[] characters) { PreCon.notNull(characters); _string = characters; } /** * Constructor. * * @param string The initial string. */ public CircularString(String string) { PreCon.notNull(string); _string = string.toCharArray(); } /** * Set the string. The rotation is not changed. * * @param string The string to set. */ public void setString(String string) { PreCon.notNull(string); _string = string.toCharArray(); _hasResult = false; } /** * Returns a reference to the array of un-rotated characters being * used by the {@link CircularString}. */ public char[] getChars() { return _string; } /** * Reset the rotation back to 0. */ public void reset() { if (_rotation == 0) return; _rotation = 0; _hasResult = false; } /** * Get the current rotation index. */ public int getRotation() { return _rotation; } /** * Rotate the string to the left by the specified amount. * * @param amount The amount to rotate the string. */ public void rotateLeft(int amount) { _rotation = getCorrectIndex(_rotation + amount); _hasResult = false; } /** * Rotate the string to the right by the specified amount. * * @param amount The amount to rotate the string. */ public void rotateRight(int amount) { _rotation = getCorrectIndex(_rotation - amount); _hasResult = false; } /** * Set the character at the specified position. The position * is relative to the current rotation. * * <p>The index can be a negative or out of bounds number.</p> * * @param index The index. * @param ch The replacement character. */ public void setChar(int index, char ch) { _string[getCorrectIndex(_rotation + index)] = ch; _hasResult = false; } @Override public int length() { return _string.length; } /** * Set the character at the specified index relative * to the current rotation. * * <p>The index can be a negative or out of bounds number.</p> * * @param index The index. */ @Override public char charAt(int index) { return _string[getCorrectIndex(_rotation + index)]; } /** * Get a new {@link CircularString} whose characters are * a sub-sequence of characters from the current. * * @param start The start index of the sequence relative to the current rotation. * @param end The end index (+1) of the sequence relative to the current rotation. */ @Override public CircularString subSequence(int start, int end) { PreCon.isValid(end >= start, "end argument must be greater than or equal to start argument."); PreCon.lessThan(start, _string.length, "start"); PreCon.lessThan(end, _string.length, "end"); int len = end - start; CircularString result = new CircularString(); result._string = new char[len]; for (int i=0; i < len; i++) { result._string[i] = _string[getCorrectIndex(_rotation + i + start)]; } return result; } @Override public String toString() { updateResult(); return new String(_result); } protected int getCorrectIndex(int index) { return index < 0 ? _string.length - ((-index) % _string.length) : index % _string.length; } protected void updateResult() { if (_hasResult) return; if (_result == null || _result.length != _string.length) _result = new char[_string.length]; for (int i=0; i < _string.length; i++) { _result[i] = _string[(_rotation + i) % _string.length]; } _hasResult = true; } }