fujaba/NetworkParser

View on GitHub
src/main/java/de/uniks/networkparser/buffer/CharacterBuffer.java

Summary

Maintainability
F
1 wk
Test Coverage
package de.uniks.networkparser.buffer;

import java.util.List;
/*
 * NetworkParser The MIT License Copyright (c) 2010-2016 Stefan Lindel
 * https://www.github.com/fujaba/NetworkParser/
 * 
 * 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.
 */
import de.uniks.networkparser.interfaces.BaseItem;
import de.uniks.networkparser.interfaces.Converter;
import de.uniks.networkparser.list.SimpleList;

/**
 * Buffer of String for alternative for StringBuffer.
 *
 */

public class CharacterBuffer extends BufferedBuffer implements CharSequence, BaseItem {
  /** The value is used for character storage. */
  char[] buffer;

  /**
   * Returns the {@code char} value in this sequence at the specified index. The first {@code char}
   * value is at index {@code 0}, the next at index {@code 1}, and so on, as in array indexing.
   * <p>
   * The index argument must be greater than or equal to {@code 0}, and less than the length of this
   * sequence.
   *
   * <p>
   * If the {@code char} value specified by the index is a
   * <a href="Character.html#unicode">surrogate</a>, the surrogate value is returned.
   *
   * @param index the index of the desired {@code char} value.
   * @return the {@code char} value at the specified index.
   */
  @Override
  public char charAt(int index) {
    if ((index < 0) || (index >= length) || buffer == null || start < 0 || index >= buffer.length) {
      return 0;
    }
    index += start;
    return buffer[index];
  }

  @Override
  public byte byteAt(int index) {
    if ((index < 0) || (index + start >= length())) {
      return 0;
    }
    index += start;
    return (byte) buffer[index + start];
  }

  /**
   * Returns a new character sequence that is a subsequence of this sequence.
   *
   * <p>
   * An invocation of this method of the form
   *
   * <pre>
   * {@code
   * sb.subSequence(begin,&nbsp;end)}
   * </pre>
   *
   * behaves in exactly the same way as the invocation
   *
   * <pre>
   * {@code
   * sb.substring(begin,&nbsp;end)}
   * </pre>
   *
   * This method is provided so that this class can implement the {@link CharSequence} interface.
   *
   * @param start the start index, inclusive.
   * @param end the end index, exclusive.
   * @return the specified subsequence.
   */
  @Override
  public CharacterBuffer subSequence(int start, int end) {
    start += this.start;
    end += this.start;
    if (buffer == null) {
      return new CharacterBuffer();
    }
    if (start < 0) {
      start = position();
    }
    if (end < 0) {
      end = 0;
    }
    if (end > buffer.length) {
      end = buffer.length;
    }
    return new CharacterBuffer().with(this.buffer, start, end, false);
  }

  /**
   * Set the currentVlaue to Buffer
   *
   * @param value String of Value
   * @return the CharacterBuffer
   */
  public CharacterBuffer withValue(String value) {
    if (value != null) {
      this.buffer = value.toCharArray();
      this.length = buffer.length;
      this.start = 0;
      this.position = 0;
    }
    return this;
  }

  public char[] toCharArray() {
    char[] result = new char[this.length];
    for (int i = start; i < this.length; i++) {
      result[i] = (char) buffer[i];
    }
    return result;
  }

  public boolean replace(int start, int end, String replace) {
    int pos = 0;
    if (replace == null || buffer == null || start > end || start > buffer.length) {
      return false;
    }
    int diff = replace.length() - (end - start);
    char[] oldChar = null;
    int oldStart = 0;
    int oldLen = 0;
    if (this.length + diff > this.buffer.length) {
      /* Argh array is to Small */
      int newCapacity = (this.length + diff) * 2 + 2;
      oldChar = this.buffer;

      char[] copy = new char[newCapacity];
      System.arraycopy(buffer, this.start, copy, 0, start);
      oldStart = end;
      oldLen = this.length - oldStart;
      this.buffer = copy;
      this.start = 0;
    }
    start += this.start;
    end += this.start;

    if (diff < 0) {
      while (start < (end + diff)) {
        this.buffer[start++] = replace.charAt(pos++);
      }
      System.arraycopy(buffer, end, buffer, start, length - end);
    } else {
      while (start < end) {
        this.buffer[start++] = replace.charAt(pos++);
      }
      if (diff > 0) {
        if (oldChar == null) {
          oldLen = (this.length + this.start) - start;
          if (oldLen > 0) {
            oldChar = new char[oldLen];
            System.arraycopy(buffer, start, oldChar, 0, oldLen);
          }
        }
        int no = 0;
        while (no < diff) {
          this.buffer[start++] = replace.charAt(pos++);
          no++;
        }
        if (oldLen > 0) {
          System.arraycopy(oldChar, oldStart, buffer, start, oldLen);
        }
      }
    }
    this.length = this.length + diff;
    this.position = 0;
    return true;
  }

