/*
 * @(#)FVector.java
 *
 * Copyright 2001 by Intelligent Technology Inc. All rights reserved.
 */

package jp.co.iti.fagot.fob;

import java.util.Vector;
import java.util.Enumeration;

import jp.co.iti.fagot.util.ZDebug;
/**
 * Vector
 *
 * このクラスに登録する要素として次のものが考えられる
 *
 * <ul>
 * <li> FElementの派生クラス	→FobManagerを共有する
 * <li> IFobElement				→FobManagerを共有する
 * <li> IFobContainer			→FobManagerを共有する
 * <li> その他のクラス			→なにもしない
 * </ul>
 *
 * Vectorではオブジェクトの検出(containsなど)に equalsメソッドを使用しているが
 * オブジェクトの値を変えたあとでremoveできなくなるので、indexOfを書き換える
 *
 * @author  千曳秀喜
 * @version 1.01 2001/01/07
 */
public class FVector extends FElement {

	/**
	 * コンストラクタ
	 */
	public FVector() {
	super( new Vector() );
	}

	/**
	 * Elementの登録
	 */
	public synchronized void add(Object data) {
	add( ((Vector)getData()).size(), data );
	}

	/**
	 * Elementの登録
	 */
	public synchronized void add(int nIndex, Object data) {
	if ( mMgr != null ) {
		mMgr.push( new FUndoInsertElement(this,nIndex,data) );
	}
	addNoUndo( nIndex, data );
	
	// マネージャの登録
	FobManager mgr = getFobManager();
	if ( mgr != null ) {
		if ( data instanceof FElement ) {
//			System.out.println("Add FElement");
			((FElement)data).setFobManager( mgr, getUsrData() );
		} else if ( data instanceof IFobElement ) {
			((IFobElement)data).setFobManager( mgr, getUsrData() );
		} else if ( data instanceof IFobContainer ) {
			((IFobContainer)data).setFobManager( mgr );
		} else {
//			System.out.println("UnknownType");
		}
	}
	}

	/**
	 * Elementの登録
	 */
	public synchronized void addNoUndo(int nIndex, Object data) {
	((Vector)getData()).add( nIndex, data );
	}

	/**
	 * Elementの削除
	 */
	public synchronized void remove(Object data) {
	int nIndex = indexOf( data );
	removeElementAt( nIndex );
	}

	/**
	 * Elementの削除
	 */
	public synchronized void removeElementAt(int nIndex) {
	if ( mMgr != null ) {
		Object data = elementAt(nIndex);
		mMgr.push( new FUndoRemoveElement(this,nIndex,data) );
	}
	removeElementAtNoUndo( nIndex );
	}

	/**
	 * Elementの削除
	 */
	public synchronized void removeElementAtNoUndo(int nIndex) {
	((Vector)getData()).removeElementAt( nIndex );
	}

	/**
	 * Elementの削除
	 */
	public synchronized void removeAll() {
	while ( !isEmpty() ) {
		removeElementAt(0);
	}
	}

	/**
	 * Elementの有無
	 */
	public synchronized boolean isEmpty() {
	return ( ((Vector)getData()).isEmpty() );
	}

	/**
	 * 含むか？
	 */
	public synchronized boolean contains( Object data ) {
	return ( indexOf( data )!=-1 );
	}

	/**
	 * サイズの取得
	 */
	public synchronized int size() {
	return ( ((Vector)getData()).size() );
	}

	/**
	 * Elementの取得
	 */
	public synchronized Object elementAt(int nIndex) {
	return ((Vector)getData()).elementAt(nIndex);
	}

	/**
	 * 要素の位置を検索します
	 */
	public synchronized int indexOf( Object data ) {
	int nIndex = 0;
	Enumeration elm = elements();
	while ( elm.hasMoreElements() ) {
		Object obj = elm.nextElement();
		if ( obj == data ) {
//			ZDebug.trace("     find..."+data);
			return nIndex;
		}
//		ZDebug.trace("     xxxx..."+data+"!="+obj);
		nIndex++;
	}
	return -1;
	}

	/**
	 * Enumerationの取得
	 */
	public synchronized Enumeration elements() {
	return ( ((Vector)getData()).elements() ) ;
	}

	/**
	 * 逆順Enumerationの取得
	 */
	public synchronized Enumeration r_elements() {
	return new Enumeration() {
		Vector mVector = (Vector)getData();
	    int    mCount = 0;

		public boolean hasMoreElements() {
			return mCount < mVector.size();
		}

		public Object nextElement() {
			if (mCount < mVector.size()) {
				return mVector.elementAt(mVector.size()-(++mCount));
			}
			return null;
		}
	};
	}

