/*
 * Copyright 2006 Takahiro Nakamura.
 *
 * 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 woolpack.crud;

/**
 * 挿入位置をマークすることができる{@link StringBuilder}のラッパー。
 * 適用しているパターン：Proxy。
 * @author nakamura
 *
 */
public class MarkableStringBuilder {
	
	private final StringBuilder sb;
	private final int[] idx;
	private final boolean[] init;
	
	/**
	 * コンストラクタ。
	 * @param sb 委譲先。
	 * @param count マーカの数。
	 * @throws NullPointerException sb が null の場合。
	 * @throws RuntimeException count が負の場合。
	 */
	public MarkableStringBuilder(final StringBuilder sb, final int count) {
		this.sb = sb;
		this.idx = new int[count];
		this.init = new boolean[count];
	}
	
	/**
	 * 末尾に追加する。
	 * @param s 追加対象。
	 */
	public void append(final String s) {
		sb.append(s);
	}
	
	/**
	 * 末尾に追加する。
	 * @param c 追加対象。
	 */
	public void append(final char c) {
		sb.append(c);
	}
	
	/**
	 * 末尾のインデックスをマークする。
	 * マーカ番号とマーク位置の順序性を強制しない。
	 * @param i マーカ番号。
	 */
	public void mark(final int i) {
		idx[i] = sb.length();
		init[i] = true;
	}
	
	/**
	 * マーカの位置に挿入する。
	 * @param i マーカ番号。
	 * @param s 挿入対象。
	 */
	public void insert(final int i, final String s) {
		final int index = idx[i];
		sb.insert(index, s);
		final int l = s.length();
		for (int j = 0; j < idx.length; j++) {
			if (idx[j] >= index) {
				idx[j] += l;
			}
		}
	}
	
	/**
	 * 同一マーカの最初の呼出では first を挿入し、二回目以降の呼出では plural を挿入する。
	 * @param i マーカ番号。
	 * @param first 同一マーカの最初の呼出で挿入する値。
	 * @param plural 同一マーカの二回目以降の呼出で挿入する値。
	 */
	public final void insert(final int i, final String first, final String plural) {
		insert(i, init[i] ? first : plural);
		init[i] = false;
	}
	
	@Override
	public String toString() {
		return sb.toString();
	}
}
