package jp.ac.kyutech.mns.ist.util;

import java.awt.Dimension;
import java.awt.geom.Point2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import edu.umd.cs.piccolo.PCamera;
import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolo.nodes.PPath;
import edu.umd.cs.piccolo.util.PBounds;

/**
 * 表示領域（キャンバス）のサイズ変更に合わせて，ぴったりレイアウトするためのPropertyChangeListener
 * 
 * おもにPMenu (Piccolo Menu:勝手に作成した簡易ボタン）の位置を調整するために使用
 * 
 * @author miuramo
 * 
 */
public class CameraFitConstraint extends PBasicInputEventHandler implements PropertyChangeListener {
	public static enum PositionEnum {
		TOPLEFT, TOPRIGHT, TOPFILL, TOPCENTER, BOTTOMLEFT, BOTTOMRIGHT, BOTTOMFILL, BOTTOMCENTER, LEFTTOP, LEFTCENTER, LEFTBOTTOM, RIGHTTOP, RIGHTCENTER, RIGHTBOTTOM, TOP, RIGHT, BOTTOM, LEFT; // Cascading Style Sheet のマージン定義における並びと同じ
	}

	PPath target;

	PCamera camera;

	PositionEnum constraint;

	Dimension gap;
	
	boolean alwaysShow = false;

	public CameraFitConstraint(PPath t, PCamera cam, PositionEnum con,
			Dimension _defaultGap) {
		target = t;
		camera = cam;
		constraint = con;
		//		defaultOffset = _defaultOffset;
		gap = _defaultGap;

		camera.addInputEventListener(this);
	}
	public void setAlwaysShow(boolean b){
		alwaysShow = b;
	}

	public void mouseMoved(final PInputEvent aEvent) {
		try{
			Point2D pos = aEvent.getPositionRelativeTo(camera);
			
//			System.out.print(pos);
//			System.out.println(camera.getBoundsReference().getHeight());
//			System.out.println(target.getBoundsReference().getHeight());
			
			if (constraint == PositionEnum.BOTTOM || constraint == PositionEnum.BOTTOMLEFT || 
					constraint == PositionEnum.BOTTOMRIGHT || constraint == PositionEnum.BOTTOMCENTER || 
					constraint == PositionEnum.BOTTOMFILL ){
				if (!target.getVisible() && pos.getY()> camera.getBoundsReference().getHeight()-20) {
					target.setVisible(true);
				}
				if (target.getVisible() && pos.getY()< camera.getBoundsReference().getHeight()-target.getHeight()) {
					if (!alwaysShow) target.setVisible(false);
				}
			} else if (constraint == PositionEnum.TOP || constraint == PositionEnum.TOPCENTER || 
					constraint == PositionEnum.TOPLEFT || constraint == PositionEnum.TOPRIGHT || 
					constraint == PositionEnum.TOPFILL ){
				if (!target.getVisible() && pos.getY() <  target.getGlobalFullBounds().getHeight()+20) {
					target.setVisible(true);
				}
				if (target.getVisible() && pos.getY() > target.getGlobalFullBounds().getHeight()+20) {
					if (!alwaysShow) target.setVisible(false);
				}
			} else if (constraint == PositionEnum.RIGHTCENTER || constraint == PositionEnum.RIGHTBOTTOM 
					|| constraint == PositionEnum.RIGHTTOP ){
				if (!target.getVisible() && pos.getX() >  camera.getBoundsReference().getWidth()-20) {
					target.setVisible(true);
				}
				if (target.getVisible() && pos.getX() < camera.getBoundsReference().getWidth()-20) {
					if (!alwaysShow) target.setVisible(false);
				}
			}
			Point2D tpos = aEvent.getPositionRelativeTo(target);
			if (!target.getBoundsReference().contains(tpos)) if (!alwaysShow) target.setVisible(false);
		} catch(RuntimeException ex){
		}
	}

