/*
 * Paraselene
 * Copyright (c) 2009  Akira Terasaki
 * このファイルは同梱されているLicense.txtに定めた条件に同意できる場合にのみ
 * 利用可能です。
 */
package paraselene.tag.form;


import java.util.*;
import paraselene.*;
import paraselene.tag.*;


/**
 * リスト。SELECTタグ。
 */
public class Select extends Control {
	private static final long serialVersionUID = 2L;
	private static final String NAME = "select";
	private static final String MULTI = "multiple";

	/**
	 * 複数選択可能か？
	 * @return true:可能、false:不可能
	 */
	public boolean isMultiple() {
		return getAttribute( MULTI ) != null;
	}

	/**
	 * 複数選択指定。
	 * @param multi_f true:複数選択可、false:複数選択不可。
	 */
	public void setMultiple( boolean multi_f ) {
		if ( multi_f ) {
			try {
				setAttribute( new Attribute( MULTI ) );
			}
			catch( Exception e ) {}
		}
		else {
			removeAttribute( MULTI );
		}
	}

	/**
	 * コンストラクタ。
	 */
	public Select() {
		super( NAME, false );
	}

	protected Tag newReplica() {
		return new Select();
	}

	private void setup( HTMLPart d ) {
		if ( !(d instanceof SelectItem) )	return;
		SelectItem	item = (SelectItem)d;
		item.list = this;
		if ( item.isSelected() ) {
			setValueString( item.getValueString() );
		}
	}

	public void addHTMLPart( HTMLPart d ) {
		super.addHTMLPart( d );
		setup( d );
	}

	public void addHTMLPart( int idx, HTMLPart d ) {
		super.addHTMLPart( idx, d );
		setup( d );
	}

	/**
	 * 選択項目の取得。
	 * @return 選択項目の配列。
	 */
	public SelectItem[] getItemArray() {
		Tag[]	tag = getTagArray();
		ArrayList<SelectItem>	item = new ArrayList<SelectItem>();
		for ( int i = 0; i < tag.length; i++ ) {
			if ( tag[i] instanceof SelectItem ) {
				item.add( (SelectItem)tag[i] );
			}
		}
		return item.toArray( new SelectItem[0] );
	}

	/**
	 * 値の取得。<br>
	 * 選択されているOPTIONのvalueを返します。<br>
	 * 何も選択されていなければnullです。
	 * @return 選択値。最初に見つかったものを返す。
	 */
	public String getValueString() {
		SelectItem[]	item = getItemArray();
		for ( int i = 0; i < item.length; i++ ) {
			if ( item[i].isSelected() ) {
				return item[i].getValueString();
			}
		}
		return null;
	}

	/**
	 * 値の取得。<br>
	 * 選択されているOPTIONのvalueを全て返します。<br>
	 * 何も選択されていなければ0個の配列を返します。
	 * @return 選択値。
	 */
	public String[] getValueStrings() {
		ArrayList<String>	list = new ArrayList<String>();
		SelectItem[]	item = getItemArray();
		for ( int i = 0; i < item.length; i++ ) {
			if ( item[i].isSelected() ) {
				list.add( item[i].getValueString() );
			}
		}
		return list.toArray( new String[0] );
	}

	/**
	 * 選択値との比較。
	 * 渡された文字列配列と、getValueStrings()結果が完全一致するか検査します。
	 * 登場順序は問いません。文字列比較結果を検証します。
	 * 渡された文字列配列と、getValueStrings()結果の配列数が異なるとfalseです。
	 * @param val 検証文字列配列。
	 * @return true:一致する、false:一致しない。
	 */
	public boolean isSameSet( String[] val ) {
		String[]	myself = getValueStrings();
		if ( val.length != myself.length )	return false;
		return isSubSet( val );
	}

	/**
	 * 選択値との比較。
	 * 渡された文字列配列が全て、getValueStrings()結果中に登場するか検査します。
	 * isSameSet( String[] val )メソッドと同じ動作を行うメソッドですが、
	 * 入力配列.length &gt; getValueStrings().length の時のみfalseで
	 * 件数が完全一致する必要はありません。含まれていればtrueです。
	 * @param val 検証文字列配列。
	 * @return true:内包する、false:内包しない。
	 */
	public boolean isSubSet( String[] val ) {
		String[]	myself = getValueStrings();
		if ( val.length > myself.length )	return false;
		for ( int i = 0; i < val.length; i++ ) {
			boolean	flag = false;
			for ( int j = 0; j < myself.length; j++ ) {
				if ( val[i] == null ) {
					if ( myself[j] == null )	flag = true;
				}
				else {
					flag = val[i].equals( myself[j] );
				}
				if ( flag ) {
					myself[j] = "\bpara\bselene\b";
					break;
				}
			}
			if ( !flag )	return false;
		}
		return true;
	}

	/**
	 * 値の設定。<br>
	 * valueに指定値を持つOPTIONを選択状態にします。<br>
	 * nullを渡すと、全て選択解除されます。<br>
	 * 複数選択不可能であれば、指定値以外のOPTIONは同時に選択解除されます。
	 * @param v 設定値。
	 */
	public void setValueString( String v ) {
		SelectItem[]	item = getItemArray();
		boolean	flag = !isMultiple();
		for ( int i = 0; i < item.length; i++ ) {
			if ( v == null ) {
				item[i].setSelected( false );
				continue;
			}
			if ( v.equals( item[i].getValueString() ) ) {
				item[i].setSelected( true );
			}
			else if ( flag ) {
				item[i].setSelected( false );
			}
		}
	}

	/**
	 * 通番の選択アイテムを作成します。
	 * タグの内部は全て消去され、新しく追加されます。<br>
	 * value値も、表示文字列も同じ数値が設定されます。<br>
	 * 例えば、start=1、end=31とすれば、日にちを選択するためのSELECTを作成できます。
	 * @param start 開始番号。
	 * @param end 終了番号。
	 */
	public void makeSequenceNo( int start, int end ) {
		removeHTMLPart();
		for ( ; start <= end; start++ ) {
			String	str = Integer.toString( start );
			addHTMLPart( new SelectItem( str, str ) );
		}
	}
}

