/*
 * @(#)RidElementZone.java
 *
 * Copyright 2001 Nomura Research Institute, LTD. All rights reserved.
 *
 * RID-X : Element
 *
 * @author  Intelligent Technology Inc.
 * @version 1.01 2001/11/07
 */
package jp.co.nri.rid.doc;

import java.awt.Color;

import java.text.DecimalFormat;

import javax.swing.JComponent;
import javax.swing.JViewport;

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

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.DOMException;

import jp.co.iti.fagot.ZApp;

import jp.co.iti.fagot.fob.FColor;
import jp.co.iti.fagot.fob.xml.XElementNS;

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

import jp.co.iti.fagot.gob.GElement;
import jp.co.iti.fagot.gob.GobManager;
import jp.co.iti.fagot.gob.GLine;
import jp.co.iti.fagot.gob.GOperation;
import jp.co.iti.fagot.gob.GString;
import jp.co.iti.fagot.gob.GRectangle;
import jp.co.iti.fagot.gob.PTransform;

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

import jp.co.iti.fagot.util.ZGraphicUtil;
import jp.co.iti.fagot.util.ZInstance;
import jp.co.iti.fagot.util.ZResource;
import jp.co.iti.fagot.util.ZDebug;

import jp.co.nri.Rid;
import jp.co.nri.rid.RUpdateManager;

import jp.co.nri.rid.environment.MessageDialog;
import jp.co.nri.rid.error.RidMessage;
import jp.co.nri.rid.error.RidException;
/**
 * Rid Element(Zone用)
 */
public class RidElementZone extends RidElement {

	/**
	 * デフォルトコンストラクタ
	 */
	public RidElementZone() throws DOMException {
	}

	/**
	 * デフォルトトップページの取得
	 */
	public RidElementPage getDefaultTopPage() {
	RidElementPage topPage = null;
	String szTop = getAttribute("Top");
	if ( szTop.length() > 0 ) {
		// トップが指定されている場合はトップページ
//		topPage = (RidElementPage)findChildElement("PageUnit","File="+szTop);
		topPage = (RidElementPage)((RidDocumentSite)getOwnerDocument()).findChildElementInZone("PageUnit",szTop);
	}
	if ( topPage == null ) {
		// 存在しない場合はindex.html
		topPage = (RidElementPage)findChildElement(".PageUnit","Name=index.html");

		if ( topPage == null ) {
			// index.htm
			topPage = (RidElementPage)findChildElement(".PageUnit","Name=index.htm");
		}

		if ( topPage == null ) {
			// なんでもいいのでとにかくページ
			// findChildElement(where=null)はノードのキャッシュが帰ってくるので、
			// 自力で検索する
//			topPage = (RidElementPage)findChildElement(".PageUnit",null);
			NodeList list = getChildNodes();
			for ( int nAt=0 ; nAt<list.getLength() ; nAt++ ) {
				Node child = list.item(nAt);
				if ( child instanceof RidElementPage ) {
					topPage = (RidElementPage)child ;
//					ZDebug.trace("top:"+topPage.getAttribute("File"));
					break;
				}
			}
		}

		if ( topPage == null ) {
			// 子供のページでもよい
			NodeList list = getChildNodes();
			for ( int nAt=0 ; nAt<list.getLength() ; nAt++ ) {
				Node child = list.item(nAt);
				if ( child instanceof RidElementZone ) {
					topPage = ((RidElementZone)child).getDefaultTopPage() ;
					if ( topPage != null ) {
						break;
					}
				}
			}
		}
	}
	return topPage;
	}

