org.trnltk.model.letter.TurkishSequence.java Source code

Java tutorial

Introduction

Here is the source code for org.trnltk.model.letter.TurkishSequence.java

Source

/*
 * Copyright  2013  Ali Ok (aliokATapacheDOTorg)
 *
 *  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 org.trnltk.model.letter;

import com.google.common.base.Strings;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;

/**
 * An immutable sequence of {@link TurkishChar}s.
 */
public class TurkishSequence {
    private final String underlyingString;
    private final TurkishChar[] chars;
    private TurkishChar firstVowel;
    private TurkishChar lastVowel;
    private int count;

    /**
     * Create a {@link TurkishSequence} instance from a string.
     * <p/>
     * Chars are one by one converted to {@link TurkishChar}s, thus if you are going to clone a {@link TurkishSequence}
     * it is advised to use the method {@link TurkishSequence#TurkishSequence(TurkishSequence)}
     *
     * @param underlyingString String to convert to {@link TurkishSequence}
     */
    public TurkishSequence(String underlyingString) {
        this.underlyingString = Strings.nullToEmpty(underlyingString);
        this.count = underlyingString.length();
        this.chars = new TurkishChar[this.count];
        for (int i = 0; i < underlyingString.length(); i++) {
            char c = underlyingString.charAt(i);
            TurkishChar turkishChar = TurkishAlphabet.getChar(c);
            this.chars[i] = turkishChar;
            if (turkishChar.getLetter().isVowel()) {
                if (this.firstVowel == null)
                    this.firstVowel = turkishChar;
                this.lastVowel = turkishChar;
            }
        }
    }

    /**
     * Deep-copy constructor. Copies the properties from argument and creates a new {@link TurkishSequence}.
     *
     * @param toClone Sequence to copy
     */
    @SuppressWarnings("UnusedDeclaration")
    public TurkishSequence(final TurkishSequence toClone) {
        this(toClone, "");
    }

    /**
     * Creates a new {@link TurkishSequence} from the given chars.
     *
     * @param turkishChars Char array to convert to a {@link TurkishSequence}
     */
    public TurkishSequence(final TurkishChar[] turkishChars) {
        StringBuilder underlyingStringBuilder = new StringBuilder();
        this.count = turkishChars.length;
        this.chars = new TurkishChar[this.count];
        for (int i = 0; i < this.count; i++) {
            TurkishChar turkishChar = turkishChars[i];
            this.chars[i] = turkishChar;
            if (turkishChar.getLetter().isVowel()) {
                if (this.firstVowel == null)
                    this.firstVowel = turkishChar;
                this.lastVowel = turkishChar;
            }

            underlyingStringBuilder.append(turkishChar.getCharValue());
        }

        this.underlyingString = underlyingStringBuilder.toString();
    }

    private TurkishSequence(final TurkishSequence first, final String strSecond) {
        // some notes here:
        // - TurkishChar instances are immutable. Thus it is safe to reference the chars of param 'first'.

        final String strFirst = first.underlyingString;
        final TurkishChar[] charsFirst = first.chars;
        this.underlyingString = strFirst + strSecond;
        this.count = this.underlyingString.length();
        this.firstVowel = first.firstVowel;
        this.lastVowel = first.lastVowel;
        this.chars = new TurkishChar[charsFirst.length + strSecond.length()];
        System.arraycopy(charsFirst, 0, this.chars, 0, charsFirst.length);
        for (int i = 0; i < strSecond.length(); i++) {
            char charOfSecondStr = strSecond.charAt(i);
            TurkishChar turkishCharOfSecondStr = TurkishAlphabet.getChar(charOfSecondStr);
            this.chars[i + charsFirst.length] = turkishCharOfSecondStr;
            if (turkishCharOfSecondStr.getLetter().isVowel()) {
                if (this.firstVowel == null)
                    this.firstVowel = turkishCharOfSecondStr;
                this.lastVowel = turkishCharOfSecondStr;
            }
        }
    }

    /**
     * Appends the given char to current sequence and returns a new sequence. Current sequence will not be modified.
     *
     * @param turkishChar Char to append
     * @return New sequence
     */
    public TurkishSequence append(TurkishChar turkishChar) {
        return new TurkishSequence(this, String.valueOf(turkishChar.getCharValue()));
    }

    /**
     * Appends the given string to current sequence and returns a new sequence. Current sequence will not be modified.
     *
     * @param str String to append
     * @return New sequence
     */
    public TurkishSequence append(String str) {
        if (StringUtils.isEmpty(str))
            return this;
        else
            return new TurkishSequence(this, str);
    }