  public void replace(char search, char replace) {
    int len = this.length + start;
    int pos = position + start;
    if (replace > 0) {
      while (pos < len) {
        if (buffer[pos] == search) {
          buffer[pos] = replace;
        }
        pos++;
      }
    } else {
      int offset = pos;
      while (pos < len) {
        if (buffer[pos] == search) {
          this.length--;
        } else {
          buffer[offset] = buffer[pos];
          offset++;
        }
        pos++;
      }
    }
  }

  public boolean replace(String search, String replace) {
    if (search == null || search.length() < 1) {
      return false;
    }
    int deleted = 0;
    CharacterBuffer inserts = null;
    int pos = position + start;
    int len = this.length + start;
    int startSet = 0;
    while (pos < len) {
      int i = 0;
      for (; i < search.length(); i++) {
        if (buffer[pos + i] != search.charAt(i)) {
          break;
        }
      }
      if (i == search.length()) {
        int diff = replace.length() - search.length();
        if (diff < 0) {
          for (i = 0; i < replace.length(); i++) {
            buffer[pos + deleted + i] = replace.charAt(i);
          }
          deleted += diff;
          pos += search.length();
        } else {
          if (inserts == null) {
            for (i = 0; i < search.length(); i++) {
              buffer[pos + i] = replace.charAt(i);
            }
            inserts = new CharacterBuffer();
            deleted += replace.length() - i;
            pos += i;
            startSet = pos;
          } else {
            i = 0;
            deleted += replace.length() - search.length();
            pos += search.length();
          }
          for (; i < replace.length(); i++) {
            inserts.with(replace.charAt(i));
          }
        }
      } else {
        if (deleted == 0) {
        } else if (deleted < 0) {
          buffer[pos + deleted] = buffer[pos];
        } else {
          inserts.with(buffer[pos + i]);
        }
        pos++;
      }
    }
    pos = pos + deleted - start;
    if (inserts != null) {
      if (this.length < pos) {
        char[] copy = new char[pos];
        startSet -= this.start;
        System.arraycopy(buffer, this.start, copy, 0, startSet);
        buffer = copy;
        this.start = 0;
      }
      for (int i = 0; i < inserts.length(); i++) {
        this.buffer[startSet + i] = inserts.charAt(i);
      }
    }
    this.length = pos;
    return true;
  }

  /**
   * Get the next character in the source string.
   *
   * @return The next character, or 0 if past the end of the source string.
   */
  @Override
  public char getChar() {
    if (this.buffer == null || this.position + this.start >= this.buffer.length || this.position + this.start < 0) {
      return 0;
    }
    if (this.position < this.length) {
      this.position++;
    }
    if (this.position + this.start == this.buffer.length || this.position + this.start == this.length) {
      return 0;
    }
    char c = this.buffer[this.position + this.start];
    return c;
  }

  /**
   * Init the new CharacterBuffer
   * 
   * @param values the reference CharArray
   * @return the new CharacterBuffer
   */
  public CharacterBuffer with(byte[] values) {
    if (values == null) {
      return this;
    }
    this.buffer = new char[values.length];
    start = 0;
    length = values.length;
    position = 0;
    for (int i = 0; i < values.length; i++) {
      this.buffer[i] = (char) values[i];
    }
    return this;
  }

  public CharacterBuffer withLine(CharSequence value) {
    with(value);
    with(BaseItem.CRLF);
    return this;
  }

  @Override
  public CharacterBuffer withLength(int len) {
    withBufferLength(len);
    super.withLength(len);
    return this;
  }

  public CharacterBuffer withBufferLength(int len) {
    if (this.buffer == null) {
      this.buffer = new char[len];
    } else if (len + start > buffer.length) {
      char[] oldValue = this.buffer;
      this.buffer = new char[len + start];
      if (start < this.length && len > this.length - start) {
        System.arraycopy(oldValue, start, this.buffer, 0, this.length);
      }
      start = 0;
      this.position = 0;
    }
    return this;
  }

