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

package jp.co.iti.fagot.gob;

import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.Shape;
import java.awt.GradientPaint;

import java.awt.geom.Rectangle2D;
import java.awt.geom.AffineTransform;

import java.awt.image.BufferedImage;

import java.awt.geom.GeneralPath;

import jp.co.iti.fagot.fob.FobManager;
import jp.co.iti.fagot.fob.FInteger;

import jp.co.iti.fagot.geom.ZPath;
import jp.co.iti.fagot.geom.ZDimension;
import jp.co.iti.fagot.geom.ZPoint;
import jp.co.iti.fagot.geom.ZRectangle;
import jp.co.iti.fagot.geom.ZGeneralPath;

import jp.co.iti.fagot.util.ZGraphicUtil;

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

import jp.co.iti.fagot.util.ZDebug;

/**
 * Rectangle
 * 一時的な選択矩形もこのクラスで表現します
 *
 * @author  福島康治
 * @version 1.01 2001/01/07
 */
public class GRectangle extends GPath {

	/**
	 * コンストラクタ
	 */
	public GRectangle() {
		super();
		//{{FAGOT_ATTR
		mRect   = new ZRectangle();
		mMinSize = new ZDimension();
		mPaintOption = new FInteger();
		mEditOption = new FInteger();
		//}}FAGOT_ATTR

		mMinSize.setSize(10,10);
	}

	//## 位置##########################################################
	/**
	 * 位置の取得
	 */
	public ZRectangle getBounds() {
	return new ZRectangle(mRect);
	}

	/**
	 * 要素にヒットするか？
	 * @param pt   論理座標
	 */
	public byte getHitModeGob(ZPoint pt) {
	// セレクターにヒットするか？
	GSelector sel = new GSelector();
	AffineTransform at = getTransform().getTransform();
	sel = sel.createScaledSelector( 1/at.getScaleX(), 1/at.getScaleY() );
	if ( isSelect() && (getEditOption()&NORESIZE)==0 )  { 
		for (byte nAt=GOperation.ZOOMBASE;nAt<=GOperation.ZOOMMAX;nAt++ ) {
			if ( sel.isHit(getSelectorPoint(nAt),pt) ) {
				return ( nAt ) ;
			}
		}
	}

	// 塗りつぶしの場合
	if ( true ) {
		if ( getBounds().contains(pt) ) {
			return ( GOperation.MOVE ) ;
		}
	} else {
		// パスの近くか検索する
		if ( ZGraphicUtil.isNearLine(
				getSelectorPoint(GOperation.ZOOMNW),
				getSelectorPoint(GOperation.ZOOMNE),pt,
				sel.getMargin(1,0)                     ) ||
			 ZGraphicUtil.isNearLine(
				getSelectorPoint(GOperation.ZOOMNE),
				getSelectorPoint(GOperation.ZOOMSE),pt,
				sel.getMargin(0,1)                     ) ||
			 ZGraphicUtil.isNearLine(
				getSelectorPoint(GOperation.ZOOMSE),
				getSelectorPoint(GOperation.ZOOMSW),pt,
				sel.getMargin(1,0)                     ) ||
			 ZGraphicUtil.isNearLine(
				getSelectorPoint(GOperation.ZOOMSW),
				getSelectorPoint(GOperation.ZOOMNW),pt,
				sel.getMargin(0,1)                     ) ) {
			return ( GOperation.MOVE ) ;
		}
	}
	return ( GOperation.NONE );
	}

	/**
	 * 要素の接続位置取得
	 * @param mode 接続位置
	 */
	public ZPoint getConnectPointGob(byte mode) {
	ZPoint pt = getSelectorPoint( mode );
	return getTransform().transform( pt );
	}


	//## 移動##########################################################
	/**
	 * 移動中Pathの取得
	 * @param grid グリッドコントローラー
	 */
	public ZPath getMovingPathGob(DocGridControler grid) {
	return  new ZPath( getMovingRectGob(grid) );
	}

