package j3deditor.bin.editor;

import j3deditor.bin.components.ButtonPanelLayout;
import j3deditor.bin.components.ComplexButton;
import j3deditor.bin.hierarchy.util.HierarchyEvent;
import j3deditor.bin.hierarchy.util.HierarchyEventListener;
import j3deditor.bin.components.SimpleButton;
import j3deditor.bin.components.SimpleButtonEvent;
import j3deditor.bin.components.SimpleButtonListener;

import j3deditor.bin.hierarchy.HierarchyNode;
import j3deditor.bin.hierarchy.J3DeObject;
import j3deditor.bin.hierarchy.J3DeScene;

import j3deditor.bin.util.Utilities;

import java.awt.Container;

import java.awt.Rectangle;

import javax.swing.JPanel;


/**
 * Contains buttons for transforming objects.
 *
 * @author Risto Seene
 */
public class TransformPanel extends JPanel implements SimpleButtonListener{


	/** the scene which objects this panel transforms */
	private J3DeScene node;

	/** listener that listens hierarchy manipulation events */
	private HierarchyEventListener listener;

	/** specifies if objects are transformed by their local coordinates or not */
	private boolean isLocal = false;


	/** groups all translation buttons to one complex button */
	private ComplexButton move;

	/** manipulates object position on X-axis */
	private SimpleButton moveX;

	/** manipulates object position on Y-axis */
	private SimpleButton moveY;

	/** manipulates object position on Z-axis */
	private SimpleButton moveZ;


	/** groups all resize buttons to one complex button */
	private ComplexButton scale;

	/** manipulates object scale on X-axis */
	private SimpleButton scaleX;

	/** manipulates object scale on Y-axis */
	private SimpleButton scaleY;

	/** manipulates object scale on Z-axis */
	private SimpleButton scaleZ;

	/** manipulates object scale on all axes */
	private SimpleButton scaleA;


	/** groups all rotation buttons to one complex button */
	private ComplexButton rotate;

	/** manipulates object angle around X-axis */
	private SimpleButton rotX;

	/** manipulates object angle around Y-axis */
	private SimpleButton rotY;

	/** manipulates object angle around Z-axis */
	private SimpleButton rotZ;


	/** sets the <code>isLocal</code> to <code>true</code> */
	private SimpleButton local;

	/** sets the <code>isLocal</code> to <code>false</code> */
	private SimpleButton global;


	/** infopanel that shows active button info */
	private InfoPanel infoPanel = null;


	/**
	 * Creates an instance of <code>TransformPanel</code>.
	 *
	 * @param node
	 *	the scene which objects this panel manipulates
	 */
	public TransformPanel(J3DeScene node){
		this.node = node;

		setOpaque(false);
		setLayout(new ButtonPanelLayout(60, 60, 5, ButtonPanelLayout.HORIZONTAL, ButtonPanelLayout.POSITIVE));

		initMove();
		initScale();
		initRot();

		initLocal();
	}


	/**
	 * Initializes translate buttons
	 */
	private void initMove(){
		move = new ComplexButton();
		move.setImage("ob_move.png", ComplexButton.NORMAL_IMAGE);
		move.setImage("ob_move_off.png", ComplexButton.DISABLED_IMAGE);

		moveX = new SimpleButton(SimpleButton.HORIZONTAL_DRAG);
		moveX.setButtonInfo(Utilities.translator.translate(this.getClass(), "moveX"));
		moveX.addSimpleButtonListener(this);
		move.addHotSpot(moveX, new Rectangle(2, 33, 28, 17), "ob_move_x1.png", "ob_move_x2.png");

		moveY = new SimpleButton(SimpleButton.VERTICAL_DRAG);
		moveY.setButtonInfo(Utilities.translator.translate(this.getClass(), "moveY"));
		moveY.addSimpleButtonListener(this);
		move.addHotSpot(moveY, new Rectangle(21, 2, 17, 29), "ob_move_y1.png", "ob_move_y2.png");

		moveZ = new SimpleButton(SimpleButton.HORIZONTAL_DRAG);
		moveZ.setButtonInfo(Utilities.translator.translate(this.getClass(), "moveZ"));
		moveZ.addSimpleButtonListener(this);
		move.addHotSpot(moveZ, new Rectangle(31, 33, 28, 16), "ob_move_z1.png", "ob_move_z2.png");

		add(move);
	}


