/*
 * Copyright 2013 Yuichiro Moriguchi
 *
 * 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 net.morilib.unix.misc;

/**
 * 32ビット文字列のビルダークラスです。
 *
 *
 * @author MORIGUCHI, Yuichiro 2013/03
 */
public final class WideStringBuilder implements WideCharSequence {

	//
	private static final int INIT_CAPACITY = 16;

	//
	private int[] buf;
	private int len;

	/**
	 * ビルダーを生成します。
	 * 
	 * @param capacity 初期容量
	 */
	public WideStringBuilder(int capacity) {
		buf = new int[capacity];
		len = 0;
	}

	/**
	 * ビルダーを生成します。
	 */
	public WideStringBuilder() {
		this(INIT_CAPACITY);
	}

	private void chkind(int index) {
		if(index < 0 || index >= len) {
			throw new StringIndexOutOfBoundsException(index);
		}
	}

	public int charAt(int index) {
		chkind(index);
		return buf[index];
	}

	public int length() {
		return len;
	}

	private void chkrange(int start, int end) {
		if(start < 0 || start >= len) {
			throw new IndexOutOfBoundsException(start + "");
		} else if(end < 0 || end > len) {
			throw new IndexOutOfBoundsException(end + "");
		} else if(end < start) {
			throw new IndexOutOfBoundsException(end + "");
		}
	}

	public WideCharSequence subSequence(int start, int end) {
		chkrange(start, end);
		return new WideString(buf, start, end - start);
	}

	public void ensureCapacity(int l) {
		int[] b2;

		if((len + l) >= buf.length) {
			b2  = buf;
			buf = new int[b2.length * 2];
			System.arraycopy(b2, 0, buf, 0, len);
		}
	}

	/**
	 * 文字を追加します。
	 * 
	 * @param c 文字
	 * @return このインスタンス
	 */
	public WideStringBuilder append(int c) {
		ensureCapacity(1);
		buf[len++] = c;
		return this;
	}

	/**
	 * 文字を追加します。
	 * 
	 * @param c 文字
	 * @return このインスタンス
	 */
	public WideStringBuilder append(char c) {
		return append((int)c);
	}

	/**
	 * 文字列を追加します。
	 * 
	 * @param s 文字列
	 * @return このインスタンス
	 */
	public WideStringBuilder append(WideString s) {
		ensureCapacity(s.length());
		System.arraycopy(s.wchars, 0, buf, len, s.length());
		len += s.length();
		return this;
	}

	/**
	 * 文字列を追加します。
	 * 
	 * @param s 文字列
	 * @return このインスタンス
	 */
	public WideStringBuilder append(WideStringBuilder s) {
		ensureCapacity(s.length());
		System.arraycopy(s.buf, 0, buf, len, s.len);
		len += s.len;
		return this;
	}

	/**
	 * 文字列を追加します。
	 * 
	 * @param s 文字列
	 * @return このインスタンス
	 */
	public WideStringBuilder append(String s) {
		int i = 0, c;

		for(; i < s.length(); i += c > 0xffff ? 2 : 1) {
			append(c = s.codePointAt(i));
		}
		return this;
	}

	/**
	 * 文字を削除します。
	 * 
	 * @param begin  0からの始点
	 * @param end    終点(終点は含みません)
	 * @return このインスタンス
	 */
	public WideStringBuilder delete(int start, int end) {
		chkrange(start, end);
		System.arraycopy(buf, end, buf, start, len - end);
		len -= end - start;
		return this;
	}

	/**
	 * 1文字を削除します。
	 * 
	 * @param index 削除する文字の場所
	 * @return このインスタンス
	 */
	public WideStringBuilder deleteCharAt(int index) {
		chkind(index);
		delete(index, index + 1);
		return this;
	}

	/**
	 * 32ビット文字列を取り出します。
	 * 
	 * @return 32ビット文字列
	 */
	public WideString toWideString() {
		return new WideString(buf, 0, len);
	}

	/**
	 * Java標準文字列を取り出します。
	 * 
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		return new String(buf, 0, len);
	}

}