  /**
   * Set the Current Startposition
   * 
   * @param pos The new Startposition
   * @return This Component
   */
  public CharacterBuffer withStartPosition(int pos) {
    if (pos < 0) {
      return this;
    }
    int diff = pos - start;
    this.start = pos;
    if (length > diff) {
      this.length -= diff;
    } else {
      this.length = 0;
    }
    return this;
  }

  /**
   * Init the new CharList
   * 
   * @param values the reference CharArray
   * @param start the Startposition for the new CharacterBuffer
   * @param end the Endposition for the new CharacterBuffer
   * @param copy Boolean if copy the Array to new one
   * @return the new CharacterBuffer
   */
  public CharacterBuffer with(char[] values, int start, int end, boolean copy) {
    if (copy) {
      if (values != null) {
        if (start > values.length) {
          return this;
        }
        this.buffer = new char[end];
        this.start = 0;
        this.position = 0;
        length = end;
        System.arraycopy(values, start, this.buffer, 0, end);
      }
    } else {
      this.buffer = values;
      this.start = start;
      this.length = end - start;
    }
    return this;
  }

  /**
   * Init the new CharList
   * 
   * @param values the reference CharArray
   * @param start the Startposition for the new CharacterBuffer
   * @param length the Endposition for the new CharacterBuffer
   * @return the new CharacterBuffer
   */
  public CharacterBuffer with(char[] values, int start, int length) {
    if (values == null || start + length > values.length) {
      return this;
    }
    if (this.length < 0) {
      this.length = this.buffer.length;
    }

    int newLen = length + this.length;
    if (buffer == null || newLen + this.start > buffer.length) {
      char[] oldValue = this.buffer;
      this.buffer = new char[(newLen * 2 + 2)];
      if (oldValue != null) {
        System.arraycopy(oldValue, start, this.buffer, 0, this.length);
      }
      this.start = 0;
      this.position = 0;
    }
    System.arraycopy(values, start, this.buffer, this.length, length);
    this.length = newLen;
    return this;
  }

  /**
   * Init the new CharList
   * 
   * @param values the reference CharArray
   * @param start the Startposition for the new CharacterBuffer
   * @param length the Endposition for the new CharacterBuffer
   * @return the new CharacterBuffer
   */
  public CharacterBuffer with(byte[] values, int start, int length) {
    int newLen = length + this.length;
    if (buffer == null || newLen + this.start > buffer.length) {
      char[] oldValue = this.buffer;
      this.buffer = new char[(newLen * 2 + 2)];
      if (oldValue != null) {
        System.arraycopy(oldValue, start, this.buffer, 0, this.length);
      }
      this.start = 0;
      this.position = 0;
    }
    int minusTag = 0;
    for (int i = start; i < length; i++) {
      if (values[i] >= 0) {
        this.buffer[this.length + i - minusTag] = (char) values[i];
      } else {
        byte b1 = values[i];
        byte b2 = values[i + 1];
        this.buffer[this.length + i
            - minusTag] = (char) (((b1 << 6) ^ b2) ^ (((byte) 0xC0 << 6) ^ ((byte) 0x80 << 0)));
        i++;
        minusTag++;
      }
    }
    this.length = newLen - minusTag;
    return this;
  }

  public CharacterBuffer write(byte[] values, int length) {
    if (values == null) {
      return this;
    }
    if (this.length < 0) {
      this.length = this.buffer.length;
    }
    if (length > values.length) {
      length = values.length;
    }
    int newLen = length + this.length;

    if (buffer == null || newLen + this.start > buffer.length) {
      char[] oldValue = this.buffer;
      this.buffer = new char[(newLen * 2 + 2)];
      if (oldValue != null) {
        System.arraycopy(oldValue, start, this.buffer, 0, this.length);
      }
      this.start = 0;
      this.position = 0;
    }
    for (int i = this.length; i < newLen; i++) {
      this.buffer[i] = (char) values[i - this.length];
    }
    this.length = newLen;
    return this;
  }