	/**
	 * Initializes resize buttons
	 */
	private void initScale(){
		scale = new ComplexButton();
		scale.setImage("ob_scale.png", ComplexButton.NORMAL_IMAGE);
		scale.setImage("ob_scale_off.png", ComplexButton.DISABLED_IMAGE);

		scaleX = new SimpleButton(SimpleButton.HORIZONTAL_DRAG);
		scaleX.setButtonInfo(Utilities.translator.translate(this.getClass(), "scaleX"));
		scaleX.addSimpleButtonListener(this);
		scale.addHotSpot(scaleX, new Rectangle(2, 33, 19, 18), "ob_scale_x1.png", "ob_scale_x2.png");

		scaleY = new SimpleButton(SimpleButton.VERTICAL_DRAG);
		scaleY.setButtonInfo(Utilities.translator.translate(this.getClass(), "scaleY"));
		scaleY.addSimpleButtonListener(this);
		scale.addHotSpot(scaleY, new Rectangle(21, 2, 17, 24), "ob_scale_y1.png", "ob_scale_y2.png");

		scaleZ = new SimpleButton(SimpleButton.HORIZONTAL_DRAG);
		scaleZ.setButtonInfo(Utilities.translator.translate(this.getClass(), "scaleZ"));
		scaleZ.addSimpleButtonListener(this);
		scale.addHotSpot(scaleZ, new Rectangle(37, 33, 23, 15), "ob_scale_z1.png", "ob_scale_z2.png");

		scaleA = new SimpleButton(SimpleButton.HORIZONTAL_DRAG);
		scaleA.setButtonInfo(Utilities.translator.translate(this.getClass(), "scaleA"));
		scaleA.addSimpleButtonListener(this);
		scale.addHotSpot(scaleA, new Rectangle(21, 26, 17, 18), "ob_scale_all1.png", "ob_scale_all2.png");

		add(scale);
	}


	/**
	 * Initializes rotation buttons
	 */
	private void initRot(){
		rotate = new ComplexButton();
		rotate.setImage("ob_rot.png", ComplexButton.NORMAL_IMAGE);
		rotate.setImage("ob_rot_off.png", ComplexButton.DISABLED_IMAGE);

		rotX = new SimpleButton(SimpleButton.VERTICAL_DRAG);
		rotX.setButtonInfo(Utilities.translator.translate(this.getClass(), "rotX"));
		rotX.addSimpleButtonListener(this);
		rotate.addHotSpot(rotX, new Rectangle(30, 4, 25, 31), "ob_rot_x1.png", "ob_rot_x2.png");

		rotY = new SimpleButton(SimpleButton.HORIZONTAL_DRAG);
		rotY.setButtonInfo(Utilities.translator.translate(this.getClass(), "rotY"));
		rotY.addSimpleButtonListener(this);
		rotate.addHotSpot(rotY, new Rectangle(8, 36, 47, 14), "ob_rot_y1.png", "ob_rot_y2.png");

		rotZ = new SimpleButton(SimpleButton.VERTICAL_DRAG);
		rotZ.setButtonInfo(Utilities.translator.translate(this.getClass(), "rotZ"));
		rotZ.addSimpleButtonListener(this);
		rotate.addHotSpot(rotZ, new Rectangle(7, 4, 22, 31), "ob_rot_z1.png", "ob_rot_z2.png");

		add(rotate);
	}


	/**
	 * Initializes local/global buttons
	 */
	private void initLocal(){
		local = new SimpleButton(SimpleButton.CLICK);
		local.setButtonInfo(Utilities.translator.translate(this.getClass(), "local"));
		local.setImage("local.png", SimpleButton.NORMAL_IMAGE);
		local.setImage("local_1.png", SimpleButton.MOUSE_OVER_IMAGE);
		local.setImage("local_2.png", SimpleButton.MOUSE_DOWN_IMAGE);
		local.addSimpleButtonListener(this);
	          local.setBounds(5, 35, 20, 20);

		global = new SimpleButton(SimpleButton.CLICK);
		global.setButtonInfo(Utilities.translator.translate(this.getClass(), "global"));
		global.setImage("global.png", SimpleButton.NORMAL_IMAGE);
		global.setImage("global_1.png", SimpleButton.MOUSE_OVER_IMAGE);
		global.setImage("global_2.png", SimpleButton.MOUSE_DOWN_IMAGE);
		global.addSimpleButtonListener(this);
	          global.setBounds(5, 35, 20, 20);

		JPanel localPanel = new JPanel();
		localPanel.setLayout(null);
		localPanel.setOpaque(false);
		localPanel.add(global);
		add(localPanel);
	}


	/**
	 * Sets the listener this panel can send hierarchy manipulation events to.
	 *
	 * @param listener
	 *	object which listens hierarchy manipulation events sent by this panel
	 */
	public void setEditorEventListener(HierarchyEventListener listener){
		this.listener = listener;
	}