	//## IGobContainer：ヒット ########################################
	/**
	 * ダブルクリックの動作
	 * @param gob  リクエスト元Gob
	 * @param mode クリック位置
	 */
	public void verbDblClick(GElement gob,ZPoint pt) {
//	ZDebug.trace();
	String szActive = ZInstance.prop().getProperty( Rid.PANEL_ACTIVE );
	JComponent active = (JComponent)ZInstance.map().get(szActive);
	if ( !(active instanceof DocPane) ) {
		// アクティブパネルが描画パネルでない場合は描画しない
		return;
	}
	DocPane editor = (DocPane)active;
	RidDocumentSite doc = (RidDocumentSite)editor.getDocument();
	RidElement top = doc.getTopZone();

//	PTransform trans = gob.getTransform();
//	ZRectangle rect = gob.getTransformedBounds();
	ZRectangle rect = gob.getBounds();

	ZPoint ptTTL = new ZPoint(0,getTitleHeight()+TTLIN*2);
//	ZPoint ptTTLTrans = trans.transform( ptTTL );
//	double dTTL = ptTTLTrans.getY();
	double dTTL = ptTTL.getY();

	// タイトル行のクリックの場合
	if ( pt.getY() < rect.getY()+dTTL ) {
		// シュリンクボタンにかかっていない場合
		if ( pt.getX() < rect.getX()+rect.getWidth()-dTTL ) {
		  	RidElementZone parent = (RidElementZone)getParentNode();
			RidElementZone root   = (RidElementZone)((DocDocument)getOwnerDocument()).getRootElement(editor.getPanelId());
			if ( parent == root ) {
				// 名前の編集
				rect.setHeight( dTTL );
				editor.setEditElement(this,rect,false);
			} else {
				// ゾーンの描画(孫ゾーンのタイトル編集は行わない)
				changeRoot( editor );
				top.setChildUnSelect();
				doc.setLinksUnSelect();
			}
		// シュリンクボタン
		} else {
//			ZDebug.trace("Omission");
			XElementNS elm = getChildElement(".ViewInfo."+editor.getPanelId(),null);
			boolean bValue = elm.getBooleanAttr("Omission",false);
			elm.setBooleanAttr("Omission",!bValue);
			editor.updateGobs();
		}
	} else {
		// ゾーンの描画
		changeRoot( editor );
		top.setChildUnSelect();
		doc.setLinksUnSelect();
	}
	}

	/**
	 * ルートの変更
	 * @param editor エディタ
	 */
	public void changeRoot(DocPane editor) {
	// ルートの変更
	RidDocumentSite doc = (RidDocumentSite)getOwnerDocument();
	doc.setRootElement(editor.getPanelId(),this);

	// ビューポートの再配置
	editor.setPaintMode(false);
	JViewport port = (JViewport)editor.getParent();
	port.doLayout();
	editor.setPaintMode(true);

	// 再描画
	editor.editRestart();

//	RUpdateManager.update(RUpdateManager.VIEWACTION_VIEWZONE, true );
	RUpdateManager.update(RUpdateManager.VIEWACTION_VIEWZONE );
	}

	//## IGobContainer：移動 ##########################################
	/**
	 * 移動中Pathの取得
	 * @param gob  リクエスト元Gob
	 * @param grid グリッドコントローラ
	 */
	public ZPath getMovingPath(GElement gob,DocGridControler grid) {
	ZRectangle rect = null;

	if ( grid.getMoveMode() == GOperation.NEW ) {
		ZPoint ptSta= grid.getStartGrid();
		ZPoint ptMov= grid.getMoveGrid();
		if ( (ptMov.getX()-ptSta.getX()) < 10 ) { ptMov.setX(ptSta.getX()+200); }
		if ( (ptMov.getY()-ptSta.getY()) < 10 ) { ptMov.setY(ptSta.getY()+100); }
		ZPoint ptBR = new ZPoint( Math.max(ptMov.getX(),ptSta.getX()+30),
								  Math.max(ptMov.getY(),ptSta.getY()+30) );
		rect = new ZRectangle( ptSta, ptBR );
	} else {
		rect = ((GRectangle)gob).getMovingRectGob(grid);
	}
	return  new ZPath( rect );
	}

