/*
 * Copyright 2008 Google Inc.
 * 
 * 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.google.gwt.core.client.impl;

/**
 * <p>
 * An implementation for a {@link StringBuilder} or {@link StringBuffer}. This
 * class holds a default implementation based on an array of strings and the
 * JavaScript join function. Deferred bindings can substitute a subclass
 * optimized for a particular browser.
 * </p>
 * 
 * <p>
 * The main implementations are static classes nested within this one. All of
 * the implementations have been carefully tweaked to get the most inlining
 * possible, so be sure to check with
 * {@link com.google.gwt.emultest.java.lang.StringBuilderBenchmark StringBuilderBenchmark}
 * whenever these classes are modified.
 * </p>
 */
public class StringBuilderImpl {

  /**
   * A {@link StringBuilderImpl} that uses an array and an explicit length for
   * appending strings. Note that the length of the array is stored as a
   * property of the underlying JavaScriptObject. Making it a field of
   * {@link ImplArray} causes difficulty with inlining.
   */

  public static class ImplArray extends StringBuilderImpl {
    private  static native void setArrayLength(String[] array, int length) /*-{
      array.explicitLength = length;
    }-*/;

    private String[] array = new String[0];

    public ImplArray() {
      setArrayLength(array, 0);
    }

    @Override
    public native void append(String s) /*-{
      var a = this.@com.google.gwt.core.client.impl.StringBuilderImpl.ImplArray::array;
      a[a.explicitLength++] = s==null ? "null" : s;
    }-*/;

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

    @Override
    public void replace(int start, int end, String toInsert) {
      String s = toString();
      array = new String[] {s.substring(0, start), toInsert, s.substring(end)};
    }

    @Override
    public native String toString() /*-{
      this.@com.google.gwt.core.client.impl.StringBuilderImpl.ImplArray::array = 
        [ this.@com.google.gwt.core.client.impl.StringBuilderImpl.ImplArray::array.join('') ];
      this.@com.google.gwt.core.client.impl.StringBuilderImpl.ImplArray::array.explicitLength = 1;
      return this.@com.google.gwt.core.client.impl.StringBuilderImpl.ImplArray::array[0];
    }-*/;
  }

  /**
   * A {@link StringBuilderImpl} that uses <code>push</code> for appending
   * strings.
   */
  public static class ImplPush extends StringBuilderImpl {
    @SuppressWarnings("unused")
    private String[] array = new String[0];

    @Override
    public native void append(String s) /*-{
      this.@com.google.gwt.core.client.impl.StringBuilderImpl.ImplPush::array.push(s == null ? "null" : s);
    }-*/;

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

    @Override
    public void replace(int start, int end, String toInsert) {
      String s = toString();
      array = new String[] {s.substring(0, start), toInsert, s.substring(end)};
    }

    @Override
    public native String toString() /*-{
      this.@com.google.gwt.core.client.impl.StringBuilderImpl.ImplPush::array = 
        [ this.@com.google.gwt.core.client.impl.StringBuilderImpl.ImplPush::array.join('') ];
      return this.@com.google.gwt.core.client.impl.StringBuilderImpl.ImplPush::array[0];
    }-*/;
  }

  /**
   * A {@link StringBuilderImpl} that uses += for appending strings.
   */
  public static class ImplStringAppend extends StringBuilderImpl {
    private String string = "";

    @Override
    public void append(String s) {
      string += s;
    }

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

    @Override
    public void replace(int start, int end, String toInsert) {
      string = string.substring(0, start) + toInsert + string.substring(end);
    }
    
    @Override
    public String toString() {
      return string;
    }
  }

  private static native String join(String[] stringArray) /*-{
    return stringArray.join('');
  }-*/;

  private static native String setLength(String[] stringArray, int length) /*-{
    stringArray.length = length;
  }-*/;

  private int arrayLen = 0;
  private String[] stringArray = new String[0];
  private int stringLength = 0;

  public void append(String toAppend) {
    // Coerce to "null" if null.
    if (toAppend == null) {
      toAppend = "null";
    }
    int appendLength = toAppend.length();
    if (appendLength > 0) {
      stringArray[arrayLen++] = toAppend;
      stringLength += appendLength;
      /*
       * If we hit 1k elements, let's do a join to reduce the array size. This
       * number was arrived at experimentally through benchmarking.
       */
      if (arrayLen > 1024) {
        toString();
        // Preallocate the next 1024 (faster on FF).
        setLength(stringArray, 1024);
      }
    }
  }

  public int length() {
    return stringLength;
  }

  public void replace(int start, int end, String toInsert) {
    // Get the joined string.
    String s = toString();

    // Build a new buffer in pieces (will throw exceptions).
    stringArray = new String[] {
        s.substring(0, start), toInsert, s.substring(end)};
    arrayLen = 3;

    // Calculate the new string length.
    stringLength += toInsert.length() - (end - start);
  }

  @Override
  public String toString() {
    /*
     * Normalize the array to exactly one element (even if it's completely
     * empty), so we can unconditionally grab the first element.
     */
    if (arrayLen != 1) {
      setLength(stringArray, arrayLen);
      String s = join(stringArray);
      // Create a new array to allow everything to get GC'd.
      stringArray = new String[] {s};
      arrayLen = 1;
    }
    return stringArray[0];
  }
}