	/**
	 * 移動中Pathの取得
	 * @param grid グリッドコントローラー
	 */
	public ZRectangle getMovingRectGob(DocGridControler grid) {
	ZRectangle rect = getBounds();
	ZPoint pt1 = grid.getMoveGridZone() ;
	ZPoint pt2;
	ZPoint ptTL;
	ZPoint ptBR;
//	System.out.println("GRectangle:getMovingRect:"+grid.getMoveMode());

	switch ( grid.getMoveMode() ) {
	  case GOperation.MOVE:		// 移動
	  case GOperation.HANDON:	// 移動
		rect.translate( grid.getOffsetGrid() ) ;
		break ;

	  case GOperation.ZOOMNE:	// 原点がある拡大
		pt2 = getSelectorPoint( getContrastPoint( grid.getMoveMode() ) );
		ptTL= new ZPoint( pt2.getX(), Math.min(pt1.getY(),pt2.getY()-mMinSize.getHeight()) );
		ptBR= new ZPoint( Math.max(pt1.getX(), pt2.getX()+mMinSize.getWidth()), pt2.getY() );
		rect = new ZRectangle( ptTL, ptBR );
		break ;
	  case GOperation.ZOOMNW:
		pt2 = getSelectorPoint( getContrastPoint( grid.getMoveMode() ) );
		ptTL= new ZPoint( Math.min(pt1.getX(),pt2.getX()-mMinSize.getWidth()), Math.min(pt1.getY(),pt2.getY()-mMinSize.getHeight()) );
		ptBR= pt2;
		rect = new ZRectangle( ptTL, ptBR );
		break ;
	  case GOperation.ZOOMSE:
		pt2 = getSelectorPoint( getContrastPoint( grid.getMoveMode() ) );
		ptTL= pt2;
		ptBR= new ZPoint( Math.max(pt1.getX(),pt2.getX()+mMinSize.getWidth()), Math.max(pt1.getY(),pt2.getY()+mMinSize.getHeight()) );
		rect = new ZRectangle( ptTL, ptBR );
		break ;
	  case GOperation.ZOOMSW:
		pt2 = getSelectorPoint( getContrastPoint( grid.getMoveMode() ) );
		ptTL= new ZPoint( Math.min(pt1.getX(), pt2.getX()-mMinSize.getWidth()), pt2.getY() );
		ptBR= new ZPoint( pt2.getX(), Math.max(pt1.getY(),pt2.getY()+mMinSize.getHeight()) );
		rect = new ZRectangle( ptTL, ptBR );
		break ;

	  case GOperation.ZOOME:	// 横拡大
		ptTL= new ZPoint( rect.getX(), rect.getY() );
		ptBR= new ZPoint( Math.max(pt1.getX(), rect.getX()+mMinSize.getWidth()), rect.getY()+rect.getHeight() );
		rect = new ZRectangle( ptTL, ptBR );
		break;
	  case GOperation.ZOOMW:
		ptTL= new ZPoint( Math.min(pt1.getX(), rect.getX()+rect.getWidth()-mMinSize.getWidth()), rect.getY() );
		ptBR= new ZPoint( rect.getX()+rect.getWidth(), rect.getY()+rect.getHeight() );
		rect = new ZRectangle( ptTL, ptBR );
		break;

	  case GOperation.ZOOMN:	// 縦拡大
		ptTL= new ZPoint( rect.getX(), Math.min(pt1.getY(), rect.getY()+rect.getHeight()-mMinSize.getHeight()) );
		ptBR= new ZPoint( rect.getX()+rect.getWidth(), rect.getY()+rect.getHeight() );
		rect = new ZRectangle( ptTL, ptBR );
		break;
	  case GOperation.ZOOMS:
		ptTL= new ZPoint( rect.getX(), rect.getY() );
		ptBR= new ZPoint( rect.getX()+rect.getWidth(), Math.max(pt1.getY(), rect.getY()+mMinSize.getHeight()) );
		rect = new ZRectangle( ptTL, ptBR );
		break;
	}

	// 最小値を設定
	if ( rect.getWidth() < 10 ) {
		rect.setWidth(10);
	}
	if ( rect.getHeight() < 10 ) {
		rect.setHeight(10);
	}
//	ZDebug.trace("GRectangle:getMovingRect:"+rect.toString());
	return rect;
	}

	/**
	 * グループ化移動
	 */
	public void groupIn(double x,double y) {
	ZRectangle rect = getBounds();
	rect.translate( x, y );
	setRect( rect );
	}

	/**
	 * グループ化解除移動
	 */
	public void groupOut(double x,double y,double width,double height) {
	ZRectangle rect = getBounds();

	// 拡大縮小による移動
	rect.setRect( rect.getX()      * width,
				  rect.getY()      * height,
				  rect.getWidth()  * width,
				  rect.getHeight() * height);

	// 移動
	rect.translate( x, y );

	setRect( rect );
	}

	//## 固有##########################################################
	/**
	 * セレクターポイントの取得
	 */
	public ZPoint getSelectorPoint(byte nAt) {
	ZRectangle rect = getBounds();
	ZPoint pt = new ZPoint();

	// X座標
	switch(nAt) {
	  case GOperation.ZOOME:
	  case GOperation.ZOOMNE:
	  case GOperation.ZOOMSE:
		pt.setX( rect.getX()+rect.getWidth()) ;
		break;
	  case GOperation.ZOOMW:
	  case GOperation.ZOOMNW:
	  case GOperation.ZOOMSW:
		pt.setX(rect.getX()) ;
		break;
	  case GOperation.ZOOMN:
	  case GOperation.ZOOMS:
	  case GOperation.MOVE:
		pt.setX(rect.getX()+rect.getWidth()/2) ;
		break;
	}

	// Y座標
	switch(nAt) {
	  case GOperation.ZOOMN:
	  case GOperation.ZOOMNE:
	  case GOperation.ZOOMNW:
		pt.setY( rect.getY() ) ;
		break;
	  case GOperation.ZOOMS:
	  case GOperation.ZOOMSE:
	  case GOperation.ZOOMSW:
		pt.setY( rect.getY()+rect.getHeight() ) ;
		break;
	  case GOperation.ZOOME:
	  case GOperation.ZOOMW:
	  case GOperation.MOVE:
		pt.setY( rect.getY()+rect.getHeight()/2 ) ;
		break;
	}
	return ( pt ) ;
	}