	//## 描画 #########################################################
	/**
	 * 描画エレメントの取得
	 *
	 * ルートの場合は、自分自身を描画しない
	 * @param szPanelId パネル識別子
	 * @param isRoot    ルートの有無
	 */
	public Vector createGobs(String szPanelId,boolean isRoot) {
	Vector gobs = new Vector();

	// 省略有無
	XElementNS vwi = getChildElement(".ViewInfo."+szPanelId,null);
	boolean bOmission = vwi.getBooleanAttr("Omission",false);

	// 自分自身の作成
	if ( !isRoot ) {
		if ( !hasRect(szPanelId) ) {
			// 自動レイアウト
			ZPoint pt = getSpace(szPanelId);
			ZRectangle rt = new ZRectangle( pt.getX(), pt.getY(), 200, 100 );
			setRect(szPanelId,rt);
		}
		GRectangle gRect = createMainGob(szPanelId);
		gRect.setSelect(isSelect());
		gRect.setContainer(this);
		gRect.setGobId("zone");
		gRect.setMinSize(new ZDimension(30,30));
		gobs.add(gRect);
		setMainGob(szPanelId,gRect);

		// 影の描画
		gRect.addBackChildren( createShadowGobs( gRect ) );

		// 名前の描画
		gRect.addForeChildren( createTitleGobs( szPanelId ) );

		// 省略マークの描画
		double dTitleHeight = getTitleHeight();
		Vector omi = new Vector();
		ZRectangle rect = getRect(szPanelId);
		double dXStart = rect.getX()+rect.getWidth()-(dTitleHeight+TTLIN*2);
		double dYStart = rect.getY();
		double dZ      = dTitleHeight+TTLIN*2;
		// 左線の表示
		GLine gLine = new GLine();
		gLine.getStyle().setStrokeColor( new FColor( Color.black ));
		gLine.setLine( new ZLine(dXStart,dYStart,dXStart,dYStart+dZ) );
		omi.add(gLine);
		// 中央線
		gLine = new GLine();
		gLine.getStyle().setStrokeColor( new FColor( Color.black ));
		gLine.setLine( new ZLine(dXStart+TTLIN,dYStart+dZ/2,dXStart+dZ-TTLIN,dYStart+dZ/2) );
		omi.add(gLine);
		// 縦線
		if ( bOmission ) {
			gLine = new GLine();
			gLine.getStyle().setStrokeColor( new FColor( Color.black ));
			gLine.setLine( new ZLine(dXStart+dZ/2,dYStart+TTLIN,dXStart+dZ/2,dYStart+dZ-TTLIN) );
			omi.add(gLine);
		}
		gRect.addForeChildren( omi );

		// シュリンク文字列の表示
		if ( bOmission ) {
			Vector childPages = getPages(true);
			Vector childZones = getZones(true);
			Enumeration elm = childPages.elements();
			int nDone = 0;
			while( elm.hasMoreElements() ) {
				DocElement page = (DocElement)elm.nextElement();
				if ( page.getAttribute("Status").equals("done") ) {
					nDone++;
				}
			}
			ZRectangle canvas = new ZRectangle( rect.getX()+INSET,
												rect.getY()+INSET+dTitleHeight,
												rect.getWidth()-INSET*2,
												rect.getHeight()-INSET*2-dTitleHeight );
			// キャンバスが小さい場合は描画しない
			if ( canvas.getWidth() >= 50 && canvas.getHeight() >= 20 ) {
				Color bgcol = getBackgroundColor();
				Color txtcol = (ZGraphicUtil.isBlackFamily(bgcol)?Color.white:Color.black);
				Vector children = new Vector();
				// Page
				GString gStr = new GString();
				gStr.setText( "Page　　　"+nDone+"/"+childPages.size() );
				gStr.getStyle().setFillColor( new FColor( txtcol ));
				gStr.setFormat( GString.CENTER|GString.MIDDLE );
				ZRectangle rtCanvas = new ZRectangle( canvas.getX(),canvas.getY(),canvas.getWidth(),canvas.getHeight()/2);
				gStr.setRect( rtCanvas );
				children.add(gStr);

				// Zone
				gStr = new GString();
				gStr.setText( "Zone　　　"+childZones.size() );
				gStr.getStyle().setFillColor( new FColor( txtcol ));
				gStr.setFormat( GString.CENTER|GString.MIDDLE );
				rtCanvas = new ZRectangle( canvas.getX(),canvas.getY()+canvas.getHeight()/2,canvas.getWidth(),canvas.getHeight()/2);
				gStr.setRect( rtCanvas );
				children.add(gStr);

				gRect.addForeChildren( children );
			}
		}
	}

	// 子供用Gobの作成
	if ( isRoot || !bOmission ) {
		Vector children = createChildGobs(szPanelId);
		convertChildGobs( szPanelId, children ) ;
		gobs.addAll(children);
	} else {
		// 子ノードに、省略時のGobを通知する
		for ( int nIndex=0; nIndex<getLength() ; nIndex++ ) {
			Node elm = (Node)item(nIndex);
			if ( elm instanceof RidElement ) {
				((RidElement)elm).setOmissionGob( szPanelId,getMainGob(szPanelId) );
			}
		}
	}

	return gobs;
	}

