/*
 * @(#)GPath.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.Stroke;
import java.awt.Composite;
import java.awt.AlphaComposite;
import java.awt.Rectangle;

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

import jp.co.iti.fagot.fob.FobManager;
import jp.co.iti.fagot.fob.FColor;
import jp.co.iti.fagot.fob.FFloat;
import jp.co.iti.fagot.fob.FString;

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

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

import jp.co.iti.fagot.util.ZDebug;
/**
 * Path
 *
 * 当面描画用テンポラリクラスとして使用する
 * そのため、mPathは undoable ではない
 *
 * @author  福島康治
 * @version 1.01 2001/01/07
 */

public class GPath extends GElement {

	/**
	 * コンストラクタ
	 */
	public GPath() {
	super();
	//{{FAGOT_ATTR
	mPath = new ZPath();
	//}}FAGOT_ATTR
	}

	//## 位置##########################################################
	/**
	 * 位置の取得
	 */
	public ZRectangle getMyBounds() {
	return new ZRectangle(mPath.getBounds2D());
	}

	/**
	 * 要素にヒットするか？
	 * @param pt   論理座標
	 */
	public byte getHitModeGob(ZPoint pt) {
	ZPath path = getPath();
	if ( path.contains(pt) ) {
		return GOperation.MOVE;
	}
	return GOperation.NONE ;
	}

	/**
	 * 要素の接続位置取得
	 * @param mode 接続位置
	 */
	public ZPoint getConnectPointGob(byte mode) {
//	ZRectangle rect = getTransformedBounds();
	ZRectangle rect = new ZRectangle(getPath().getBounds2D());
	return rect.getCenter();
/*
	GRectangle gRect = new GRectangle();
	gRect.setRect(rect);
	return gRect.getConnectPointGob(mode);
*/
	}

	//## 移動##########################################################
	/**
	 * 移動中Pathの取得
	 * @param grid グリッドコントローラー
	 */
	public ZPath getMovingPathGob(DocGridControler grid) {
	ZPath path = getPath();
	switch ( grid.getMoveMode() ) {
	  case GOperation.MOVE:		// 移動
		ZPoint pt = grid.getOffsetGrid();
		AffineTransform at = new AffineTransform(1,0,0,1,pt.getX(),pt.getY());
		path.transform(at);
	}
	
	return path;
	}

	//## 描画##########################################################
	/**
	 * 描画
	 * @param g グラフィックス
	 */
	public void paintContents(DocGraphics g) {
	Graphics2D g2 = g.getGraphics();
	PStyle style = getStyle();

/*	*** 20020410 *** 描画図形は、paintCheck()にて、mPaintShapeに設定する
	ZPath   path = getPath();

	// 塗りつぶしルールの設定
	// default値は、WIND_NON_ZEROのため、WIND_EVEN_ODDの場合のみ設定する
	if ( !style.getFill().getRule().isNull() &&
	      style.getFill().getRule().get().equals("evenodd") ) {
		path.setWindingRule(ZGeneralPath.WIND_EVEN_ODD);
	}

	Shape sh = g.getGridControler().transform( path );
	// クリップ領域に座標が含まれない場合は、描画しない
	if ( !checkClipRect(g2,sh.getBounds2D()) ) {
		return;
	}
*/
	if ( mPaintShape == null ) {
		createPaintShape(g);
	}

	// 塗りつぶし
	if ( !style.getFill().getColor().isNull() ) {
		// 色の設定
		Color oldColor = g2.getColor();
		g2.setColor( style.getFill().getColor().get() );

		// 透過度の設定
		Composite oldComposite = null ;
		if ( !style.getFill().getOpacity().isNull() ) {
			oldComposite = g2.getComposite();
			g2.setComposite (
				AlphaComposite.getInstance(
					AlphaComposite.SRC_OVER,
					style.getFill().getOpacity().get()
				)
			);
		}

		// 塗りつぶし
		g2.fill( mPaintShape );

		// 元に戻す
		g2.setColor( oldColor ) ;
		if ( oldComposite != null ) {
			g2.setComposite( oldComposite );
		}
	}

	// 輪郭
	if ( !style.getStroke().getColor().isNull() ) {
		// 色の設定
		Color oldColor = g2.getColor();
		g2.setColor( style.getStroke().getColor().get() );

		// 透過度の設定
		Composite oldComposite = null ;
		if ( !style.getStroke().getOpacity().isNull() ) {
			oldComposite = g2.getComposite();
			g2.setComposite (
				AlphaComposite.getInstance(
					AlphaComposite.SRC_OVER,
					style.getStroke().getOpacity().get()
				)
			);
		}

		// Stroke の作成
		Stroke oldStroke = g2.getStroke();
		g2.setStroke( style.getStroke().createStroke() );

		// 輪郭
		g2.draw( mPaintShape );

		// 元に戻す
		g2.setColor( oldColor ) ;
		g2.setStroke( oldStroke ) ;
		if ( oldComposite != null ) {
			g2.setComposite( oldComposite );
		}
	}
	}