	/**
	 * 対象点の取得
	 */
	public byte getContrastPoint(byte mode) {
	byte nRet = GOperation.NONE;
	switch ( mode ) {
	  case GOperation.ZOOMNE:
		nRet = GOperation.ZOOMSW ;
		break;
	  case GOperation.ZOOMNW:
		nRet = GOperation.ZOOMSE ;
		break;
	  case GOperation.ZOOMSE:
		nRet = GOperation.ZOOMNW ;
		break;
	  case GOperation.ZOOMSW:
		nRet = GOperation.ZOOMNE ;
		break;
	  case GOperation.ZOOME:
		nRet = GOperation.ZOOMW ;
		break;
	  case GOperation.ZOOMW:
		nRet = GOperation.ZOOME ;
		break;
	  case GOperation.ZOOMN:
		nRet = GOperation.ZOOMS ;
		break;
	  case GOperation.ZOOMS:
		nRet = GOperation.ZOOMN ;
		break;
	}
	return ( nRet ) ;
	}

	//## 描画##########################################################
	/**
	 * 選択点の描画：上下左右、角の８箇所描画
	 * @param g グラフィックス
	 */
	public void paintSelector(DocGraphics graphics) {

	// 座標変換の適用
	graphics.getGridControler().pushTransform(getTransform());

	GSelector sel = new GSelector();
	int nMax = GOperation.ZOOMMAX;
	if ( (getEditOption()&NORESIZE)==1 )  { 
		nMax = GOperation.ZOOMBASE+3 ;
	}

	for (byte nAt=GOperation.ZOOMBASE;nAt<=nMax;nAt++ ) {
		ZPoint pt = getSelectorPoint(nAt) ;
		ZPoint ptTrans = graphics.getGridControler().transform( pt );
		sel.paint(graphics.getGraphics(),ptTrans);
	}

	// 座標変換を元に戻す
	graphics.getGridControler().popTransform();
	}

	//## FAGOT ########################################################
	/**
	 * 位置の設定
	 */
	public void setRect(ZRectangle data) {
	mRect.setRect( data );
	setPath();
	}

	/**
	 * パスの設定
	 */
	public void setPath() {
	setPath( new ZPath( getRect() ) );
	}

	/**
	 * 位置の取得
	 */
	public ZRectangle getRect() {
	return new ZRectangle(mRect);
	}

	/**
	 * 最小サイズの設定
	 */
	public void setMinSize(ZDimension dim) {
	mMinSize.setSize( dim );
	}

	/**
	 * 位置の取得
	 */
	public ZDimension getMinSize() {
	return new ZDimension(mMinSize);
	}

	/**
	 * オプションの設定
	 * @param nOption オプション
	 */
	public void setPaintOption(int nOption) {
		mPaintOption.set( nOption );
	}

	/**
	 * オプションの取得
	 */
	public int getPaintOption() {
	return mPaintOption.get();
	}

	/**
	 * オプションの設定
	 * @param nOption オプション
	 */
	public void setEditOption(int nOption) {
		mEditOption.set( nOption );
	}

	/**
	 * オプションの取得
	 */
	public int getEditOption() {
	return mEditOption.get();
	}

	/**
	 * Fobマネージャの登録
	 * @param mgr マネージャ
	 */
	public void setFobManager(FobManager mgr) {
		super.setFobManager(mgr);
		//{{FAGOT_ATTR
//		mRect.setFobManager(mgr,this);
//		mMinSize.setFobManager(mgr,this);
		mPaintOption.setFobManager(mgr,this);
		mEditOption.setFobManager(mgr,this);
		//}}FAGOT_ATTR
	}

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

	/**
	 * アトリビュートの複製
	 * @param obj 複製先のオブジェクト
	 */
	public void copyAttribute( Object obj ) {
	super.copyAttribute( obj );
	((GRectangle)obj).setRect( getRect() );
	((GRectangle)obj).setMinSize( getMinSize() );
	((GRectangle)obj).setPaintOption( getPaintOption() );
	((GRectangle)obj).setEditOption( getEditOption() );
	}

	//##{FAGOT_ATTRIBUTE###############################################
	/**
	 * 座標
	 */
	protected ZRectangle	mRect = null;

	/**
	 * 最小サイズ
	 */
	protected ZDimension	mMinSize = null;

	/**
	 * オプション
	 */
	protected FInteger	mPaintOption = null;

	/**
	 * オプション
	 */
	protected FInteger	mEditOption = null;

	/**
	 * オプション：サイズ変更なし
	 */
	public final static int NORESIZE = 0x0001;
}
