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

package jp.co.iti.fagot.gob;

import java.awt.Color;
import java.awt.BasicStroke;

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

import jp.co.iti.fagot.geom.ZPoint;
import jp.co.iti.fagot.geom.ZRectangle;

import jp.co.iti.fagot.doc.DocElement;
import jp.co.iti.fagot.doc.DocGraphics;
import jp.co.iti.fagot.doc.DocGridControler;
import jp.co.iti.fagot.doc.DocPane;

import jp.co.iti.fagot.util.ZInstance;
import jp.co.iti.fagot.util.ZDebug;
import jp.co.iti.fagot.util.ZReverseEnumeration;
/**
 * 現在選択されているエレメントに対する操作を定義する
 *
 * 画面の表示倍率に関する座標変換はこのクラスでインプリメントする
 *
 * @author  福島康治
 * @version 1.01 2001/01/07
 */
public class GobManager {

	//## カレント ####################################################
	/**
	 * エレメントをカレントエレメントに設定する
	 * カレントエレメントは操作中のみ有効で、LButtonDownからLButtonUpまでの間のみ有効
	 *
	 * @param panelId パネル識別子
	 * @param elm     エレメント
	 */
	static public void setCurrent( String panelId, GElement elm ) {
	// 全選択解除
	Vector items = list(panelId,CURRENT);
	items.removeAllElements();
	if ( elm != null ) {
		items.add(elm);
	}
	}

	/**
	 * カレントエレメントに追加する
	 * @param panelId パネル識別子
	 */
	static public void addCurrent( String panelId, GElement elm ) {
	// 全選択解除
	Vector items = list(panelId,CURRENT);
	if ( elm != null ) {
		items.add(elm);
	}
	}

	/**
	 * 選択されているエレメントをカレントエレメントに設定する
	 * @param panelId パネル識別子
	 */
	static public void updateCurrent( String panelId ) {
	ZInstance.setList(panelId+CURRENT+ELEMENTS,getSelectedElement(panelId));
	}

	/**
	 * 現在選択エレメントの個数を取得する
	 * @param panelId パネル識別子
	 */
	static public Vector getCurrent( String panelId ) {
	return list(panelId,CURRENT);
	}

	//## エレメント ##################################################
	/**
	 * エレメントを取得する
	 * @param panelId パネル識別子
	 */
	static public Vector getElement( String panelId ) {
	return list(panelId,ALL);
	}

	/**
	 * 選択されているエレメントを取得する
	 * @param panelId パネル識別子
	 */
	static public Vector getSelectedElement( String panelId ) {
	Vector items = new Vector();
	Enumeration elm = list(panelId,ALL).elements();
	while ( elm.hasMoreElements() ) {
		GElement item = (GElement)elm.nextElement();
		if ( item.isSelect() ) {
			items.add( item );
		}
	}
//	ZDebug.trace("select count:"+panelId+":"+items.size());
	return items;
	}


	//## ヒットモード ################################################
	/**
	 * 現在選択されているエレメントにヒットするか？
	 * @param editor コンポーネント
	 * @param pt     ポイント
	 */
	static public byte getSelectedHitMode( DocPane editor, ZPoint pt ) {
	String panelId = editor.getPanelId();
	ZPoint transPt = transrateRootTransform( editor, pt );
	byte nMode = GOperation.NONE;

	// 現在選択されているエレメントの取得
	int nCount = 0;
	Enumeration elm = elements(panelId,ALL);
	while ( elm.hasMoreElements() ) {
		GElement item = (GElement)elm.nextElement();
		if ( item.isSelect() ) {
			nCount ++;
			byte mode = item.getHitMode(transPt);
			if ( mode != GOperation.NONE ) {
				nMode = mode;
			}
		}
	}

	if ( nMode != GOperation.NONE && nCount>1 ) {
		nMode = GOperation.MOVE;
	}
	return nMode;
	}

	/**
	 * 現在選択されているエレメントの移動モードはなにか？
	 * @param editor コンポーネント
	 * @param pt     ポイント
	 */
	static public byte getSelectedPreMoveMode( DocPane editor, ZPoint pt ) {
	String panelId = editor.getPanelId();
	ZPoint transPt = transrateRootTransform( editor, pt );
	byte nMode = GOperation.NONE;

	// 現在選択されているエレメントの取得
	int nCount = 0;
	Enumeration elm = elements(panelId,ALL);
	while ( elm.hasMoreElements() ) {
		GElement item = (GElement)elm.nextElement();
		if ( item.isSelect() ) {
			nCount ++;
			byte mode = item.getPreMoveMode(transPt);
			if ( mode != GOperation.NONE ) {
				nMode = mode;
			}
		}
	}

	if ( nMode != GOperation.NONE && nCount>1 ) {
		nMode = GOperation.MOVE;
	}
	return nMode;
	}

