/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 *
 * $Header:$
 */
package org.apache.beehive.netui.util.internal;

import java.io.Serializable;


/**
 * Unsynchronized alternative to StringBuffer.
 */
public final class InternalStringBuilder
        implements Serializable
{
    private char _buffer[];
    private int _length = 0;
    private boolean _shared;

    static final long serialVersionUID = 1;

    public InternalStringBuilder()
    {
        this( 16 );
    }

    public InternalStringBuilder( int length )
    {
        _buffer = new char[length];
        _shared = false;
    }

    public InternalStringBuilder( String str )
    {
        this( str.length() + 16 );
        append( str );
    }

    public int length()
    {
        return _length;
    }

    private final void copyWhenShared()
    {
        if ( _shared )
        {
            char newValue[] = new char[_buffer.length];
            System.arraycopy( _buffer, 0, newValue, 0, _length );
            _buffer = newValue;
            _shared = false;
        }
    }

    public void ensureCapacity( int minCapacity )
    {
        int maxCapacity = _buffer.length;

        if ( minCapacity > maxCapacity )
        {
            int newCapacity = ( maxCapacity + 1 ) * 2;
            if ( minCapacity > newCapacity ) newCapacity = minCapacity;
            char newValue[] = new char[newCapacity];
            System.arraycopy( _buffer, 0, newValue, 0, _length );
            _buffer = newValue;
            _shared = false;
        }
    }

    public void setLength( int length )
    {
        if ( length < 0 ) throw new StringIndexOutOfBoundsException( length );
        ensureCapacity( length );

        if ( _length < length )
        {
            copyWhenShared();
            while ( _length < length )
            {
                _buffer[_length++] = '\0';
            }
        }
        _length = length;
    }

    public char charAt( int index )
    {
        if ( index < 0 || index >= _length ) throw new StringIndexOutOfBoundsException( index );
        return _buffer[index];
    }

    public InternalStringBuilder append( Object obj )
    {
        return append( String.valueOf( obj ) );
    }

    public InternalStringBuilder append( String str )
    {
        if ( str == null ) str = String.valueOf( str );
        int len = str.length();
        ensureCapacity( _length + len );
        copyWhenShared();
        str.getChars( 0, len, _buffer, _length );
        _length += len;
        return this;
    }

    public InternalStringBuilder append( char c )
    {
        ensureCapacity( _length + 1 );
        copyWhenShared();
        _buffer[_length++] = c;
        return this;
    }

    public InternalStringBuilder append( int i )
    {
        return append( String.valueOf( i ) );
    }

    public String toString()
    {
        _shared = true;
        return new String( _buffer, 0, _length );
    }

    public InternalStringBuilder deleteCharAt( int index )
    {
        if ( index < 0 || index >= _length ) throw new StringIndexOutOfBoundsException( index );
        System.arraycopy( _buffer, index + 1, _buffer, index, _length - index - 1 );
        _length--;
        return this;
    }
}

@@ -891,16 +891,52 @@
 izable;%0A
+import java.lang.ref.SoftReference;%0A
 %0A%0A/**%0A *
@@ -1119,37 +1119,8 @@
 = 0;
-%0A    private boolean _shared;
 %0A%0A  
@@ -1323,33 +1323,8 @@
 h%5D;%0A
-        _shared = false;%0A
     
@@ -1514,610 +1514,772 @@
    p
-rivate final void copyWhenShared()%0A    %7B%0A        if ( _shared )%0A        %7B%0A            char newValue%5B%5D = new char%5B_buffer.length%5D;%0A            System.arraycopy( _buffer, 0, newValue, 0, _length );%0A            _buffer = newValue;%0A            _shared = false;%0A        %7D%0A    %7D%0A%0A    public void ensureCapacity( int minCapacity )%0A    %7B%0A        int maxCapacity = _buffer.length;%0A%0A        if ( minCapacity %3E maxCapacity )%0A        %7B%0A            int newCapacity = ( maxCapacity + 1 ) * 2;%0A            if ( minCapacity %3E newCapacity ) newCapacity = minCapacity;%0A            char newValue%5B%5D = new char%5BnewCapacity%5D
+ublic void ensureCapacity( int minCapacity )%0A    %7B%0A        int maxCapacity = _buffer.length;%0A%0A        if ( minCapacity %3E maxCapacity )%0A        %7B%0A            int newCapacity = ( maxCapacity + 1 ) * 2;%0A            if ( newCapacity %3C 0 ) newCapacity = Integer.MAX_VALUE;%0A            else if ( minCapacity %3E newCapacity ) newCapacity = minCapacity;%0A            // allow _buffer to be GCd if needed, rather than throw OOM%0A            final SoftReference%3Cchar%5B%5D%3E softBuffer = new SoftReference%3Cchar%5B%5D%3E(_buffer);%0A            _buffer = null;%0A            final char newValue%5B%5D = new char%5BnewCapacity%5D;%0A            _buffer = softBuffer.get();%0A            if (_buffer == null)%0A                throw new OutOfMemoryError(%22could not increase capacity in InternalStringBuilder%22)
 ;%0A  
@@ -2378,37 +2378,8 @@
 ue;%0A
-            _shared = false;%0A
     
@@ -2597,38 +2597,8 @@
   %7B%0A
-            copyWhenShared();%0A
     
@@ -3231,34 +3231,8 @@
  );%0A
-        copyWhenShared();%0A
     
@@ -3428,34 +3428,8 @@
  );%0A
-        copyWhenShared();%0A
     
@@ -3631,32 +3631,8 @@
   %7B%0A
-        _shared = true;%0A
     

Update InternalStringBuilder.java to remove now useless _shared logic, and handle OOM on array copy gracefully