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

import java.awt.Color;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.Point2D;
import java.util.ArrayList;

import javax.swing.JOptionPane;

import jp.ac.kyutech.mns.ist.FocusFrame;
import jp.ac.kyutech.mns.ist.Note;
import edu.umd.cs.piccolo.PLayer;
import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolo.event.PInputEventFilter;
import edu.umd.cs.piccolo.event.PInputEventListener;
import edu.umd.cs.piccolo.nodes.PText;

public class LayerSeatmapButton extends LayerButton implements PInputEventListener {
	private static final long serialVersionUID = 8033945569687683416L;

	SeatmapController seatmapcontroller;
	ArrayList<Note> jumps; //飛び先の可能性
	ArrayList<Note> leaves;//離れる可能性
	int x,y;
	public ArrayList<PText> jumpT;
	public ArrayList<PText> leaveT;
	//IDにホバーしたら，筆記をハイライト

	public LayerSeatmapButton(double x, double y, double w, double h, PLayer l, SeatmapController sc) {
		super(x, y, w, h, l);
		seatmapcontroller = sc;
		jumpT = new ArrayList<PText>();
		leaveT = new ArrayList<PText>();
//		leaveT.setTextPaint(Color.black);
//		addChild(leaveT);
//		leaveT.setOffset();

		jumps = new ArrayList<Note>();
		leaves = new ArrayList<Note>();

		addInputEventListener(this);
	}

	PText createJumpT(Note stu){
		final PText jt = new PText(String.valueOf(stu.penid));
		jt.setTextPaint(Color.blue);
		jt.addAttribute("student", stu);
		jt.addAttribute("button", this);
		jt.addAttribute("seatmapcontroller", seatmapcontroller);
		jt.addInputEventListener(new PBasicInputEventHandler(){
			public void mouseEntered(PInputEvent aEvent){
				jt.setPaint(Color.yellow);
				seatmapcontroller.hilit(jt.getAttribute("student"),Color.red);
			}
			public void mouseExited(PInputEvent aEvent){
				jt.setPaint(null);
				seatmapcontroller.hilit(jt.getAttribute("student"),new Color(0, 0, 90));
			}
			public void mouseClicked(PInputEvent aEvent){
				if (aEvent.isRightMouseButton()){
//					if (jt.getTextPaint() == Color.red){
//					JOptionPane.showMessageDialog(null, "conflict");
//					aEvent.setHandled(true);
//					} else {
////					JOptionPane.showMessageDialog(null, "jt right");

					Point2D cp = aEvent.getPositionRelativeTo(seatmapcontroller.cam);
					FramePopup popup = new LayerSeatmapButtonMenu(LayerSeatmapButton.this, jt);
					popup.showWithFrame(seatmapcontroller, (int) cp.getX(), (int) cp.getY(), seatmapcontroller.frame);

					aEvent.setHandled(true);
//					}
				}
				if (aEvent.isLeftMouseButton()){
					String numstr = jt.getText();
					int num = Integer.parseInt(numstr);
					int res = JOptionPane.showConfirmDialog(seatmapcontroller.frame, numstr+"番を拡大しますか？","拡大",JOptionPane.YES_NO_OPTION);
					if (res == JOptionPane.YES_OPTION){
//						JOptionPane.showMessageDialog(null, "jt left");
						jumpByNumber(num);
					}
					aEvent.setHandled(true);
				}
			}
		});
//		addChild(jt);
//		jt.setOffset(10,0);
		return jt;
	}

	public void jumpByNumber(int num){
		Note spanel = seatmapcontroller.satn.getNote(num);
		spanel.focus();
//		ATNWindow window = spanel.buffer.getActiveViewAny();
//		if (window != null) {
//			PBounds pBounds = spanel.getBounds();
//			if (pBounds != null){
//				Point2D spoffset = spanel.studentcamera.getOffset();
//				pBounds.moveBy(spoffset.getX(), spoffset.getY());
//				window.zoomToBounds(pBounds, spanel.buffer.atnProperty.animsec);
//			}						
//		}
	}