	public void propertyChange(PropertyChangeEvent evt) {
		if (evt.getSource() == camera) {
			if (evt.getPropertyName().equals("bounds")) {
				fitTo(camera.getBoundsReference());
			}
		}
	}
	public void fitTo(PBounds b){
		if (constraint == PositionEnum.TOPRIGHT)
			fitToTopRight(camera.getBoundsReference());
		else if (constraint == PositionEnum.TOPLEFT)
			fitToTopLeft(camera.getBoundsReference());
		else if (constraint == PositionEnum.TOPCENTER)
			fitToTopCenter(camera.getBoundsReference());
		else if (constraint == PositionEnum.LEFTTOP)
			fitToLeftTop(camera.getBoundsReference());
		else if (constraint == PositionEnum.LEFTCENTER)
			fitToLeftCenter(camera.getBoundsReference());
		else if (constraint == PositionEnum.LEFTBOTTOM)
			fitToLeftBottom(camera.getBoundsReference());
		else if (constraint == PositionEnum.RIGHTTOP)
			fitToRightTop(camera.getBoundsReference());
		else if (constraint == PositionEnum.RIGHTCENTER)
			fitToRightCenter(camera.getBoundsReference());
		else if (constraint == PositionEnum.RIGHTBOTTOM)
			fitToRightBottom(camera.getBoundsReference());
		else if (constraint == PositionEnum.BOTTOMLEFT)
			fitToBottomLeft(camera.getBoundsReference());
		else if (constraint == PositionEnum.BOTTOMCENTER)
			fitToBottomCenter(camera.getBoundsReference());
		else if (constraint == PositionEnum.BOTTOMRIGHT)
			fitToBottomRight(camera.getBoundsReference());

	}

	private void fitToBottomRight(PBounds b) {
		target.setOffset(b.width - target.getFullBounds().width - gap.width,
				b.height - target.getFullBounds().height - gap.height);
	}

	private void fitToBottomCenter(PBounds b) {
		target.setOffset(b.width/2 - target.getFullBounds().width/2 + gap.width,
				b.height - target.getFullBounds().height - gap.height);
	}

	private void fitToBottomLeft(PBounds b) {
		target.setOffset(gap.width,
				b.height - target.getFullBounds().height - gap.height);

	}

	private void fitToRightBottom(PBounds b) {
		target.setOffset(b.getWidth() - target.getFullBounds().width - gap.width,
				b.getHeight() - target.getFullBounds().height - gap.height);
	}

	private void fitToRightCenter(PBounds b) {
		target.setOffset(b.getWidth() - target.getFullBounds().width - gap.width,
				b.getHeight()/2 - target.getFullBounds().height/2 + gap.height);
	}

	private void fitToRightTop(PBounds b) {
		target.setOffset(b.getWidth() - target.getFullBounds().width - gap.width,
				gap.height);
	}

	private void fitToLeftBottom(PBounds b) {
		target.setOffset(gap.width,
				b.getHeight() - target.getFullBounds().height - gap.height);
	}

	private void fitToLeftCenter(PBounds b) {
		target.setOffset(gap.width,
				b.getHeight()/2 - target.getFullBounds().height/2 + gap.height);
	}

	private void fitToLeftTop(PBounds b) {
		target.setOffset(gap.width,
				gap.height);
	}

	public void fitToTopRight(PBounds b) {
		// Boundsが変化したら！！！
		// resize((float)b.width);
		target.setOffset(b.width - target.getFullBounds().width, gap.height);

		// preBounds = b;
	}
	public void fitToTopLeft(PBounds b) {
		// Boundsが変化したら！！！
		// resize((float)b.width);
		target.setOffset(gap.width, gap.height);
		// preBounds = b;
	}
	public void fitToTopCenter(PBounds b) {
		// Boundsが変化したら！！！
		// resize((float)b.width);
		target.setOffset(b.getWidth()/2 - target.getFullBounds().width/2, gap.height);
		// preBounds = b;
	}

	public void fitToBottomFill(PBounds b) {
		// Boundsが変化したら！！！
		resize((float) b.width);
		target.setOffset(gap.getWidth(), b.height
				- target.getFullBounds().height - 2);

		// preBounds = b;
	}

	public void resize(float width) {
		target.setPathToRectangle((float) 0, (float) 0,
				(float) (width - (gap.getWidth() * 2)),
				(float) gap.getHeight());
	}
}