/*
 * Copyright (c) 2009 The openGion Project.
 *
 * 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 org.opengion.fukurou.system;

import java.util.function.Function;

/**
 * 内部にStringBuilderを持った、文字列連結クラスです。
 *
 * 文字列連結時に、取り込む／取り込まないの判断を行う、boolean 付きの
 * appendIf メソッドや、null値を無視する append など、用意しています。
 *
 * @og.rev 6.4.4.1 (2016/03/18) 新規追加
 *
 * @og.group その他
 *
 * @version  6.0
 * @author	 Kazuhiko Hasegawa
 * @since    JDK8.0,
 */
public final class OgBuilder {
	private final StringBuilder buf = new StringBuilder( HybsConst.BUFFER_MIDDLE );

	/**
	 * デフォルトコンストラクター
	 *
	 * @og.rev 6.4.4.1 (2016/03/18) 新規追加
	 */
	public OgBuilder() {
		super();
	}

	/**
	 * 引数の可変長文字列を追加する appendです。
	 *
	 * 引数の可変長文字列の個々の文字列が null の場合は、追加しません。
	 *
	 * @og.rev 6.4.4.1 (2016/03/18) 新規追加
	 *
	 * @param arys	追加する可変長文字列
	 * @return	自分自身
	 * @og.rtnNotNull
	 */
	public OgBuilder append( final String... arys ) {
		if( arys != null ) {
			for( final String str : arys ) {
				if( str != null ) { buf.append( str ); }
			}
		}

		return this;
	}

	/**
	 * 引数の可変長文字列を追加し、最後に改行コードを追加する appendです。
	 *
	 * 引数の可変長文字列の個々の文字列が null の場合は、追加しません。
	 * 引数がnull値の場合は、改行コードのみ追加されます。
	 *
	 * @og.rev 6.4.4.1 (2016/03/18) 新規追加
	 *
	 * @param arys	追加する文字列可変長(nullは追加しません)
	 * @return	自分自身
	 * @see		#append( String... )
	 * @og.rtnNotNull
	 */
	public OgBuilder appendCR( final String... arys ) {
		append( arys );
		buf.append( HybsConst.CR );

		return this;
	}

	/**
	 * 引数の可変長文字列を追加する appendです。
	 *
	 * 引数の可変長文字列の個々の文字列の中に、一つでも null の場合は、
	 * すべて追加しません。
	 * 例えば、key="AAAA" のような文字列を構築したい場合、AAAA 部分が、nullの
	 * 場合は、key= の箇所も出しません。
	 *
	 * @og.rev 6.4.4.1 (2016/03/18) 新規追加
	 *
	 * @param arys	追加する可変長文字列
	 * @return	自分自身
	 * @og.rtnNotNull
	 */
	public OgBuilder appendNN( final String... arys ) {
		if( arys != null ) {
			final StringBuilder tmp = new StringBuilder();
			for( final String str : arys ) {
				if( str == null ) { return this; }		// 一つでも null があれば、すぐに抜ける。
				else { tmp.append( str ); }
			}
			buf.append( tmp );
		}
		return this;
	}

	/**
	 * 文字列を追加するかどうか判定するフラグ付きのappendメソッドです。
	 *
	 * 引数の可変長文字列の個々の文字列が null の場合は、追加しません。
	 *
	 * @og.rev 6.4.4.1 (2016/03/18) 新規追加
	 *
	 * @param flag	文字列を追加するかどうか判定するフラグ(trueの時のみ追加)
	 * @param arys	追加する可変長文字列
	 * @return	自分自身
	 * @og.rtnNotNull
	 */
	public OgBuilder appendIf( final boolean flag , final String... arys ) {
		if( flag && arys != null ) {
			for( final String str : arys ) {
				if( str != null ) { buf.append( str ); }
			}
		}

		return this;
	}

	/**
	 * 引数の可変長文字列を追加し、最後に改行コードを追加する appendです。
	 *
	 * 引数の可変長文字列の個々の文字列が null の場合は、追加しません。
	 * 引数がnull値の場合は、改行コードのみ追加されます。
	 *
	 * @og.rev 6.4.4.1 (2016/03/18) 新規追加
	 *
	 * @param flag	文字列を追加するかどうか判定するフラグ(trueの時のみ追加)
	 * @param arys	追加する可変長文字列
	 * @return	自分自身
	 * @see		#appendIf( boolean,String... )
	 * @og.rtnNotNull
	 */
	public OgBuilder appendIfCR( final boolean flag , final String... arys ) {
		appendIf( flag,arys );
		buf.append( HybsConst.CR );

		return this;
	}