  /**
   * Init the new CharacterBuffer
   * 
   * @param values the reference CharSequence
   * @param start the Startposition for the new CharacterBuffer
   * @param end the Endposition for the new CharacterBuffer
   * @return the new CharacterBuffer
   */
  public CharacterBuffer with(CharSequence values, int start, int end) {
    if (values == null || (buffer != null && start > buffer.length)) {
      return this;
    }
    if (this.buffer == null) {
      this.buffer = new char[end - start];
      length = this.buffer.length;
      this.position = 0;
      if (length > 0) {
        for (int i = start; i < values.length(); i++) {
          this.buffer[i - start] = values.charAt(i);
        }
      }
      start = 0;
    } else {
      if (this.length() + values.length() > buffer.length) {
        int newCapacity = (this.length + values.length()) * 2 + 2;
        if (newCapacity < 0) {
          newCapacity = 0;
        }
        char[] copy = new char[newCapacity];
        if (this.start < newCapacity) {
          System.arraycopy(buffer, this.start, copy, 0, length);
          buffer = copy;
        }
        this.start = 0;
      }
      int len = values.length();
      if (this.buffer.length >= length + start + len) {
        for (int c = 0; c < len; c++) {
          this.buffer[length + start + c] = values.charAt(c);
        }
        length += len;
      }
    }
    return this;
  }

  /**
   * Init the new CharacterBuffer
   * 
   * @param items the reference CharSequence
   * @return the new CharacterBuffer
   */
  public CharacterBuffer with(CharSequence... items) {
    if (items == null) {
      return this;
    }
    if (this.buffer == null) {
      int newCapubility = 0;
      for (int i = 0; i < items.length; i++) {
        if (items[i] != null) {
          newCapubility += items[i].length();
        }
      }
      this.buffer = new char[newCapubility];
      start = 0;
      length = this.buffer.length;
      int pos = 0;
      for (int i = 0; i < items.length; i++) {
        if (items[i] == null) {
          continue;
        }
        int len = items[i].length();
        for (int c = 0; c < len; c++) {
          this.buffer[pos++] = items[i].charAt(c);
        }
      }
    } else {
      for (CharSequence item : items) {
        if (item == null) {
          continue;
        }
        with(item, 0, item.length());
      }
    }
    return this;
  }

  public CharacterBuffer with(int value) {
    String bytes = "" + value;
    this.with(bytes);
    return this;
  }

  public CharacterBuffer with(long value) {
    String bytes = "" + value;
    this.with(bytes);
    return this;
  }

  public CharacterBuffer withCollection(String splitter, Object... values) {
    if (values == null) {
      return this;
    }
    int len = values.length;
    if (len < 1) {
      return this;
    }
    if (len == 1 && values[0] instanceof List<?>) {
      List<?> collection = (List<?>) values[0];
      len = collection.size();
      this.add(collection.get(0));
      for (int i = 1; i < len; i++) {
        this.with(splitter);
        this.add(collection.get(i));
      }
      return this;
    }
    this.add(values[0]);
    for (int i = 1; i < len; i++) {
      this.with(splitter);
      this.add(values[i]);
    }
    return this;
  }

  /**
   * Append a new Character to CharacterBuffer
   * 
   * @param item a new StartItem
   * @return CharacterBuffer Instance
   */
  public CharacterBuffer withStart(char item) {
    if (start > 0) {
      if (start > this.buffer.length) {
        start = this.buffer.length - 1;
      }
      this.buffer[--start] = item;
      return this;
    }
    if (buffer != null) {
      char[] oldValue = this.buffer;
      this.buffer = new char[buffer.length + 1];
      this.buffer[0] = item;
      this.position = 0;
      this.validateValue();
      if (length > 0) {
        System.arraycopy(oldValue, start, this.buffer, 1, length - 1);
        this.length++;
      }
    }
    return this;
  }

  /**
   * Append a new Character to CharacterBuffer
   * 
   * @param item a new StartItem
   * @param newLine add newLine to Buffer at the end
   * @return CharacterBuffer Instance
   */
  public CharacterBuffer withStart(CharSequence item, boolean newLine) {
    if (item == null || start < 0) {
      return this;
    }
    int len = item.length();
    if (newLine) {
      len += 2;
    }
    if (start > len && start > 0) {
      if (start < buffer.length) {
        if (newLine) {
          this.buffer[--start] = '\n';
          this.buffer[--start] = '\r';
        }
        for (int i = item.length() - 1; i >= 0; i--) {
          this.buffer[--start] = item.charAt(i);
        }
      }
      return this;
    }
    char[] oldValue = this.buffer;
    if (buffer != null) {
      this.buffer = new char[buffer.length + len];
    } else {
      this.buffer = new char[len];
    }
    for (int i = 0; i < item.length(); i++) {
      this.buffer[i] = item.charAt(i);
    }
    if (newLine) {
      this.buffer[item.length()] = '\r';
      this.buffer[item.length() + 1] = '\n';
    }
    this.position = 0;
    if (oldValue != null && length > 0) {
      System.arraycopy(oldValue, start, this.buffer, len, length);
      start = 0;
    }
    length += len;
    return this;
  }

