package it.micegroup.voila2.cartridge.library.formatters;

/**
* Copyright 2008 hybrid labs 
* 
* 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.
*/

/**
 * This implementation of the JDK CharSequence hides the details of the
 * realization of the underlying implementation, while tryping to 
 * minimize conversions between strings, stringbuffers and charsequences.
 * Moreover this class is used as part of the Beautifier interface definition. 
 * 
 * @author Karsten Klein, hybrid labs
 *
 */
public final class CharacterSequence implements CharSequence, Comparable<CharacterSequence> {

    private String string;
    private CharSequence charSequence;
    private StringBuffer stringBuffer;
    
    /**
     * Constructs a CharacterSequence object based on the provided StringBuffer.
     * 
     * @param stringBuffer The StringBuffer the Character Sequence is based on.
     */
    public CharacterSequence(StringBuffer stringBuffer) {
        set(stringBuffer);
    }

    /**
     * Constructs a CharacterSequence object based on the provided String.
     * 
     * @param string The String the Character Sequence is based on.
     */
    public CharacterSequence(String string) {
        set(string);
    }

    /**
     * Constructs a CharacterSequence object based on the provided CharSequence.
     * 
     * @param charSequence The CcharSequence the Character Sequence is based on.
     */
    public CharacterSequence(CharSequence charSequence) {
        set(charSequence);
    }

    /**
     * Returns the content of the CharacterSequence as String.
     * 
     * @return The String representation.
     */
    public String getString() {
        if (string == null) {
            if (charSequence != null) {
                string = charSequence.toString();
            } else if (stringBuffer != null) {
                string = stringBuffer.toString();
            }
        }        
        return string;
    }

    /**
     * Returns the content of the CharacterSequence as StringBuffer.
     * 
     * @return The StringBuffer representation.
     */
    public StringBuffer getStringBuffer() {
        if (stringBuffer == null) {
            stringBuffer = new StringBuffer(getString());
        }
        return stringBuffer;
    }

    public CharSequence getCharSequence() {
        return charSequence;
    }
    
    public void set(StringBuffer stringBuffer) {
        this.charSequence = stringBuffer;
        this.stringBuffer = stringBuffer;
        this.string = null;
    }

    public void set(CharacterSequence characterSequence) {
        this.charSequence = characterSequence.charSequence;
        this.stringBuffer = characterSequence.stringBuffer;
        this.string = characterSequence.string;
    }

    public void set(CharSequence charSequence) {
        this.charSequence = charSequence;
        this.stringBuffer = charSequence instanceof StringBuffer ? (StringBuffer) charSequence : null;;
        this.string = charSequence instanceof String ? (String) charSequence : null; 
    }
    
    public void set(String string) {
        this.stringBuffer = null;
        this.charSequence = string;
        this.string = string;
    }

    /**
     * {@inheritDoc}
     */
    public String toString() {
        return getString();
    }

    /**
     * {@inheritDoc}
     */
    public int length() {
        return getCharSequence().length();
    }

    /**
     * {@inheritDoc}
     */
    public char charAt(int index) {
        return charSequence.charAt(index);
    }

    /**
     * {@inheritDoc}
     */
    public CharSequence subSequence(int start, int end) {
        return charSequence.subSequence(start, end);
    }

    public int lastIndexOf(String string) {
        if (stringBuffer != null) {
            return stringBuffer.lastIndexOf(string);
        }
        return getString().lastIndexOf(string);
    }

    public int lastIndexOf(char c) {
        if (stringBuffer != null) {
            return stringBuffer.lastIndexOf(String.valueOf(c));
        }
        return getString().lastIndexOf(c);
    }

    public boolean endsWith(char c) {
        return charAt(length() - 1) == c;
    }

    public boolean endsWith(String suffix) {
        return getString().endsWith(suffix);
    }

    public CharSequence substring(int start) {
        return subSequence(start, length());
    }

    public boolean startsWith(String suffix) {
        return getString().startsWith(suffix);
    }

    public boolean startsWith(CharacterSequence sequence) {
        return getString().startsWith(sequence.getString());
    }
    
    public int compareTo(CharacterSequence cs) {
        return getString().compareTo(cs.getString());
    }
    
    public int hashCode() {
        return getCharSequence().hashCode();
    }
    
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj instanceof String) {
            return getString().equals(obj);
        }
        if (obj instanceof StringBuffer) {
            return getStringBuffer().equals(obj);
        }
        CharacterSequence cs = (CharacterSequence) obj;
        return getStringBuffer().equals(cs.getStringBuffer());
    }

    public CharacterSequence subCharacterSequence(int start, int end) {
        return new CharacterSequence(getString().substring(start, end));
    }

    public void append(CharacterSequence imports) {
        append(imports.getCharSequence());
    }

    public void append(String string) {
        getStringBuffer().append(string);
        charSequence = stringBuffer;
        string = null;
    }

    public void append(CharSequence cs) {
        getStringBuffer().append(cs);
        charSequence = stringBuffer;
        string = null;
    }

    public void append(char c) {
        getStringBuffer().append(c);
        charSequence = stringBuffer;
        string = null;
    }
    
}