	/**
	 * Listens the mouse click events sent by <code>SimpleButton</code> objects.
	 *
	 * @param e
	 *	event sent by <code>SimpleButton</code>
	 */
	public void buttonClicked(SimpleButtonEvent e){
		if(e.getSource() == local){
			Container parent = local.getParent();
			parent.remove(local);
			parent.add(global);
			parent.validate();
			global.mouseEntered(null);
			isLocal = false;
		} else if(e.getSource() == global){
			Container parent = global.getParent();
			parent.remove(global);
			parent.add(local);
			parent.validate();
			local.mouseEntered(null);
			isLocal = true;
		}
	}


	/**
	 * Listens the mouse drag events sent by <code>SimpleButton</code> objects.
	 *
	 * @param e
	 *	event sent by <code>SimpleButton</code>
	 */
	public void buttonDragged(SimpleButtonEvent e){
		HierarchyNode[] objects = node.getSelectedObjects();
		for(int i = 0; i < objects.length; i++){
			if(objects[i] instanceof J3DeObject){
				if(e.getSource() == moveX){
					((J3DeObject)objects[i]).translateX(-0.1f * e.getX(), isLocal);
				} else if(e.getSource() == moveY){
					((J3DeObject)objects[i]).translateY(0.1f * e.getY(), isLocal);
				} else if(e.getSource() == moveZ){
					((J3DeObject)objects[i]).translateZ(-0.1f * e.getX(), isLocal);
				}

				else if(e.getSource() == scaleX){
					((J3DeObject)objects[i]).scaleX(0.01f * e.getX(), isLocal);
				} else if(e.getSource() == scaleY){
					((J3DeObject)objects[i]).scaleY(0.01f * e.getY(), isLocal);
				} else if(e.getSource() == scaleZ){
					((J3DeObject)objects[i]).scaleZ(-0.01f * e.getX(), isLocal);
				} else if(e.getSource() == scaleA){
					((J3DeObject)objects[i]).scaleAll(-0.01f * e.getX());
				}

				else if(e.getSource() == rotX){
					((J3DeObject)objects[i]).rotateX(-0.5f * e.getY(), isLocal);
				} else if(e.getSource() == rotY){
					((J3DeObject)objects[i]).rotateY(-0.5f * e.getX(), isLocal);
				} else if(e.getSource() == rotZ){
					((J3DeObject)objects[i]).rotateZ(-0.5f * e.getY(), isLocal);
				}
			}
		}
	}


	/**
	 * Listens the mouse enter events sent by <code>SimpleButton</code> objects.
	 *
	 * @param e
	 *	event sent by <code>SimpleButton</code>
	 */
	public void buttonEntered(SimpleButtonEvent e){
		if(infoPanel != null){
			infoPanel.setInfo(e.getSource().getButtonInfo());
		}
	}


	/**
	 * Listens the mouse exit events sent by <code>SimpleButton</code> objects.
	 *
	 * @param e
	 *	event sent by <code>SimpleButton</code>
	 */
	public void buttonExited(SimpleButtonEvent e){
		if(infoPanel != null){
			infoPanel.setInfo(null, null);
		}
	}


	/**
	 * Listens the mouse drag events sent by <code>SimpleButton</code> objects.
	 *
	 * @param e
	 *	event sent by <code>SimpleButton</code>
	 */
	public void buttonDragEnded(SimpleButtonEvent e){
		if(listener != null){
			listener.hierarchyEventOccured(new HierarchyEvent(this, HierarchyEvent.OBJECT_TRANSFORMATION));
		}
	}


	/**
	 * Specifies if the current transformation mode is local or global.
	 *
	 * @param isLocal
	 *	if <code>true</code> transformation mode will be set to <code>local</code>,
	 *	otherwise <code>global</code>
	 */
	public void setTransformMode(boolean isLocal){
		this.isLocal = isLocal;
	}


	/**
	 * Sets the infopanel which shows information about the buttons of this panel.
	 *
	 * @param infoPanel
	 *	infopanel which shows information about the buttons of this panel
	 */
	public void setInfoListener(InfoPanel infoPanel){
		this.infoPanel = infoPanel;
	}


	/**
	 * Enables/disables the buttons of this panel.
	 *
	 * @param state
	 *	if <code>true</code> enables the buttons of this panel,
	 *	otherwise disables
	 */
	public void setEnabled(boolean state){
		move.setEnabled(state);
		scale.setEnabled(state);
		rotate.setEnabled(state);
	}

}
