/*                     __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2006-2009, LAMP/EPFL             **
**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
\*                                                                      */

// $Id: StringBuilder.scala 16884 2009-01-09 16:52:09Z cunei $


package scala.collection.mutable

import collection.generic._
import scala.runtime.RichString
import compat.Platform.arraycopy
import scala.reflect.Manifest

/** <p>
 *    A mutable sequence of characters.  This class provides an API compatible
 *    with <a class="java/lang/StringBuilder" href="" target="_top">
 *    <code>java.lang.StringBuilder</code></a>.
 *  </p>generic/
 *
 *  @author Stephane Micheloud
 *  @author Martin Odersky
 *  @version 2.8
 */
@serializable
@SerialVersionUID(0 - 8525408645367278351L)
final class StringBuilder(initCapacity: Int, private val initValue: String)
      extends Builder[Char, String]
         with Vector[Char] {

  require(initCapacity >= 0)

  /** The value is used for character storage. */
  private var array = new Array[Char](initCapacity + initValue.length)

  /** The count is the number of characters used. */
  private var count: Int = 0

  /** Constructs a string builder with no characters in it and an 
   *  initial capacity of 16 characters.
   */
  def this() = this(16, "")

  /** Constructs a string builder with no characters in it and an 
   *  initial capacity specified by the <code>capacity</code> argument. 
   *
   *  @param  capacity  the initial capacity.
   *  @throws NegativeArraySizeException  if the <code>capacity</code>
   *                    argument is less than <code>0</code>.
   */
  def this(capacity: Int) = this(capacity, "")

  /** Constructs a string builder with initial characters 
   *  equal to characters of `str`.
   */
  def this(str: String) = this(16, str)

  append(initValue)

  def toArray: Array[Char] = array

  def length: Int = count
  def length_=(n: Int) { setLength(n) }
 
  /** Clears the builder contents.
   */
  def clear(): Unit = setLength(0)

 /** Sets the length of the character sequence.
   *
   *  @param  newLength  the new length
   *  @throws IndexOutOfBoundsException  if the <code>n</code> argument is negative.
   */
  def setLength(n: Int) {
    require(n >= 0, n)
    while (count < n) append('\0')
    count = n
  }

  /** Returns the current capacity. The capacity is the amount of storage 
   *  available for newly inserted characters, beyond which an allocation 
   *  will occur.
   *
   *  @return  the current capacity
   */
  def capacity: Int = array.length

  /** Same as <code>ensureCapacity</code>. */
  @deprecated("use `ensureCapacity' instead. An assignment is misleading because\n"+
              "it can never decrease the capacity.")
  def capacity_=(n: Int) { ensureCapacity(n) }

  /** <p>
   *    Ensures that the capacity is at least equal to the specified minimum.
   *    If the current capacity is less than the argument, then a new internal
   *    array is allocated with greater capacity. The new capacity is the larger of: 
   *  </p>
   *  <ul>
   *    <li>The <code>n</code> argument. 
   *    <li>Twice the old capacity, plus <code>2</code>. 
   *  </ul>
   *  <p>
   *    If the <code>n</code> argument is non-positive, this
   *    method takes no action and simply returns.
   *  </p>
   *
   *  @param n the minimum desired capacity.
   */
  def ensureCapacity(n: Int) {
    if (n > array.length) {
      var newsize = array.length * 2
      while (n > newsize)
        newsize = newsize * 2
      val newar = new Array[Char](newsize)
      arraycopy(array, 0, newar, 0, count)
      array = newar
    }
  }
      
  /** <p>
   *    Returns the <code>Char</code> value in this sequence at the specified index.
   *    The first <code>Char</code> value is at index <code>0</code>, the next at index
   *    <code>1</code>, and so on, as in array indexing.
   *  </p>
   *  <p>
   *    The index argument must be greater than or equal to
   *    <code>0</code>, and less than the length of this sequence.
   *  </p>
   *
   *  @param  index   the index of the desired <code>Char</code> value.
   *  @return         the <code>Char</code> value at the specified index.
   *  @throws IndexOutOfBoundsException  if <code>index</code> is 
   *                  negative or greater than or equal to <code>length()</code>.
   */
  def charAt(index: Int): Char = {
    if (index < 0 || index >= count)
      throw new StringIndexOutOfBoundsException(index)
    array(index)
  }

  /** Same as <code>charAt</code>. */
  def apply(i: Int): Char = charAt(i)

  /** <p>
   *    Removes the <code>Char</code> at the specified position in this
   *    sequence. This sequence is shortened by one <code>Char</code>.
   *  </p>
   *
   *  @param  index  Index of <code>Char</code> to remove
   *  @return        This object.
   *  @throws StringIndexOutOfBoundsException  if the <code>index</code>
   *	             is negative or greater than or equal to <code>length()</code>.
   */
  def deleteCharAt(index: Int): StringBuilder = {
    if (index < 0 || index >= count)
      throw new StringIndexOutOfBoundsException(index)
    arraycopy(array, index + 1, array, index, count - index - 1)
    count -= 1
    this
  }

  /** <p>
   *    The character at the specified index is set to <code>ch</code>. This 
   *    sequence is altered to represent a new character sequence that is 
   *    identical to the old character sequence, except that it contains the 
   *    character <code>ch</code> at position <code>index</code>. 
   *  </p>
   *  <p>
   *    The index argument must be greater than or equal to 
   *    <code>0</code>, and less than the length of this sequence. 
   *  </p>
   *
   *  @param  index   the index of the character to modify.
   *  @param  ch      the new character.
   *  @throws IndexOutOfBoundsException  if <code>index</code> is 
   *                  negative or greater than or equal to <code>length()</code>.
   */
  def setCharAt(index: Int, ch: Char) {
    if (index < 0 || index >= count)
      throw new StringIndexOutOfBoundsException(index)
    array(index) = ch
  }

  /** Same as <code>setCharAt</code>. */
  def update(i: Int, c: Char) { setCharAt(i, c) }

  /** Returns a new <code>String</code> that contains a subsequence of
   *  characters currently contained in this character sequence. The 
   *  substring begins at the specified index and extends to the end of
   *  this sequence.
   * 
   *  @param  start  The beginning index, inclusive.
   *  @return        The new string.
   *  @throws StringIndexOutOfBoundsException  if <code>start</code> is
   *                 less than zero, or greater than the length of this object.
   */
  def substring(start: Int): String = substring(start, count)

  /** Returns a new <code>String</code> that contains a subsequence of
   *  characters currently contained in this sequence. The 
   *  substring begins at the specified <code>start</code> and 
   *  extends to the character at index <code>end - 1</code>.
   *
   *  @param  start  The beginning index, inclusive.
   *  @param  end    The ending index, exclusive.
   *  @return The new string.
   *  @throws StringIndexOutOfBoundsException  if <code>start</code>
   *                 or <code>end</code> are negative or greater than
   *		     <code>length()</code>, or <code>start</code> is
   *		     greater than <code>end</code>.
   */
  def substring(start: Int, end: Int): String = {
    if (start < 0)
      throw new StringIndexOutOfBoundsException(start)
    if (end > count)
      throw new StringIndexOutOfBoundsException(end)
    if (start > end)
      throw new StringIndexOutOfBoundsException(end - start)
    new String(array, start, end - start)
  }

  def subSequence(start: Int, end: Int): java.lang.CharSequence = substring(start, end)

  /* Appends the string representation of the <code>Any</code> argument.
   */
  def +=(x: Char): this.type = { append(x); this }

  def +(x: Char): this.type = { +=(x); this }


  /** <p>
   *    Appends the string representation of the <code>Any</code> 
   *    argument.
   *  </p>
   *  <p>
   *    The argument is converted to a string as if by the method 
   *    <code>String.valueOf</code>, and the characters of that 
   *    string are then appended to this sequence.
   *  </p>
   *
   *  @param  x   an <code>Any</code> object.
   *  @return     a reference to this object.
   */
  def append(x: Any): StringBuilder =
    append(String.valueOf(x))

  /** Appends the specified string to this character sequence.
   *
   *  @param  s   a string.
   *  @return     a reference to this object.
   */
  def append(s: String): StringBuilder = {
    val str = if (s == null) "null" else s
    val len = str.length
    ensureCapacity(count + len)
    str.getChars(0, len, array, count)
    count += len
    this
  }

  /** Appends the specified string builder to this sequence.
   *
   *  @param sb
   *  @return 
   */
  def append(sb: StringBuilder): StringBuilder =
    if (sb == null)
      append("null")
    else {
      val len = sb.length
      ensureCapacity(count + len)
      arraycopy(sb.toArray, 0, array, count, len)
      count += len
      this
    }

  /** <p>
   *    Appends the string representation of the <code>Char</code> sequence 
   *    argument to this sequence.
   *  </p>
   *  <p>
   *    The characters of the sequence argument are appended, in order,
   *    to the contents of this sequence. The length of this sequence
   *    increases by the length of the argument.
   *  </p>
   *
   *  @param  x  the characters to be appended.
   *  @return    a reference to this object.
   */
  def appendAll(x: Seq[Char]): StringBuilder =
    appendAll(x.toArray, 0, x.length)

  @deprecated("use appendAll instead. This method is deprecated because of the\n"+
              "possible confusion with `append(Any)'.")
  def append(x: Seq[Char]): StringBuilder =
    appendAll(x)
      
  /** <p>
   *    Appends the string representation of the <code>Char</code> array 
   *    argument to this sequence.
   *  </p>
   *  <p>
   *    The characters of the array argument are appended, in order, to 
   *    the contents of this sequence. The length of this sequence
   *    increases by the length of the argument.
   *  </p>
   *
   *  @param  x  the characters to be appended.
   *  @return    a reference to this object.
   */
  def appendAll(x: Array[Char]): StringBuilder =
    appendAll(x, 0, x.length)

  @deprecated("use appendAll instead. This method is deprecated because\n"+
              "of the possible confusion with `append(Any)'.")
  def append(x: Array[Char]): StringBuilder =
    appendAll(x)

  /** <p>
   *    Appends the string representation of a subarray of the
   *    <code>char</code> array argument to this sequence.
   *  </p>
   *  <p>
   *    Characters of the <code>Char</code> array <code>x</code>, starting at
   *    index <code>offset</code>, are appended, in order, to the contents
   *    of this sequence. The length of this sequence increases
   *    by the value of <code>len</code>.
   *  </p>
   *
   *  @param  x      the characters to be appended.
   *  @param  offset the index of the first <code>Char</code> to append.
   *  @param  len    the number of <code>Char</code>s to append.
   *  @return        a reference to this object.
   */
  def appendAll(x: Array[Char], offset: Int, len: Int): StringBuilder = {
    ensureCapacity(count + len)
    arraycopy(x, offset, array, count, len)
    count += len
    this
  }

  @deprecated("use appendAll instead. This method is deprecated because\n"+
              "of the possible confusion with `append(Any, Int, Int)'.")
  def append(x: Array[Char], offset: Int, len: Int): StringBuilder = 
    appendAll(x, offset, len)

  /** <p>
   *    Appends the string representation of the <code>Boolean</code> 
   *    argument to the sequence.
   *  </p>
   *  <p>
   *    The argument is converted to a string as if by the method 
   *    <code>String.valueOf</code>, and the characters of that 
   *   string are then appended to this sequence. 
   *  </p>
   *
   *   @param  x  a <code>Boolean</code>.
   *   @return    a reference to this object.
   */
  def append(x: Boolean): StringBuilder = append(String.valueOf(x))
  def append(x: Byte): StringBuilder = append(String.valueOf(x))

  def append(x: Char): StringBuilder = {
    ensureCapacity(count + 1)
    array(count) = x
    count += 1
    this
  }

  def append(x: Short): StringBuilder =
    append(String.valueOf(x))

  def append(x: Int): StringBuilder =
    append(String.valueOf(x))

  def append(x: Long): StringBuilder =
    append(String.valueOf(x))

  def append(x: Float): StringBuilder =
    append(String.valueOf(x))

  def append(x: Double): StringBuilder = 
    append(String.valueOf(x))

  /** Removes the characters in a substring of this sequence.
   *  The substring begins at the specified <code>start</code> and extends to
   *  the character at index <code>end - 1</code> or to the end of the
   *  sequence if no such character exists. If
   *  <code>start</code> is equal to <code>end</code>, no changes are made.
   *
   *  @param  start  The beginning index, inclusive.
   *  @param  end    The ending index, exclusive.
   *  @return        This object.
   *  @throws StringIndexOutOfBoundsException  if <code>start</code>
   *                 is negative, greater than <code>length()</code>, or
   *		     greater than <code>end</code>.
   */
  def delete(start: Int, end: Int): StringBuilder = {
    if (start < 0 || start > end)
      throw new StringIndexOutOfBoundsException(start)
    val end0 = if (end > count) count else end
    val len = end0 - start
    if (len > 0) {
      arraycopy(array, start + len, array, start, count - end0)
      count -= len
    }
    this
  }

  /** Replaces the characters in a substring of this sequence
   *  with characters in the specified <code>String</code>. The substring
   *  begins at the specified <code>start</code> and extends to the character
   *  at index <code>end - 1</code> or to the end of the sequence if no such
   *  character exists. First the characters in the substring are removed and
   *  then the specified <code>String</code> is inserted at <code>start</code>.
   * 
   *  @param  start  The beginning index, inclusive.
   *  @param  end    The ending index, exclusive.
   *  @param  str    String that will replace previous contents.
   *  @return        This object.
   *  @throws StringIndexOutOfBoundsException  if <code>start</code>
   *                 is negative, greater than <code>length()</code>, or
   *		     greater than <code>end</code>.
   */
  def replace(start: Int, end: Int, str: String) {
    if (start < 0 || start > count || start > end)
      throw new StringIndexOutOfBoundsException(start)

    val end0 = if (end > count) count else end
    val len = str.length()
    val newCount = count + len - (end0 - start)
    ensureCapacity(newCount)

    arraycopy(array, end, array, start + len, count - end)
    str.getChars(0, len, array, start)  
    count = newCount
    this
  }

  /** Inserts the string representation of a subarray of the <code>str</code>
   *  array argument into this sequence. The subarray begins at the specified
   *  <code>offset</code> and extends <code>len</code> <code>char</code>s.
   *  The characters of the subarray are inserted into this sequence at
   *  the position indicated by <code>index</code>. The length of this
   *  sequence increases by <code>len</code> <code>Char</code>s.
   *
   * @param  index   position at which to insert subarray.
   * @param  str     a <code>Char</code> array.
   * @param  offset  the index of the first <code>char</code> in subarray to
   *                 be inserted.
   * @param  len     the number of <code>Char</code>s in the subarray to
   *                 be inserted.
   * @return         This object
   * @throws StringIndexOutOfBoundsException  if <code>index</code>
   *                 is negative or greater than <code>length()</code>, or
   *                 <code>offset</code> or <code>len</code> are negative, or
   *                 <code>(offset+len)</code> is greater than
   *                 <code>str.length</code>.
   */
  def insertAll(index: Int, str: Array[Char], offset: Int, len: Int): StringBuilder = {
    if (index < 0 || index > count)
      throw new StringIndexOutOfBoundsException(index)
    if (offset < 0 || len < 0 || offset > str.length - len)
      throw new StringIndexOutOfBoundsException(
                "offset " + offset + ", len " + len +
                ", str.length " + str.length)
    ensureCapacity(count + len)
    arraycopy(array, index, array, index + len, count - index)
    arraycopy(str, offset, array, index, len)
    count += len
    this
  }

  @deprecated("use insertAll instead. This method is deprecated because of the\n"+
              "possible confusion with `insert(Int, Any, Int, Int)'.")
  def insert(index: Int, str: Array[Char], offset: Int, len: Int): StringBuilder = 
    insertAll(index, str, offset, len)

  /** <p>
   *    Inserts the string representation of the <code>Any</code> 
   *    argument into this character sequence.
   *  </p>
   *  <p>
   *    The second argument is converted to a string as if by the method 
   *    <code>String.valueOf</code>, and the characters of that 
   *    string are then inserted into this sequence at the indicated 
   *    offset. 
   *  </p>
   *  <p>
   *    The offset argument must be greater than or equal to 
   *    <code>0</code>, and less than or equal to the length of this 
   *    sequence.
   *  </p>
   *
   *  @param  offset  the offset.
   *  @param  x       an <code>Any</code> value.
   *  @return         a reference to this object.
   *  @throws StringIndexOutOfBoundsException  if the offset is invalid.
   */
  def insert(at: Int, x: Any): StringBuilder =
    insert(at, String.valueOf(x))
  
  /** Inserts the string into this character sequence.
   *
   *  @param  at  the offset position.
   *  @param  x   a string.
   *  @return     a reference to this object.
   *  @throws StringIndexOutOfBoundsException  if the offset is invalid.
   */
  def insert(at: Int, x: String): StringBuilder = {
    if (at < 0 || at > count)
      throw new StringIndexOutOfBoundsException(at)
    val str = if (x == null) "null" else x
    val len = str.length
    ensureCapacity(count + len)
    arraycopy(array, at, array, at + len, count - at)
    str.getChars(0, len, array, at)
    count += len
    this
  }

  /** Inserts the string representation of the <code>Char</code> sequence 
   *  argument into this sequence.
   *
   *  @param  at  the offset position.
   *  @param  x   a character sequence.
   *  @return     a reference to this object.
   *  @throws StringIndexOutOfBoundsException  if the offset is invalid.
   */
  def insertAll(at: Int, x: Seq[Char]): StringBuilder =
    insertAll(at, x.toArray)

  @deprecated("use insertAll instead. This method is deprecated because of\n"+
              "the possible confusion with `insert(Int, Any)'.")
  def insert(at: Int, x: Seq[Char]): StringBuilder =
    insertAll(at, x)

  /** Inserts the string representation of the <code>Char</code> array 
   *  argument into this sequence.
   *
   *  @param  at  the offset position.
   *  @param  x   a character array.
   *  @return     a reference to this object.
   *  @throws StringIndexOutOfBoundsException  if the offset is invalid.
   */
  def insertAll(at: Int, x: Array[Char]): StringBuilder = {
    if (at < 0 || at > count)
      throw new StringIndexOutOfBoundsException(at)
    val len = x.length
    ensureCapacity(count + len)
    arraycopy(array, at, array, at + len, count - at)
    arraycopy(x, 0, array, at, len)
    count += len
    this
  }

  @deprecated("use insertAll instead. This method is deprecated because of\n"+
              "the possible confusion with `insert(Int, Any)'.")
  def insert(at: Int, x: Array[Char]): StringBuilder = 
    insertAll(at, x)

  /** <p>
   *    Inserts the string representation of the <code>Boolean</code> argument
   *    into this sequence.
   *  </p>
   *  <p>
   *    The offset argument must be greater than or equal to 0, and less than
   *    or equal to the length of this sequence.
   *  </p>
   *
   *  @param  at  the offset position.
   *  @param  x   a <code>Boolean</code> value.
   *  @return     a reference to this object.
   */
  def insert(at: Int, x: Boolean): StringBuilder =
    insert(at, String.valueOf(x))

  /** <p>
   *    Inserts the string representation of the <code>Byte</code> argument
   *    into this sequence.
   *  </p>
   *  <p>
   *    The offset argument must be greater than or equal to 0, and less than
   *    or equal to the length of this sequence.
   *  </p>
   *
   *  @param  at  the offset position.
   *  @param  x   a <code>Byte</code> value.
   *  @return     a reference to this object.
   */
  def insert(at: Int, x: Byte): StringBuilder =
    insert(at, String.valueOf(x))

  /** <p>
   *    Inserts the string representation of the <code>Char</code> argument
   *    into this sequence.
   *  </p>
   *  <p>
   *    The offset argument must be greater than or equal to 0, and less than
   *    or equal to the length of this sequence.
   *  </p>
   *
   *  @param  at  the offset position.
   *  @param  x   a <code>Char</code> value.
   *  @return     a reference to this object.
   */
  def insert(at: Int, x: Char): StringBuilder = {
    if (at < 0 || at > count)
      throw new StringIndexOutOfBoundsException(at)
    ensureCapacity(count + 1)
    arraycopy(array, at, array, at + 1, count - at)
    array(at) = x
    count += 1
    this
  }

  /** <p>
   *    Inserts the string representation of the <code>Short</code> argument
   *    into this sequence.
   *  </p>
   *  <p>
   *    The offset argument must be greater than or equal to 0, and less than
   *    or equal to the length of this sequence.
   *  </p>
   *
   *  @param  at  the offset position.
   *  @param  x   a <code>Short</code> value.
   *  @return     a reference to this object.
   */
  def insert(at: Int, x: Short): StringBuilder =
    insert(at, String.valueOf(x))

  /** <p>
   *    Inserts the string representation of the <code>Int</code> argument
   *    into this sequence.
   *  </p>
   *  <p>
   *    The offset argument must be greater than or equal to 0, and less than
   *    or equal to the length of this sequence.
   *  </p>
   *
   *  @param  at  the offset position.
   *  @param  x   a <code>Int</code> value.
   *  @return     a reference to this object.
   */
  def insert(at: Int, x: Int): StringBuilder =
    insert(at, String.valueOf(x))

  /** <p>
   *    Inserts the string representation of the <code>Long</code> argument
   *    into this sequence.
   *  </p>
   *  <p>
   *    The offset argument must be greater than or equal to 0, and less than
   *    or equal to the length of this sequence.
   *  </p>
   *
   *  @param  at  the offset position.
   *  @param  x   a <code>Long</code> value.
   *  @return     a reference to this object.
   */
  def insert(at: Int, x: Long): StringBuilder =
    insert(at, String.valueOf(x))

  /** <p>
   *    Inserts the string representation of the <code>Float</code> argument
   *    into this sequence.
   *  </p>
   *  <p>
   *    The offset argument must be greater than or equal to 0, and less than
   *    or equal to the length of this sequence.
   *  </p>
   *
   *  @param  at  the offset position.
   *  @param  x   a <code>Float</code> value.
   *  @return     a reference to this object.
   */
  def insert(at: Int, x: Float): StringBuilder =
    insert(at, String.valueOf(x))

  /** <p>
   *    Inserts the string representation of the <code>Double</code> argument
   *    into this sequence.
   *  </p>
   *  <p>
   *    The offset argument must be greater than or equal to 0, and less than
   *    or equal to the length of this sequence.
   *  </p>
   *
   *  @param  at  the offset position.
   *  @param  x   a <code>Double</code> value.
   *  @return     a reference to this object.
   */
  def insert(at: Int, x: Double): StringBuilder =
    insert(at, String.valueOf(x))

  /** <p>
   *    Returns the index within this string of the first occurrence of the
   *    specified substring. The integer returned is the smallest value 
   *    <i>k</i> such that:
   *  </p>
   *  <blockquote><pre>
   *  this.toString().startsWith(str, <i>k</i>)</pre>
   *  </blockquote>
   *  <p>
   *    is <code>true</code>.
   *  </p>
   *
   *  @param  str  any string.
   *  @return      if the string argument occurs as a substring within this
   *               object, then the index of the first character of the first
   *               such substring is returned; if it does not occur as a
   *               substring, <code>-1</code> is returned.
   *  @throws NullPointerException if <code>str</code> is <code>null</code>.
   */
  def indexOf(str: String): Int = indexOfSeq(str.toArray)

  /** <p>
   *    Returns the index within this string of the first occurrence of the
   *    specified substring, starting at the specified index. The integer
   *    returned is the smallest value <code>k</code> for which:
   *  </p><pre>
   *    k >= Math.min(fromIndex, str.length()) &&
   *                   this.toString().startsWith(str, k)</pre>
   *  <p>
   *    If no such value of <code>k</code> exists, then <code>-1</code>
   *    is returned.
   *  </p>
   *
   *  @param str        the substring for which to search.
   *  @param fromIndex  the index from which to start the search.
   *  @return           the index within this string of the first occurrence
   *                    of the specified substring, starting at the specified index.
   */
  def indexOf(str: String, fromIndex: Int): Int = indexOfSeq(str.toArray, fromIndex)

  /** <p>
   *    Returns the index within this string of the rightmost occurrence
   *    of the specified substring.  The rightmost empty string "" is
   *    considered to occur at the index value <code>this.length()</code>. 
   *    The returned index is the largest value <i>k</i> such that 
   *  </p>
   *  <blockquote><pre>
   *  this.toString().startsWith(str, k)</pre>
   *  </blockquote>
   *  <p>
   *    is true.
   *  </p>
   *
   * @param  str  the substring to search for.
   * @return      if the string argument occurs one or more times as a substring
   *              within this object, then the index of the first character of
   *              the last such substring is returned. If it does not occur as
   *              a substring, <code>-1</code> is returned.
   * @throws NullPointerException  if <code>str</code> is <code>null</code>.
   */
  def lastIndexOf(str: String): Int = lastIndexOfSeq(str.toArray, count)

  /** <p>
   *    Returns the index within this string of the last occurrence of the
   *    specified substring. The integer returned is the largest value
   *    <code>k</code> such that:
   *  </p><pre>val
   *    k <= Math.min(fromIndex, str.length()) &&
   *                   this.toString().startsWith(str, k)</pre>
   *  <p>
   *    If no such value of <code>k</code> exists, then <code>-1</code>
   *    is returned.
   *  </p>
   *
   *  @param  str        the substring to search for.
   *  @param  fromIndex  the index to start the search from.
   *  @return            the index within this sequence of the last occurrence
   *                     of the specified substring.
   */
  def lastIndexOf(str: String, fromIndex: Int): Int = lastIndexOfSeq(str.toArray, fromIndex)

  /** <p>
   *    Causes this character sequence to be replaced by the reverse of the
   *    sequence. If there are any surrogate pairs included in the sequence,
   *    these are treated as single characters for the reverse operation.
   *    Thus, the order of the high-low surrogates is never reversed.
   *  </p>
   *  <p>
   *    Let <i>n</i> be the character length of this character sequence
   *    (not the length in <code>Char</code> values) just prior to
   *    execution of the <code>reverse</code> method. Then the
   *    character at index <i>k</i> in the new character sequence is
   *    equal to the character at index <i>n-k-1</i> in the old
   *    character sequence.
   *  </p>
   *
   *  @return  a reference to this object.
   */
  override def reverse(): StringBuilder = {
    var hasSurrogate = false
    val n = count - 1
    var j = (n-1) >> 1
    while (j >= 0) {
      val temp = array(j)
      val temp2 = array(n - j)
      if (!hasSurrogate)
        hasSurrogate =
          (temp >= Character.MIN_HIGH_SURROGATE && temp <= Character.MAX_LOW_SURROGATE) ||
       	  (temp2 >= Character.MIN_HIGH_SURROGATE && temp2 <= Character.MAX_LOW_SURROGATE)
      array(j) = temp2
      array(n - j) = temp
      j -= 1
    }
    if (hasSurrogate) {
      // Reverse back all valid surrogate pairs
      var i = 0
      while (i < count - 1) {
        val c2 = array(i)
	if (Character.isLowSurrogate(c2)) {
          val c1 = array(i + 1)
          if (Character.isHighSurrogate(c1)) {
            array(i) = c1; i += 1
            array(i) = c2
          }
        }
        i += 1
      }
    }
    this
  }

  /** Returns a string representing the data in this sequence.
   *  A new <code>String</code> object is allocated and initialized to 
   *  contain the character sequence currently represented by this 
   *  object. This <code>String</code> is then returned. Subsequent 
   *  changes to this sequence do not affect the contents of the 
   *  <code>String</code>.
   *
   *  @return  a string representation of this sequence of characters.
   */
  override def toString: String = new String(array, 0, count)
  
  def result(): String = toString
}


object StringBuilder {

  type Array[T] = scala.Array[T] // !!!

  // method <code>java.util.Arrays.copyOf</code> exists since 1.6
  private def copyOf(src: Array[Char], newLength: Int): Array[Char] = {
    val dest = new Array[Char](newLength)
    arraycopy(src, 0, dest, 0, Math.min(src.length, newLength))
    dest
  }
}