/*
 * 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.util;

import java.util.LinkedHashSet;
import java.util.Collection;											// 7.0.1.1 (2018/10/22)
import java.util.Collections;
import java.util.Iterator;
import java.util.function.BiConsumer;

import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;		// 7.0.1.1 (2018/10/22)

/**
 * ArraySet.java は、LinkedHashSet を継承した、Setオブジェクトです。
 *
 * 初期オブジェクト作成のための、引数に、配列(可変長配列)を渡せるようにしています。
 * また、Iterable#forEach( Consumer ) で、ループカウンタが使えるように、新しく、
 * BiConsumer を引数に取る forEach( int , BiConsumer ) メソッドを用意しています。
 *
 * @og.rev 6.4.3.4 (2016/03/11) 新規追加
 *
 * @version  6.4
 * @author	 Kazuhiko Hasegawa
 * @since    JDK8.0,
 */
public class ArraySet<E> extends LinkedHashSet<E> {
	/** このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "7.0.1.1 (2018/10/22)" ;
	private static final long serialVersionUID = 701120181022L ;

	/**
	 * LinkedHashSet を継承した、Setオブジェクトです。
	 *
	 * 初期オブジェクト作成のための、引数に、配列を渡せるようにしています。
	 *
	 * @og.rev 7.0.1.1 (2018/10/22) 新規追加
	 *
	 * @param	elements 初期値として設定する可変長配列
	 */
	@SuppressWarnings({"unchecked", "varargs"})
	public ArraySet( final E... elements ) {
		super();
		Collections.addAll( this, elements );
	}

	/**
	 * 他のCollectionオブジェクトを追加します。
	 *
	 * @og.rev 6.4.3.4 (2016/03/11) 新規追加
	 *
	 * @param	collect Collectionオブジェクトの可変長配列
	 * @return	自分自身
	 */
	@SuppressWarnings({"unchecked"})
	public ArraySet<E> addAll( final Collection<E>... collect ) {
		if( collect != null && collect.length > 0 ) {
			for( final Collection<E> obj : collect ) {
				super.addAll( obj );
			}
		}
		return this ;
	}

	/**
	 * Iterable#forEach( Consumer ) で、引数に、ループカウンタを使用できるメソッドです。
	 *
	 * ラムダ式から参照されるローカル変数は、finalまたは事実上のfinalである必要があります。
	 * ところが、訳あって、ループカウンタが必要です。そこで、内部処理として、ループカウンタを
	 * 用意しておき、それを、ラムダ式の引数として渡す方法で、対応します。
	 * 一覧の処理は、内部で、Iterator#hasNext() と、Iterator#next() を使用しているため、
	 * インスタンスレベルのsynchronized ブロックを使用しています。
	 *
	 * @og.rev 6.4.3.4 (2016/03/11) 新規追加
	 *
	 * @param	cnt カウンタの初期値
	 * @param	action 各要素に対して実行されるアクション( カウンタ、内部オブジェクト )
	 * @see		Iterable#forEach( Consumer )
	 */
	public void forEach( final int cnt , final BiConsumer<Integer ,E> action ) {
		int i = cnt;

		synchronized( this ) {
			final Iterator<E> ite = iterator();
			while( ite.hasNext() ) {
				action.accept( i++ , ite.next() );
			}
		}
	}

	/**
	 * このオブジェクトの内部表現を、文字列にして返します。
	 * 内部ｵﾌﾞｼﾞｪｸﾄの toString() を順番に呼んで、カンマで連結した文字列を返します。
	 *
	 * @og.rev 7.0.1.1 (2018/10/22) 新規追加
	 *
	 * @return  引数に対する値
	 * @og.rtnNotNull
	 */
	@Override
	public String toString() {
		final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );

		synchronized( this ) {
			final Iterator<E> ite = iterator();
			while( ite.hasNext() ) {
				buf.append( ite.next() ).append( ',' );
			}
		}

		if( buf.length() > 0 ) { buf.setLength( buf.length()-1 ); }		// 最後のカンマを削除

		return buf.toString();
	}
}