	//## FAGOT ########################################################
	/**
	 * マネージャの設定
	 * @param mgr マネージャ
	 * @param usrData ユーザデータ(任意のユーザデータ)
	 */
	public void setFobManager( FobManager mgr, Object usrData ) {
	super.setFobManager( mgr, usrData );
	Enumeration elm = elements() ;
	while( elm.hasMoreElements() ) {
		Object obj = elm.nextElement();

		// マネージャの登録
		if ( obj instanceof FElement ) {
			((FElement)obj).setFobManager( mgr, usrData );
		} else if ( obj instanceof IFobContainer ) {
			((IFobContainer)obj).setFobManager( mgr );
		}
	}
	}

	//## CLONE ########################################################
	/**
	 * 複製インスタンスの作成
	 * 各実現クラスにおいてインスタンスを生成する
	 * 仮想クラス（およびインスタンス化されないクラス）ではnullを返す
	 */
	public Object createClone() {
	return new FVector();
	}

	/**
	 * アトリビュートの複製
	 * @param obj 複製先のオブジェクト
	 */
	public void copyAttribute( Object obj ) {
	Enumeration elm = elements() ;
	while ( elm.hasMoreElements() ) {
		Object item  = elm.nextElement();
		if ( item instanceof FElement ) {
			((FVector)obj).add(((FElement)item).clone());
		} else if ( obj instanceof IFobContainer ) {
			((FVector)obj).add(((IFobContainer)item).clone());
		} else {
			ZDebug.err("not yet support：clone"+item.toString());
		}
	}
	}

	//## サブクラス：アンドゥオブジェクト（insert,remove共通）#########
	/**
	 * FVector用undoオブジェクト
	 */
	public class FUndoVectorElement implements IFUndoElement {
	/**
	 * コンストラクタ
	 * @param org    オリジナルオブジェクト
	 * @param nIndex 位置
	 * @param obj    値
	 */
	public FUndoVectorElement(FVector org, int nIndex, Object obj) {
	mOrg    = org    ;
	mIndex  = nIndex ;
	mObj    = obj    ;
	}

	/**
	 * アンドゥ
	 */
	public void undo() {
	}

	/**
	 * リドゥ
	 */
	public void redo() {
	}

	/**
	 * オリジナルオブジェクトの取得
	 */
	public void getFobs( Vector items ) {
	items.add( mOrg );
	items.add( mObj );
	}

	//## アトリビュート################################################
	/**
	 * オリジナルオブジェクト
	 */
	protected FVector  mOrg    = null ;
	
	/**
	 * 位置
	 */
	protected int      mIndex  = -1   ;
	
	/**
	 * 値
	 */
	protected Object   mObj    = null ;
	}

	//## サブクラス：アンドゥオブジェクト（insert用）##################
	/**
	 * FVector用undoオブジェクト(insert用)
	 */
	public class FUndoInsertElement extends FUndoVectorElement {
	/**
	 * コンストラクタ
	 * @param org    オリジナルオブジェクト
	 * @param nIndex 位置
	 * @param obj    値
	 */
	public FUndoInsertElement(FVector org, int nIndex, Object obj) {
	super( org, nIndex, obj ) ;
	}

	/**
	 * アンドゥ
	 */
	public void undo() {
//	mOrg.removeNoUndo(mObj);
	mOrg.removeElementAtNoUndo(mIndex);
	}

	/**
	 * リドゥ
	 */
	public void redo() {
	mOrg.addNoUndo(mIndex,mObj);
	}
	}

	//## サブクラス：アンドゥオブジェクト（remove用）##################
	/**
	 * FVector用undoオブジェクト(remove用)
	 */
	public class FUndoRemoveElement extends FUndoVectorElement {
	/**
	 * コンストラクタ
	 * @param org    オリジナルオブジェクト
	 * @param nIndex 位置
	 * @param obj    値
	 */
	public FUndoRemoveElement(FVector org, int nIndex, Object obj) {
	super( org, nIndex, obj ) ;
	}

	/**
	 * アンドゥ
	 */
	public void undo() {
	mOrg.addNoUndo(mIndex,mObj);
	}

	/**
	 * リドゥ
	 */
	public void redo() {
	mOrg.removeElementAtNoUndo(mIndex);
	}
	}
}