	/**
	 * カレントエレメントの選択状態を設定する
	 * @param panelId パネル識別子
	 * @param bSel    選択状態
	 */
	static public void setCurrentSelect( String panelId, boolean bSel ) {
	setSelect(panelId,CURRENT,bSel);
	}

	/**
	 * 全てのエレメントの選択状態を設定する
	 * @param panelId パネル識別子
	 * @param bSel    選択状態
	 */
	static public void setSelect( String panelId, boolean bSel ) {
	setSelect(panelId,ALL,bSel);
	}

	/**
	 * 選択状態を設定する
	 * @param panelId パネル識別子
	 * @param szMode  モード
	 * @param bSel    選択状態
	 */
	static public void setSelect( String panelId, String szMode, boolean bSel ) {
	Enumeration elm = elements(panelId,szMode);
	while ( elm.hasMoreElements() ) {
		GElement item = (GElement)elm.nextElement();
		item.setSelect(bSel);
	}
	}

	//## ヒットエレメント ##############################################
	/**
	 * すべてのエレメントにヒットするか？
	 * @param editor コンポーネント
	 * @param pt    ポイント
	 */
	static public GElement getCurrentHitElement( DocPane editor, ZPoint pt ) {
	return getHitElement( editor, CURRENT, pt );
	}

	/**
	 * すべてのエレメントにヒットするか？
	 * @param editor コンポーネント
	 * @param pt    ポイント
	 */
	static public GElement getHitElement( DocPane editor, ZPoint pt ) {
	return getHitElement( editor, ALL, pt );
	}

	/**
	 * すべてのエレメントにヒットするか？
	 * @param editor コンポーネント
	 * @param szMode モード
	 * @param pt     ポイント
	 */
	static public GElement getHitElement( DocPane editor, String szMode, ZPoint pt ) {
	String panelId = editor.getPanelId();
	ZPoint transPt = transrateRootTransform( editor, pt );

	// 現在選択されているエレメントの取得
	Enumeration elm = r_elements(panelId,szMode);
	while ( elm.hasMoreElements() ) {
		GElement item = (GElement)elm.nextElement();
		byte mode = item.getHitMode(transPt);
		if ( mode != GOperation.NONE ) {
			return item;
		}
	}
	
	return null;
	}

	//## 移動 ##########################################################
	/**
	 * 移動の開始
	 * @param editor コンポーネント
	 * @param grid   グリッドコントローラ
	 */
	static public void moveStart( DocPane editor, DocGridControler grid ) {
	String panelId = editor.getPanelId();
	pushRootTransform(editor,grid);

	Enumeration elm = elements( panelId, CURRENT );
	while ( elm.hasMoreElements() ) {
		GElement item = (GElement)elm.nextElement();
		item.moveStart( grid );
	}
	grid.popTransform();
	}

	/**
	 * 移動の終了
	 * @param editor コンポーネント
	 * @param grid   グリッドコントローラ
	 */
	static public void moveEnd( DocPane editor, DocGridControler grid ) {
	String panelId = editor.getPanelId();
	pushRootTransform(editor,grid);

	Enumeration elm = elements( panelId, CURRENT );
	while ( elm.hasMoreElements() ) {
		GElement item = (GElement)elm.nextElement();
		item.moveEnd( grid );
	}
	grid.popTransform();
	}

	//## 描画 ##########################################################
	/**
	 * 描画
	 * @param editor   コンポーネント
	 * @param graphics グラフィックス
	 */
	static public void paint( DocPane editor, DocGraphics graphics ) {
//	ZDebug.trace();
	String panelId = editor.getPanelId();
	pushRootTransform(editor,graphics.getGridControler());

	// Gob本体の描画
	Enumeration elm = elements( panelId, ALL );
	while ( elm.hasMoreElements() ) {
		GElement item = (GElement)elm.nextElement();
		item.paint( graphics );
	}

	graphics.getGridControler().popTransform();
	}