  /**
   * Init the new CharList
   * 
   * @param value the reference CharSequence
   * @return the new CharList
   */
  public CharacterBuffer set(CharSequence value) {
    this.start = 0;
    if (value == null) {
      this.length = 0;
      this.buffer = null;
      return this;
    }
    this.length = value.length();
    if (this.buffer == null || this.buffer.length < value.length()) {
      this.buffer = new char[this.length];
    }
    for (int i = 0; i < this.length; i++) {
      this.buffer[i] = value.charAt(i);
    }
    return this;
  }

  /**
   * Init the new CharacterBuffer
   * 
   * @param value the reference CharSequence
   * @return the new CharacterBuffer
   */
  public CharacterBuffer set(char value) {
    if (buffer == null) {
      return this;
    }
    this.start = 0;
    this.length = 1;
    if (this.buffer.length < 1) {
      this.buffer = new char[1];
    }
    this.buffer[0] = value;
    return this;
  }

  public boolean startsWith(CharSequence prefix) {
    return this.startsWith(prefix, 0, false);
  }

  public boolean startsWith(CharSequence prefix, int toffset, boolean ignoreCase) {
    if (buffer == null) {
      return false;
    }
    char ta[] = buffer;
    int to = toffset + start;
    int pc = prefix.length();
    if ((toffset < 0) || (toffset > buffer.length - pc)) {
      return false;
    }
    int po = 0;
    /* Note: toffset might be near -1>>>1. */
    while (--pc >= 0) {
      char c1 = ta[to++];
      char c2 = prefix.charAt(po++);
      if (c1 != c2) {
        if (ignoreCase) {
          if (Character.toLowerCase(c1) == Character.toLowerCase(c2)) {
            continue;
          }
        }
        return false;
      }
    }
    return true;
  }

  /**
   * Returns the number of elements between the current position and the limit.
   *
   * @return The number of elements remaining in this buffer
   */
  public final int remaining() {
    if (buffer == null) {
      return 0;
    }
    return buffer.length - start;
  }

  public char remove(int position) {
    if (position < 0 || this.buffer == null || position > this.buffer.length) {
      return 0;
    }
    char oldChar = this.buffer[position];
    if (position == start) {
      start++;
      return this.buffer[position];
    } else if (position == length - 1) {
    } else {
      char[] copy = new char[this.buffer.length - 1];
      System.arraycopy(this.buffer, start, copy, 0, position);
      if (length - position - 1 > 0) {
        System.arraycopy(this.buffer, position + 1, copy, position, length - position - 1);
      }
      start = 0;
    }
    length--;
    return oldChar;
  }

  public CharacterBuffer trimStart(int pos) {
    this.start += pos;
    this.length -= pos;
    return this;
  }

  public CharacterBuffer trimEnd(int pos) {
    this.length -= pos;
    return this;
  }

  private boolean validateValue() {
    if (buffer == null) {
      this.start = 0;
      this.length = 0;
      return true;
    }
    boolean change = false;
    if (this.start < 0) {
      this.start = 0;
      change = true;
    }
    if (this.length < 0) {
      this.length = buffer.length - start;
      if (length < 0) {
        length = 0;
      }
      change = true;
    } else if (this.length > buffer.length) {
      change = true;
      this.length = buffer.length - start;
    }
    return change;
  }

  public CharacterBuffer rtrim(char... items) {
    validateValue();
    if (items != null) {
      int z;
      while (length > 0) {
        if (buffer[length + start - 1] <= SPACE) {
          length--;
        } else {
          boolean found = false;
          for (z = 0; z < items.length; z++) {
            if (buffer[length + start - 1] == items[z]) {
              found = true;
              break;
            }
          }
          if (found) {
            length--;
          } else {
            break;
          }
        }
      }
      return this;
    }
    while (length > 0 && (buffer[length + start - 1] <= SPACE)) {
      length--;
    }
    return this;
  }

  public CharacterBuffer trim() {
    if (buffer == null) {
      return this;
    }
    if (length > buffer.length) {
      length = buffer.length;
    }
    if (start < 0 || start > length) {
      return this;
    }
    while (length > 0 && (buffer[length + start - 1] <= SPACE)) {
      length--;
    }
    while ((start < length) && (buffer[start] <= SPACE)) {
      start++;
      length--;
    }
    return this;
  }