	public LayerSeatmapButton(Shape shape) {
		super(shape);
	}

	public LayerSeatmapButton(Shape shape, Stroke stroke) {
		super(shape, stroke);
	}

	public void setXY(int _x, int _y){
		x = _x;
		y = _y;
	}
	public void doClick(PInputEvent a){
		if (clickAction != null){
			clickAction.actionPerformed(new ActionEvent(LayerSeatmapButton.this,
					a.getModifiersEx(),
					String.valueOf(x)+" "+String.valueOf(y)+" "+
					String.valueOf(a.getPosition().getX())+" "+String.valueOf(a.getPosition().getY())));
		}
	}

	public void addJump(Note stu){
		if (!jumps.contains(stu)) {
			jumps.add(stu);
			System.out.println("x "+x+" y "+y+" jump add "+stu.penid);
			updateJumpLeave();
		}
	}
	public void removeJump(Note stu){
		if (jumps.contains(stu)) {
			jumps.remove(stu);
			System.out.println("x "+x+" y "+y+" jump remove "+stu.penid);
			updateJumpLeave();
		}
	}
	public void addLeave(Note stu){
		if (!leaves.contains(stu)) {
			leaves.add(stu);
			System.out.println("x "+x+" y "+y+" leave add "+stu.penid);
			updateJumpLeave();
		}
	}
	public void removeLeave(Note stu){
		if (leaves.contains(stu)) {
			leaves.remove(stu);
			System.out.println("x "+x+" y "+y+" leave remove "+stu.penid);
			updateJumpLeave();
		}
	}

	public void updateJumpLeave(){
		for(PText pt: jumpT){
			pt.removeFromParent();
		}
		jumpT.clear();

		int pos = 10;
		for(Note st: jumps){
			PText jt = createJumpT(st);
			addChild(jt);
			jt.setOffset(pos,0);
			pos+=20;
			if (jumps.size()>1) jt.setTextPaint(Color.red);
			jumpT.add(jt);
		}

		for(PText pt: leaveT){
			pt.removeFromParent();
		}
		leaveT.clear();

		pos = 10;
		for(Note st: leaves){
			PText jt = createJumpT(st);
			addChild(jt);
			jt.setOffset(pos,getHeight()-jt.getHeight());
			pos+=20;
			jt.setTextPaint(Color.black);
			leaveT.add(jt);
		}
	}
	public String getIDs(ArrayList<Note> astu){
		StringBuffer sb = new StringBuffer();
		for(Note stu:astu){
			sb.append(stu.penid+"   ");
		}
		return sb.toString();
	}


	private PInputEventFilter eventFilter = new PInputEventFilter();		

	public void processEvent(PInputEvent event, int type) {
		if (!acceptsEvent(event, type)) return;

		switch (type) {
		case KeyEvent.KEY_PRESSED:
			keyPressed(event);
			break;

		case KeyEvent.KEY_RELEASED:
			keyReleased(event);
			break;

		case KeyEvent.KEY_TYPED:
			keyTyped(event);
			break;

		case MouseEvent.MOUSE_CLICKED:
			mouseClicked(event);
			break;

		case MouseEvent.MOUSE_DRAGGED:
			mouseDragged(event);
			break;

		case MouseEvent.MOUSE_ENTERED:
			mouseEntered(event);
			break;

		case MouseEvent.MOUSE_EXITED:
			mouseExited(event);
			break;

		case MouseEvent.MOUSE_MOVED:
			mouseMoved(event);
			break;

		case MouseEvent.MOUSE_PRESSED:
			mousePressed(event);
			break;

		case MouseEvent.MOUSE_RELEASED:
			mouseReleased(event);
			break;

		case MouseWheelEvent.WHEEL_UNIT_SCROLL:
			mouseWheelRotated(event);
			break;

		case MouseWheelEvent.WHEEL_BLOCK_SCROLL:
			mouseWheelRotatedByBlock(event);
			break;

		case FocusEvent.FOCUS_GAINED:
			keyboardFocusGained(event);
			break;

		case FocusEvent.FOCUS_LOST:
			keyboardFocusLost(event);
			break;

		default:
			throw new RuntimeException("Bad Event Type");
		}
	}