	/**
	 * 現在要素に対する描画
	 * @param editor   コンポーネント
	 * @param graphics グラフィックス
	 */
	static public void paintCurrent( DocPane editor, DocGraphics graphics ) {
	String panelId = editor.getPanelId();
	pushRootTransform(editor,graphics.getGridControler());

	boolean bDrag = ( size(panelId,CURRENT)!=0 );
	// ドラッグ中の場合、描画モードの変更
	if ( bDrag ) {
		graphics.getGraphics().setXORMode(Color.black);

		BasicStroke dotted = new BasicStroke(1, BasicStroke.CAP_BUTT, 
					BasicStroke.JOIN_MITER, 10.0f, new float[]{3,3}, 0);
		graphics.getGraphics().setStroke(dotted);

		// 移動影の描画
		Enumeration elm = elements( panelId, CURRENT );
		while ( elm.hasMoreElements() ) {
			GElement item = (GElement)elm.nextElement();
			item.paintDrag( graphics );
		}

		// 描画モードを戻す
		graphics.getGraphics().setPaintMode();

	} else {
		// セレクターの描画
		Enumeration elm = getSelectedElement(panelId).elements();
		while ( elm.hasMoreElements() ) {
			GElement item = (GElement)elm.nextElement();
			item.paintSelector( graphics );
		}
	}

	// 追加Gobの描画
	// コネクタの新規作成の場合、コネクタエレメントはGobとしてまだ存在しないため
	// 追加Gobとして描画する
	Enumeration elm = elements( panelId, HIGHLIGHT );
	while ( elm.hasMoreElements() ) {
		GElement item = (GElement)elm.nextElement();
		item.paint( graphics );
	}

	graphics.getGridControler().popTransform();
	}

	//## 位置 ##########################################################
	/**
	 * 表示スケール座標変換の格納
	 * @param editor   コンポーネント
	 * @param graphics グラフィックス
	 */
	static public void pushRootTransform( DocPane editor, DocGridControler grid ) {
	String panelId = editor.getPanelId();
	DocElement root = (DocElement)editor.getDocument().getRootElement(panelId);
	if ( root != null ) {
		grid.pushTransform(root.getDisplayScaledTransform(panelId));
	} else {
		grid.pushTransform(new PTransform(1,0,0,1,0,0));
	}
	}

	/**
	 * 表示スケール座標変換
	 * @param editor   コンポーネント
	 * @param pt       座標
	 */
	static public ZPoint transrateRootTransform( DocPane editor, ZPoint pt ) {
	String panelId = editor.getPanelId();
	DocElement root = (DocElement)editor.getDocument().getRootElement(panelId);
	if ( root != null ) {
		return root.getDisplayScaledTransform(panelId).inverseTransform(pt);
	}
	return pt;
	}

	/**
	 * 矩形の取得
	 * それぞれの子要素ごとに座標変換を保持している可能性があるので、
	 * グループとしては座標変換済み矩形しか取得できない。
	 *
	 * @param items 矩形を計算する子要素のベクター
	 */
	static public ZRectangle getTransformedBounds(Vector items) {
	Enumeration elm = items.elements();
	ZRectangle rect = null;
	while ( elm.hasMoreElements() ) {
		GElement item = (GElement)elm.nextElement();
		ZRectangle childRect = item.getTransformedBounds();
		if ( childRect != null ) {
			if ( rect == null ) {
				rect = childRect;
			} else {
				rect.union(childRect);
			}
		}
	}
	return rect;
	}

	//## ユーティリティ ################################################
	/**
	 * 現在選択されているエレメントの取得
	 * @param panelId パネル識別子
	 * @param mode    モード
	 */
	static public Vector list(String panelId,String mode) {
	return ZInstance.list(panelId+mode+ELEMENTS);
	}

	/**
	 * 現在選択されているエレメントの取得
	 * @param panelId パネル識別子
	 * @param mode    モード
	 */
	static public Enumeration elements(String panelId,String mode) {
	return list(panelId,mode).elements();
	}

	/**
	 * 現在選択されているエレメントの逆順取得
	 * @param panelId パネル識別子
	 * @param mode    モード
	 */
	static public Enumeration r_elements(String panelId,String mode) {
	return new ZReverseEnumeration((Vector)list(panelId,mode));
	}

	/**
	 * 現在選択されているエレメントの取得
	 * @param panelId パネル識別子
	 * @param mode    モード
	 */
	static public int size(String panelId,String mode) {
	return list(panelId,mode).size();
	}

	//## アトリビュート################################################
    /**
	 * インスタンスマネージャ登録キー：現在オブジェクト
     */
	public  static final String CURRENT		= ".current";

    /**
	 * インスタンスマネージャ登録キー：すべて
     */
	public  static final String ALL			= ".all";

    /**
	 * インスタンスマネージャ登録キー：ハイライト
     */
	public  static final String HIGHLIGHT	= ".highlight";

    /**
	 * インスタンスマネージャ登録キー：エレメントプレフィックス
     */
	public  static final String ELEMENTS	= ".elements";
}