  public boolean equalsText(char... other) {
    if (other == null) {
      return true;
    }
    if (start > length || start < 0 || buffer == null) {
      return false;
    }
    int pos = start;
    if (length() > buffer.length) {
      length = buffer.length;
    }
    int l = 0;
    while (pos < length) {
      if (l == other.length) {
        break;
      }
      if (buffer[pos] == SPACE || buffer[pos] == '\t') {
        if (l == 0) {
          pos++;
          continue;
        } else if (other[l] == buffer[pos]) {
          pos++;
          l++;
          continue;
        }
        break;
      } else if (other[l] == buffer[pos]) {
        pos++;
        l++;
        continue;
      }
      return false;
    }
    return l == other.length;
  }

  /**
   * Get Levenstein distance
   * 
   * @param t the other String
   * @return Levenstein distance 0 both String are equals pro Case difference ( + 0.01 ) pro
   *         difference ( + 1 ) if this contains t Levenstein is negativ
   */
  public double equalsLevenshtein(CharacterBuffer t) {
    if (t == null || t.length() < 1) {
      return this.length();
    }
    if (this.length() < 1) {
      return t.length();
    }
    int n = this.length();
    int m = t.length();
    CharacterBuffer s = this;

    if (n > m) {
      /* swap the input strings to consume less memory */
      s = t;
      t = this;
      n = m;
      m = this.length();
    }
    final double p[] = new double[n + 1]; /* indexes into strings s and t */
    int i; /* iterates through s */
    int j; /* iterates through t */
    double upper_left;
    double upper;
    char t_j; /* jth character of t */
    double cost;
    for (i = 0; i <= n; i++) {
      p[i] = i;
    }
    int containsPos = 1;
    boolean search = true;
    for (j = 1; j <= m; j++) {
      upper_left = p[0];
      t_j = t.charAt(j - 1);
      p[0] = j;
      search = true;
      for (i = 1; i <= n; i++) {
        upper = p[i];
        if (s.charAt(i - 1) == t_j) {
          cost = 0;
          if (containsPos == i) {
            containsPos++;
            search = false;
          }
        } else if (toLower(t_j) == toLower(s.charAt(i - 1))) {
          if (s.charAt(0) == t_j) {
            containsPos = 2;
          } else {
            containsPos = 1;
          }
          cost = 0.01;
        } else {
          cost = 1;
          if (containsPos == i && search) {
            if (s.charAt(0) == t_j) {
              containsPos = 2;
            } else {
              containsPos = 1;
            }
          }
        }
        /* minimum of cell to the left+1, to the top+1, diagonally left and up +cost */
        p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost);
        upper_left = upper;
      }
    }
    if (containsPos > n) {
      return p[n] * -1;
    }
    return p[n];
  }

  private static char toLower(char item) {
    if (item >= 'A' && item <= 'Z') {
      return item += 32;
    }
    return item;
  }

  public boolean isEmptyCharacter() {
    if (super.isEmpty() || start > length || start < 0) {
      return true;
    }
    if (length > buffer.length) {
      length = buffer.length;
    }
    int len = length;
    int pos = start;
    while (len > 0 && (buffer[len + pos - 1] <= SPACE)) {
      len--;
    }
    while ((pos < len) && (buffer[pos] <= SPACE)) {
      pos++;
      len--;
    }
    return len == 0;
  }

  public boolean withRepeat(String string, int rest) {
    if (string == null) {
      return false;
    }
    int newCapacity = this.length() + rest * string.length();
    if (this.buffer == null) {
      this.buffer = new char[newCapacity];
      start = 0;
      length = 0;
    } else {
      if (newCapacity > buffer.length) {
        char[] copy = new char[newCapacity];
        if (length > 0 && (start + length) <= buffer.length) {
          System.arraycopy(buffer, this.start, copy, 0, length);
        }
        buffer = copy;
        this.start = 0;
      }
    }
    for (int i = 0; i < rest; i++) {
      for (int c = 0; c < string.length(); c++) {
        this.buffer[length++] = string.charAt(c);
      }
    }
    return true;
  }

  /**
   * Init the new CharacterBuffer
   * 
   * @param items the reference CharSequence
   * @return the new CharacterBuffer
   */
  public CharacterBuffer withObjects(Object... items) {
    if (items == null) {
      return this;
    }
    if (this.buffer == null) {
      int newCapubility = 0;
      for (int i = 0; i < items.length; i++) {
        if (items[i] != null) {
          if ((items[i] instanceof CharSequence) == false) {
            items[i] = items[i].toString();
          }
          newCapubility += ((CharSequence) items[i]).length();
        }
      }
      this.buffer = new char[newCapubility];
      start = 0;
      length = this.buffer.length;
      int pos = 0;
      for (int i = 0; i < items.length; i++) {
        if (items[i] != null) {
          CharSequence value = (CharSequence) items[i];
          int len = value.length();
          for (int c = 0; c < len; c++) {
            this.buffer[pos++] = value.charAt(c);
          }
        }
      }
    } else {
      for (Object item : items) {
        CharSequence value = null;
        if (item instanceof CharSequence) {
          value = (CharSequence) item;
        } else if (item != null) {
          value = item.toString();
        }
        if (value != null) {
          with(value, 0, value.length());
        }
      }
    }
    return this;
  }

  /**
   * Init the new CharList
   * 
   * @param src the reference CharSequence
   * @return the new CharList
   */
  public CharacterBuffer with(char src) {
    if (this.buffer == null) {
      this.buffer = new char[5];
      start = 0;
      length = 1;
      this.buffer[0] = src;
    } else {
      if (this.length + 1 > buffer.length && this.start >= 0) {
        int newCapacity = buffer.length * 2 + 2;
        char[] copy = new char[newCapacity];
        System.arraycopy(buffer, this.start, copy, 0, length);
        buffer = copy;
        this.start = 0;
      }
      if (length >= 0 && length < this.buffer.length) {
        this.buffer[length++] = src;
      }
    }
    return this;
  }

  public void trimSize() {
    if (length() >= 0) {
      char[] array = new char[length];
      if (length > 0) {
        System.arraycopy(buffer, this.start, array, 0, length);
      }
      this.buffer = array;
      this.position = 0;
      this.start = 0;
    }
  }

  @Override
  public String toString() {
    if (length < 1) {
      return "";
    }
    return new String(buffer, start, length);
  }

  public boolean equals(CharSequence other) {
    if (other == null || other.length() != length) {
      return false;
    }
    return startsWith(other, 0, false);
  }

  public boolean equalsIgnoreCase(CharSequence other) {
    if (other == null || other.length() != length) {
      return false;
    }
    return startsWith(other, 0, true);
  }

  public int indexOf(int ch) {
    return indexOf(ch, 0);
  }

  public int indexOf(CharSequence value) {
    return indexOf(value, 0);
  }

  public int indexOf(int ch, int fromIndex) {
    final int max = length();
    if (fromIndex < 0) {
      fromIndex = 0;
    } else if (fromIndex >= length) {
      /* Note: fromIndex might be near -1>>>1. */
      return -1;
    }
    for (int i = fromIndex; i < max; i++) {
      if (buffer[i + start] == ch) {
        return i;
      }
    }
    return -1;
  }

  public int indexOf(CharSequence str, int fromIndex) {
    final int max = length();
    if (fromIndex < 0) {
      fromIndex = 0;
    } else if (fromIndex >= length) {
      /* Note: fromIndex might be near -1>>>1. */
      return -1;
    }
    if (str == null || str.length() == 0) {
      return -1;
    }
    final int len = str.length() - 1;
    int pos = 0;
    for (int i = fromIndex; i < max; i++) {
      if (buffer[i + start] == str.charAt(pos)) {
        if (pos == len) {
          return i - pos;
        }
        pos++;
      } else {
        pos = 0;
      }
    }
    return -1;
  }

  public int lastIndexOf(char ch) {
    for (int i = length - 1; i >= start; i--) {
      if (buffer[i] == ch) {
        return i - start;
      }
    }
    return -1;
  }

  /**
   * get the () values
   *
   * @param start Startcharacter
   * @param end Endcharacter
   * @return String of values
   */
  public String getStringPart(Character start, Character end) {
    if (start == null || end == null) {
      return null;
    }
    int count = 1;
    Character current = null;
    int pos;
    if (getCurrentChar() == start) {
      pos = position();
    } else {
      pos = position() - 1;
    }
    while (isEnd() == false) {
      current = getChar();
      if (current.compareTo(end) == 0) {
        count--;
        if (count == 0) {
          skip();
          return subSequence(pos, position()).toString();
        }
        continue;
      }
      if (current.compareTo(start) == 0) {
        count++;
      }
    }
    return null;
  }

  public boolean endsWith(CharSequence string, boolean ignoreCase) {
    if (string == null) {
      return true;
    }
    int pos = this.length() - string.length();
    if (pos < 0) {
      return false;
    }
    return startsWith(string, pos, ignoreCase);
  }

  public void setNextString(CharSequence property, int pos) {
    this.withLength(pos);
    this.start = 0;
    this.with(property);
  }

  public static CharacterBuffer create(CharSequence value) {
    if (value instanceof CharacterBuffer) {
      return (CharacterBuffer) value;
    }
    CharacterBuffer buffer = new CharacterBuffer();
    if (value instanceof String) {
      buffer.with(value);
    }
    return buffer;
  }

  public String toCurrentString() {
    if (validateValue() || position > length) {
      return "";
    }

    return new String(buffer, position, length - position);
  }

  public CharacterBuffer insert(int offset, String values) {
    if ((offset < 0) || (offset > length())) {
      return this;
    }
    if (values == null)
      values = "null";
    int len = values.length();
    if (this.length + len > buffer.length) {
      int newCapacity = (this.length + len) * 2 + 2;
      char[] copy = new char[newCapacity];
      System.arraycopy(buffer, this.start, copy, 0, length);
      buffer = copy;
      this.start = 0;
    }
    /* Move String */
    System.arraycopy(buffer, offset, buffer, offset + len, this.length - offset);
    values.getChars(0, len, buffer, offset);
    this.length += len;
    return this;
  }

  public boolean addValues(char sep, String... values) {
    if (values == null) {
      return false;
    }
    int size = this.size();
    for (String item : values) {
      if (item != null) {
        if (size > 0) {
          this.with(sep);
        }
        this.with(item);
        size++;
      }
    }
    return true;
  }

  public boolean add(Object... values) {
    if (values == null) {
      return true;
    }
    boolean addValues = true;
    for (Object item : values) {
      if (item instanceof CharSequence) {
        this.with((CharSequence) item);
      } else if (item instanceof Character) {
        this.with((Character) item);
      } else {
        addValues = false;
      }
    }
    return addValues;
  }

  @Override
  public void printError(String msg) {
    int startPos = 0;
    if (position >= 10) {
      startPos = position - 10;
    }
    int endPos = position + 20;

    if (endPos >= length()) {
      endPos = length();
    }
    if (msg != null && msg.length() > 0) {
      System.err.println(substring(startPos, position) + "<--" + msg + "-->" + substring(position, endPos));
    }
  }

  @Override
  public CharacterBuffer getNewList(boolean keyValue) {
    return new CharacterBuffer();
  }

  @Override
  public int size() {
    return length();
  }

  @Override
  public String toString(Converter converter) {
    return toString();
  }

  public CharacterBuffer newLine() {
    this.with(BaseItem.CRLF);
    return this;
  }

  public CharacterBuffer getLine(int pos) {
    CharacterBuffer buffer = new CharacterBuffer();
    if (pos > 0 && pos < length()) {
      int start = pos;
      while (this.buffer[start] != '\r' && this.buffer[start] != '\n' && start > 0) {
        start--;
      }
      if (start > 0) {
        start++;
      }
      int end = pos;
      while (end < length && this.buffer[end] != '\r' && this.buffer[end] != '\n') {
        end++;
      }
      buffer.with(this.buffer, start, end - start);
    }
    return buffer;
  }

  /**
   * Split Strings
   * 
   * @param split Strng for Spliting
   * @return a List of String Parts
   */
  public SimpleList<String> splitStrings(char split) {

    SimpleList<String> result = new SimpleList<String>();
    if (buffer == null) {
      return result;
    }
    if (start > buffer.length || start < 0) {
      return result;
    }
    int s = start;
    int i = start;
    for (; i < size(); i++) {
      if (buffer[i] == split) {
        result.add(new String(buffer, s, i - s));
        s = i + 1;
      }
    }
    if (s < i) {
      result.add(new String(buffer, s, i - s));
    }
    return result;
  }

  @Override
  public int length() {
    validateValue();
    return super.length();
  }

  public boolean append(CharSequence value) {
    return this.add(value);
  }

  public boolean setCharAt(int pos, char character) {
    if (pos < 0 || pos > buffer.length) {
      return false;
    }
    buffer[pos] = character;
    return true;
  }
}