package framework.physics;
import java.util.ArrayList;

import java3d.BoundingSphere;

import framework.model3D.OBB;
import framework.model3D.Object3D;
import framework.model3D.ObjectVisitor;


public class BoundingBoxVisitor extends ObjectVisitor {
	private ArrayList<OBB> obbList = new ArrayList<OBB>();	// 全構成要素のOBBのリスト
	private ArrayList<BoundingSphere> bsStack = new ArrayList<BoundingSphere>();	// オブジェクトの階層毎のBoundingSphereのスタック
	private String partName = null;	// 部品を指定する場合に使う
	private boolean inPart = false;
	
	public BoundingBoxVisitor() {
		partName = null;
	}
	
	public BoundingBoxVisitor(String partName) {
		this.partName = partName;
	}
	
	public void preVisit(Object3D obj) {
		pushTransform(obj);
		if (partName != null && obj.name.equals(partName)) {
			inPart = true;
		}
		if (obj.hasChildren() && obj.bs == null) {
			// 子供がいる場合、下の階層用にnullをpushする
			bsStack.add(null);
		}
	}

	public void postVisit(Object3D obj) {
		int pattern = 2;
		if (!obj.hasChildren()) {
			// 葉の場合
			OBB obb = obj.getOBB(pattern);
			if (obb != null) {
				if (obj.bs == null) {
					obj.bs = obb.getBoundingSphere();
				}
	
				obb = (OBB)obb.clone();
				BoundingSphere bs = (BoundingSphere)obj.bs.clone();
				for (int i = stackList.size() - 1; i >= 0; i--) {
					obb.transform(stackList.get(i));
					bs.transform(stackList.get(i));
				}
				if (partName == null || partName.length() == 0 || inPart) {
					obbList.add(obb); // Transform3Dを適応させたBoundsをboundsListに追加
					int stackTop = bsStack.size() - 1;
					if (bs != null && stackTop >= 0) {
						if (bsStack.get(stackTop) == null) {
							// その階層の最初のオブジェクトの場合、nullを置き換え
							bsStack.set(stackTop, bs);
						} else {
							// その階層の2番目以降のオブジェクトの場合、結合
							bsStack.get(stackTop).combine(bs);
						}
					}
				}
			}
		} else {
			// 子供がいる場合
			int stackTop = bsStack.size() - 1;
			if (obj.bs == null) {
				// 下の階層の結合結果をpopして利用する
				obj.bs = bsStack.remove(stackTop);
				stackTop--;
			}
			if (obj.bs != null && stackTop >= 0) {
				if (bsStack.get(stackTop) == null) {
					// その階層の最初のオブジェクトの場合、nullを置き換え
					bsStack.set(stackTop, obj.bs);
				} else {
					// その階層の2番目以降のオブジェクトの場合、結合
					bsStack.get(stackTop).combine(obj.bs);
				}
			}
		}
		popTransform();
		if (partName != null && obj.name.equals(partName)) {
			inPart = false;
		}
	}

	public ArrayList<OBB> getObbList() {
		return obbList;
	}
}