	/**
	 * 関数を実行した結果を追加するかどうか判定するフラグ付きのappendメソッドです。
	 * 実行した結果が、null値の場合は、無視します。
	 * 引数が関数型インタフェースなので、遅延実行することが可能です。
	 *
	 * @og.rev 6.4.4.1 (2016/03/18) 新規追加
	 *
	 * @param flag	追加するかどうか判定するフラグ(trueの時のみ追加)
	 * @param key	関数の引数
	 * @param func	関数を実行した結果を追加する関数型(結果がnullの場合は追加しません)
	 * @return	自分自身
	 * @og.rtnNotNull
	 */
	public <T,R> OgBuilder appendIf( final boolean flag , final T key , final Function<? super T, ? extends R> func ) {
		if( flag && func != null ) {
			R obj = func.apply( key );
			if( obj != null ) { buf.append( obj ); }
		}
		return this;
	}

	/**
	 * 関数を実行した結果を追加するかどうか判定するフラグ付きのappendメソッドです。
	 * 実行した結果が、null値の場合は、無視します。
	 * 引数が関数型インタフェースなので、遅延実行することが可能です。
	 * 関数の結果は、文字列配列を返します。それを、内部でappendループします。
	 *
	 * @og.rev 6.4.4.1 (2016/03/18) 新規追加
	 *
	 * @param st	ループカウンタの初期値(この値を含む)
	 * @param ed	ループカウンタの終了値(この値を含まない)
	 * @param func	関数を実行した結果を追加する関数型(結果がnullの場合は追加しません)
	 * @return	自分自身
	 * @og.rtnNotNull
	 */
	public OgBuilder appendRoop( final int st , final int ed , final RoopFunction func ) {
		for( int i=st; i<ed; i++ ) {
			String[] arys = func.apply( i );
			if( arys != null ) {
				for( final String str : arys ) {
					if( str != null ) { buf.append( str ); }
				}
			}
		}
		return this;
	}

	/**
	 * 文字列を追加するかどうか判定するフラグ付きのappendメソッドです。
	 * trueの場合は、第一引数を、falseの場合は、第二引数を追加します。
	 * 第二引数は、可変長文字列です。
	 * ともに、文字列がnullの場合は、無視します。
	 *
	 * @og.rev 6.4.4.1 (2016/03/18) 新規追加
	 *
	 * @param flag	文字列を追加するかどうか判定するフラグ
	 * @param trueStr	flagがtrueの場合に追加する文字列(一つだけ)
	 * @param falseStr	flagがfalseの場合に追加する可変長文字列
	 * @return	自分自身
	 * @og.rtnNotNull
	 */
	public OgBuilder appendCase( final boolean flag , final String trueStr , final String... falseStr ) {
		if( flag ) {
			if( trueStr != null ) { buf.append( trueStr ); }
		}
		else {
			if( falseStr != null ) {
				for( final String str : falseStr ) {
					if( str != null ) { buf.append( str ); }
				}
			}
		}

		return this;
	}

	/**
	 * 内部のStringBuilderそのものを返します。
	 *
	 * StringBuilderを関数等に渡して追加処理する場合に、
	 * 内部のStringBuilderを渡して、処理させることが出来ます。
	 *
	 * @og.rev 6.4.4.1 (2016/03/18) 新規追加
	 *
	 * @return	内部のStringBuilder
	 * @og.rtnNotNull
	 */
	public StringBuilder getBuilder() {
		return buf;
	}

	/**
	 * 内部のStringBuilderをクリアします。
	 *
	 * 具体的には、StringBuilder#setLength(0) を実行します。
	 *
	 * @og.rev 6.4.4.1 (2016/03/18) 新規追加
	 */
	public void clear() {
		buf.setLength(0);
	}

	/**
	 * このシーケンス内のデータを表す文字列を返します。
	 *
	 * 新しいStringオブジェクトが割り当てられ、現在このオブジェクトで表されている
	 * 文字シーケンスを含むように初期化されます。
	 * その後、このStringが返されます。その後このシーケンスが変更されても、Stringの内容には影響ありません。
	 *
	 * @og.rev 6.4.4.1 (2016/03/18) 新規追加
	 *
	 * @return この文字シーケンスの文字列表現。
	 * @og.rtnNotNull
	 */
	@Override
	public String toString() {
		return buf.toString();
	}
}