    /**
     * Creates a subsequence starting at index {@code beginIndex} and ending at last character.
     *
     * @param beginIndex The begin index
     * @return A new {@link TurkishSequence} instance as subsequence
     * @see TurkishSequence#subsequence(int, int)
     */
    public TurkishSequence subsequence(int beginIndex) {
        //TODO: create a version which works with negatives! like the Python slicing
        return this.subsequence(beginIndex, this.count);
    }

    /**
     * Creates a subsequence starting at index {@code beginIndex} and ending at index {@code endIndex}.
     * <p/>
     * Returned subsequence is not a view, but a full-copy.
     *
     * @param beginIndex The begin index
     * @param endIndex   The end index
     * @return A new {@link TurkishSequence} instance as subsequence
     */
    public TurkishSequence subsequence(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > this.count) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        if (beginIndex > endIndex) {
            throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
        }

        if (((beginIndex == 0) && (endIndex == this.count)))
            return this;

        return new TurkishSequence(Arrays.copyOfRange(this.chars, beginIndex, endIndex));
    }

    /**
     * If last letter of the sequence is voicable, then returns a new sequence with last letter voiced.
     * If not, returns the {@link TurkishSequence} instance method triggered on.
     *
     * @return The sequence with last letter voiced if last letter is voicable
     * @see TurkishAlphabet#voice(TurkicLetter)
     */
    public TurkishSequence voiceLastLetterIfPossible() {
        final TurkishChar lastChar = this.getLastChar();
        final TurkicLetter letter = lastChar.getLetter();
        final TurkicLetter voicedLetter = TurkishAlphabet.voice(letter);
        if (voicedLetter != null)
            return this.subsequence(0, this.count - 1).append(voicedLetter.charValue() + "");
        else
            return this;
    }

    /**
     * Returns shallow clone of the underlying {@link TurkishChar}s.
     *
     * @return Shallow clone of underlying chars
     */
    public TurkishChar[] getChars() {
        return chars.clone();
    }

    /**
     * @return Underlying string of the sequence
     */
    public String getUnderlyingString() {
        return underlyingString;
    }

    /**
     * @return length of the sequence
     */
    public int length() {
        return this.count;
    }

    /**
     * Checks if given sequence is beginning of the sequence.
     *
     * @param str Sequence to check if starts with
     * @return true/false
     */
    public boolean startsWith(TurkishSequence str) {
        return this.underlyingString.startsWith(str.getUnderlyingString());
    }

    /**
     * Returns the substring starting at index {@code beginIndex} and ends at end of the sequence. Mimics the behavior of
     * {@link String#substring(int)}
     * <p/>
     * If you need subsequence instead of substring, use {@link TurkishSequence#subsequence(int)} as it is more efficient.
     *
     * @param beginIndex The begin index
     * @return Substring
     */
    public String substring(int beginIndex) {
        //TODO: create a version which works with negatives!
        return this.underlyingString.substring(beginIndex);
    }

    /**
     * Returns the substring starting at index {@code beginIndex} and ends at index {@code endIndex}. Mimics the behavior of
     * {@link String#substring(int, int)}
     * <p/>
     * If you need subsequence instead of substring, use {@link TurkishSequence#subsequence(int, int)} as it is more efficient.
     *
     * @param beginIndex The begin index
     * @param endIndex The end index
     * @return Substring
     */
    @SuppressWarnings("UnusedDeclaration")
    private String substring(int beginIndex, int endIndex) {
        return this.underlyingString.substring(beginIndex, endIndex);
    }

    /**
     * Convenience method to check if the sequence is blank (blank != empty. empty  blank).
     *
     * @see org.apache.commons.lang3.StringUtils#isBlank(CharSequence)
     *
     * @return true/false
     */
    public boolean isBlank() {
        return StringUtils.isBlank(this.underlyingString);
    }

    public TurkishChar getLastChar() {
        if (this.count == 0)
            return null;
        else
            return this.charAt(this.count - 1);
    }

    public TurkishChar charAt(int index) {
        return this.chars[index];
    }

    public TurkishChar getLastVowel() {
        return this.lastVowel;
    }

    public TurkishChar getFirstVowel() {
        return this.firstVowel;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;

        TurkishSequence that = (TurkishSequence) o;

        return count == that.count && underlyingString.equals(that.underlyingString);
    }

    @Override
    public int hashCode() {
        return underlyingString.hashCode();
    }

    @Override
    public String toString() {
        return "TurkishSequence{" + "underlyingString='" + underlyingString + '\'' + '}';
    }
}