	/**
	 * 描画エレメントの取得
	 *
	 * ルートの場合は、自分自身を描画しない
	 * @param szPanelId パネル識別子
	 * @param isRoot    ルートの有無
	 */
	public Vector createSkeltonGobs(String szPanelId,boolean isRoot) {
	Vector gobs = new Vector();

	// 自分自身の作成
	if ( isRoot ) {
		// 子供用Gobの作成
		Vector children = new Vector();
		// 子ノードの描画
		for ( int nIndex=0; nIndex<getLength() ; nIndex++ ) {
			Node elm = (Node)item(nIndex);
			if ( elm instanceof DocElement ) {
				children.addAll(((DocElement)elm).createSkeltonGobs( szPanelId,false ));
			}
		}
		convertChildGobs( szPanelId, children ) ;
		gobs.addAll(children);

	} else if ( hasRect(szPanelId) ) {
		GRectangle gRect = createMainGob(szPanelId);
		gRect.setPaintIfSmall(true);
		gobs.add(gRect);
	}

	return gobs;
	}

	/**
	 * 描画エレメントの取得
	 * @param szPanelId パネル識別子
	 */
	public GRectangle createMainGob(String szPanelId) {
	GRectangle gRect = new GRectangle();

	// 矩形の設定
	ZRectangle rect = getRect( szPanelId );
	gRect.setRect( rect );
	// 背景色の設定
	Color col = getBackgroundColor();
	gRect.getStyle().setFillColor( new FColor( col ));

	// 枠色の設定
	ZResource res = ZApp.getTheApp().getResource();
	boolean isExist = getBooleanAttr("Exist", true );
	col = res.getColor("unit.color."+((isExist)?"":"Not")+"Exist");
	gRect.getStyle().setStrokeColor( new FColor( col ));
	return gRect;
	}

	/**
	 * 子供のエレメントの取得
	 * @param szPanelId パネル識別子
	 */
	public void convertChildGobs(String szPanelId,Vector children) {
	// ルートエレメントでなければ、Zoneの中に入るよう座標変換する
	PTransform trans = null;
	if ( ((DocDocument)getOwnerDocument()).getRootElement(szPanelId)!=this && hasRect(szPanelId) ) {
		ZRectangle childRect = GobManager.getTransformedBounds(children);
		ZRectangle rect = getRect( szPanelId );
		if ( childRect != null ) {
			ZRectangle childRectMax = null;
			double dTitleHeight = getTitleHeight();
			ZRectangle canvas = new ZRectangle( rect.getX()+INSET,
												rect.getY()+INSET+dTitleHeight,
												rect.getWidth()-INSET*2,
												rect.getHeight()-INSET*2-dTitleHeight );

/* 子供の縮尺ゾーンを記憶しないよう修正
			if ( hasRect(szPanelId+".child") ) {
				ZRectangle oldChildRect = getRect(szPanelId+".child");
				childRect.union(oldChildRect);
			}
			setRect(szPanelId+".child",childRect);
*/
			trans = ZGraphicUtil.getNormalizeTransform( canvas, childRect );

			Enumeration elm = children.elements();
			while ( elm.hasMoreElements() ) {
				GElement item = (GElement)elm.nextElement();
				item.addTransform( trans );
			}
		}
	}

	// 座標変換ルーチンの保存
	if ( trans == null ) {
		mChildTransform.remove( szPanelId );
	} else {
		mChildTransform.put( szPanelId, trans );
	}
	}

	/**
	 * DOM Tree上での位置変更
	 */
	public void treeChanged() {
	updateFileAttribute();
	}

	/**
	 * 子供用座標変換の取得
	 * @param szPanelId パネル識別子
	 */
	public PTransform getChildTransform( String szPanelId ) {
	return (PTransform)mChildTransform.get( szPanelId );
	}