	//****************************************************************
	// Event Filter - All this event listener can be associated with a event
	// filter. The filter accepts and rejects events based on their modifier
	// flags and type. If the filter is null (the 
	// default case) then it accepts all events.
	//****************************************************************

	public boolean acceptsEvent(PInputEvent event, int type) {
		return eventFilter.acceptsEvent(event, type);
	}

	public PInputEventFilter getEventFilter() {
		return eventFilter;
	}

	public void setEventFilter(PInputEventFilter newEventFilter) {
		eventFilter = newEventFilter;
	}

	//****************************************************************
	// Events - Methods for handling events sent to the event listener.
	//****************************************************************

	public void keyPressed(PInputEvent event) {
	}

	public void keyReleased(PInputEvent event) {
	}

	public void keyTyped(PInputEvent event) {
	}

	public void mouseClicked(PInputEvent event) {
		if (event.isRightMouseButton()){
			JOptionPane.showMessageDialog(null, "ボタン右クリックは現在，機能がありません");

		}
		if (event.isLeftMouseButton()){
			leftClick(event);
		}
	}

	public void mousePressed(PInputEvent event) {
	}

	public void mouseDragged(PInputEvent event) {
	}

	public void mouseEntered(PInputEvent event) {
	}

	public void mouseExited(PInputEvent event) {
	}

	public void mouseMoved(PInputEvent event) {
	}

	public void mouseReleased(PInputEvent event) {
	}

	public void mouseWheelRotated(PInputEvent event) {
	}

	public void mouseWheelRotatedByBlock(PInputEvent event) {
	}

	public void keyboardFocusGained(PInputEvent event) {
	}

	public void keyboardFocusLost(PInputEvent event) {
	}

	//****************************************************************
	// Debugging - methods for debugging
	//****************************************************************

	/**
	 * Returns a string representation of this object for debugging purposes.
	 */
	public String toString() {
		String result = super.toString().replaceAll(".*\\.", "");
		return result + "[" + paramString() + "]";
	}

	/**
	 * Returns a string representing the state of this node. This method is
	 * intended to be used only for debugging purposes, and the content and
	 * format of the returned string may vary between implementations. The
	 * returned string may be empty but may not be <code>null</code>.
	 *
	 * @return  a string representation of this node's state
	 */
	protected String paramString() {
		StringBuffer result = new StringBuffer();
		result.append("eventFilter=" + eventFilter == null ? "null" : eventFilter.toString());
		return result.toString();
	}

	public void leftClick(PInputEvent event){
		if (jumps == null){
		} else {
			if (jumps.size()==0)return;//登録なし

			if (jumps.size()==1){
				Note spanel = jumps.get(0);

				spanel.focus();
				
				//他のFocusFrameについても，ズームする
				for(FocusFrame ff: FocusFrame.frames){
					ff.focus(spanel.penid);
				}
			} else {
				//複数登録されている：ズーム選択またはマージ
				SingleSelector4SeatmapController<Note> sel = new SingleSelector4SeatmapController<Note>(jumps, seatmapcontroller.frame, "Select Zoom Student (or Cancel to Merge)");
				sel.setVisible(true);
				Note selected = sel.selectedObj;
				if (selected == null){
					//マージ
				} else {
					selected.focus();
				}
			}
		}
	}

	public void setWorldRotation(double d) {
		double deg = (d/180)*Math.PI;
//		まず，紙を領域中央中心で回転させる
		cam.rotateInPlace(-cam.getTransform().getRotation());
		cam.rotateInPlace(deg);
	}

	public void clean() {
		jumps.clear();
		leaves.clear();
		for(PText pt: jumpT){
			pt.removeFromParent();
		}
		jumpT.clear();
		for(PText pt: leaveT){
			pt.removeFromParent();
		}
		leaveT.clear();
	}
}