	/**
	 * 選択点の描画
	 */
	public void paintSelector(DocGraphics graphics) {
	// 座標変換の適用
	graphics.getGridControler().pushTransform(getTransform());

	GSelector sel = new GSelector();
	PathIterator pi = getPath().getPathIterator(null);
	ZPoint pt = null;
	ZPoint ptTrans = null;
	while ( !pi.isDone() ) {
		double[] segs = new double[6];
		int nType = pi.currentSegment( segs );
		switch ( nType ) {
		  case PathIterator.SEG_MOVETO:
		  case PathIterator.SEG_LINETO:
			pt = new ZPoint( segs[0], segs[1] );
			ptTrans = graphics.getGridControler().transform( pt );
			sel.paint(graphics.getGraphics(),ptTrans);
			break;
		  case PathIterator.SEG_QUADTO:
			pt = new ZPoint( segs[2], segs[3] );
			ptTrans = graphics.getGridControler().transform( pt );
			sel.paint(graphics.getGraphics(),ptTrans);
			break;
		  case PathIterator.SEG_CUBICTO:
			pt = new ZPoint( segs[4], segs[5] );
			ptTrans = graphics.getGridControler().transform( pt );
			sel.paint(graphics.getGraphics(),ptTrans);
			break;

		  case PathIterator.SEG_CLOSE:
			break;
		}
		pi.next();
	}

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

	/**
	 * 移動影の描画
	 */
	public void paintDragContents(DocGraphics g) {
	Graphics2D g2 = g.getGraphics();
	ZPath path = getMovingPath(g.getGridControler());
	Shape sh   = g.getGridControler().transform( path );
//	ZDebug.trace("paintDrag:"+sh.toString());
	g2.draw( sh );
	}

	/**
	 * 性能向上のため描画を間引くか否かを判定する。
	 * main gobでのみ判定し、子gobはmain gobに従う
	 * @param graphics グラフィックス
	 */
	protected boolean paintCheck(DocGraphics graphics) {
	boolean bPaint = true;
	createPaintShape(graphics);

	// クリップ領域に座標が含まれない場合は、描画しない
	Rectangle2D rt     = mPaintShape.getBounds2D();
	Rectangle clipRect = graphics.getGraphics().getClipBounds();
	if ( !(mIsPaintIfSmall) && ( rt.getWidth() < 2 || rt.getHeight() < 2 ) ) {
		bPaint = false;
	} else if (  clipRect != null &&
		( clipRect.x > (rt.getX()+rt.getWidth())  || (clipRect.x+clipRect.width)  < rt.getX() ) &&
		( clipRect.y > (rt.getY()+rt.getHeight()) || (clipRect.y+clipRect.height) < rt.getY() ) ) {
		bPaint = false;
	}

	return bPaint;
	}

	/**
	 * 描画図形の計算
	 * @param graphics グラフィックス
	 */
	protected void createPaintShape(DocGraphics graphics) {
	ZPath path  = getPath();
	mPaintShape = graphics.getGridControler().transform( path );
	}

	//## FAGOT ########################################################
	/**
	 * 値の取得
	 */
	public ZPath getPath() {
	return new ZPath( mPath );
	}

	/**
	 * 値の設定
	 */
	public void setPath(ZPath data) {
	mPath.setPath( data );
	}

	/**
	 * 描画属性の設定
	 * どんなに小さくても描画するか？(sckelton用)
	 * @param bValue 表示有無
	 */
	public void setPaintIfSmall(boolean bValue) {
	mIsPaintIfSmall = bValue;
	}

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

	/**
	 * アトリビュートの複製
	 * @param obj 複製先のオブジェクト
	 */
	public void copyAttribute( Object obj ) {
	super.copyAttribute( obj );
	((GPath)obj).setPath( getPath() );
	}

	//## アトリビュート################################################
	/**
	 * 座標
	 */
	protected ZPath		mPath;

	/**
	 * 変換された描画座標
	 * paihtCheck()で作成し、paintContents()で利用する
	 */
	protected Shape 	mPaintShape = null;

	/**
	 * 小さくても描画するか？
	 */
	protected boolean mIsPaintIfSmall = false;
}