	//## 名前管理 #####################################################
	/**
	 * エレメントの追加
	 *
	 * 自分の直接の子供であれば子供を追加する
	 * 直接の子供でなければ子供ゾーンに渡す
	 *
	 * @param element エレメント
	 */
	public void appendChild( DocElement element ) {

	super.appendChild(element);

	// 直接の子供で、名前がついていなければ名前を付ける
	String szName = element.getAttribute("Name");
	if ( szName == null || szName.length()==0 ) {
		String szTag = element.getTagName();
		String szKey = szTag;
		if ( szTag.endsWith("Unit") ) {
			szKey = szTag.substring(0,szTag.length()-4);
		}

		// ページの場合は、ファイルタイプを付与
		String szSuffix = null;
		if ( szTag.startsWith("Page") ) {
			szSuffix = getAttribute("FileType");
			if ( szSuffix == null || szSuffix.length()==0 ) {
				szSuffix = "html";	// プロパティが設定されていない場合デフォルト
			}
		}

		int nIndex=1;
		for(  ; nIndex<10000 ; nIndex++ ) {
			String szNum = new DecimalFormat("0000").format( nIndex );
			szName = szKey + szNum;
			if ( szSuffix != null ) {
				szName += "." + szSuffix ;
			}
			// 同名が存在するかチェック
			if ( findChildElement("."+szTag,"Name="+szName)==null ) {
				break;
			}
		}
		
		if ( nIndex == 10000 ) {
			szName = "";
			RidMessage ridMsg = new RidMessage();
			MessageDialog.showError(ridMsg.Error("E1002",""));
		}
		element.setAttribute("Name", szName ) ;
//	} else {
//		ZDebug.trace("create:"+szName);
	}
	}

	/**
	 * ページユニットの収集
	 * @param isContainChild 孫ゾーンまで検索するか？
	 */
	public Vector getPages( boolean isContainChild ) {
	Vector pages = new Vector();
	NodeList list = getChildNodes();
	for ( int nAt=0 ; nAt<list.getLength() ; nAt++ ) {
		Node child = list.item(nAt);
		if ( child instanceof RidElementZone && isContainChild ) {
			pages.addAll(((RidElementZone)child).getPages( isContainChild ));
		} else if ( child instanceof RidElementPage ) {
			pages.add( child );
		}
	}
	return pages;
	}

	/**
	 * ゾーンユニットの収集
	 * @param isContainChild 孫ゾーンまで検索するか？
	 */
	public Vector getZones( boolean isContainChild ) {
	Vector pages = new Vector();
	NodeList list = getChildNodes();
	for ( int nAt=0 ; nAt<list.getLength() ; nAt++ ) {
		Node child = list.item(nAt);
		if ( child instanceof RidElementZone ) {
			pages.add( child );
			if ( isContainChild ) {
				pages.addAll(((RidElementZone)child).getZones( isContainChild ));
			}
		}
	}
	return pages;
	}

	/**
	 * DOMから削除
	 * 子ページからのリンクもともに削除するため
	 * 子供がいる場合は子供をそれぞれ削除しておく
	 */
	public void removeFromDocTree() {
	NodeList list = getChildNodes();
	for ( int nAt=0 ; nAt<list.getLength() ; ) {
		Node child = list.item(nAt);
		if ( child instanceof RidElement ) {
			((RidElement)child).removeFromDocTree();
		} else {
			nAt++;
		}
	}
	super.removeFromDocTree();
	}

	//## 編集 #########################################################
	/**
	 * 文字列の設定
	 */
	public void setText(String szText) {
	setAttribute("Name",szText);
	if ( !szText.equals( getAttribute("Name") ) ) {
		RidException err = (RidException)ZInstance.map().get("setAttribute");
		MessageDialog.showError(err.getMessage());
	}
	}

	/**
	 * 文字列の取得
	 */
	public String getText() {
	return 	getAttribute("Name");
	}

	//## アトリビュート################################################
	/**
	 * 子供用座標変換
	 */
	protected Hashtable mChildTransform = new Hashtable();

	/**
	 * Zone Canvasのインセット
	 */
	final static public double INSET = 10;

}
