/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2005/10/21, 16:07
!  AUTHOR(S): KOGA, Junichiro
!  File : DynamicallyEditableTG.java
!  
!  Contact address :  Phase System Consortium
!                     E-mail: phase_system@nims.go.jp URL https://azuma.nims.go.jp
!
!
!   Since 2002, this program set had been intensively developed as a part of the following 
!  national projects supported by the Ministry of Education, Culture, Sports, Science and
!  Technology (MEXT) of Japan; "Frontier Simulation Software for Industrial Science
!  (FSIS)" from 2002 to 2005, "Revolutionary Simulation Software (RSS21)" from 2006 to
!  2008. "Research and Development of Innovative Simulation Software (RISS)" from 2008
!  to 2013. These projects is lead by the Center for Research on Innovative Simulation 
!  Software (CISS), the Institute of Industrial Science (IIS), the University of Tokyo.
!   Since 2013, this program set has been further developed centering on PHASE System
!  Consortium. 
!   The activity of development of this program set has been supervised by Takahisa Ohno.
!
!=======================================================================
 */

package ciss.phase_viewer.acviewer.scenegraphelements;

import java.awt.event.InputEvent;

import javax.media.j3d.BranchGroup;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Matrix3d;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;

import org.apache.log4j.Logger;

/**
 * 'dynamically editable'なシーングラフエレメント(原子やボンド)はこっちを使うべき? TransformGroupの場合こっち.
 * 
 * @author
 */
public abstract class DynamicallyEditableTG extends SceneGraphElement implements
        DynamicallyEditable {
    private Logger logger = Logger.getLogger(DynamicallyEditableTG.class
            .getName());

    /** Creates a new instance of DynamicallyEditable */
    public DynamicallyEditableTG() {
        super();
    }

    /**
     * override this method if you want to make this object
     * 'non-dynamically-editable'
     * 
     * @return true if the scenegraph element created from this class is
     *         'dynamically-editable'
     */
    protected boolean isDynamicallyEditable() {
        return true;
    }

    /**
     * override this method to return false if you don't need initizalization.
     * 
     * @return false if no initialization should be performed
     */
    protected boolean initializationNecessary() {
        return true;
    }

    /**
     * override this method to return false if no action is needed during the
     * 'dynamical edit' procedure
     * 
     * @return false if no intermediate operations are necessary.
     */
    protected boolean intermediateStateNecessary() {
        return true;
    }

    /**
     * override this method to return false if no finallization is needed at the
     * end of the 'dynamical edit' procedure.
     * 
     * @return false if no finallization is needed.
     */
    protected boolean finalizationNecessary() {
        return true;
    }

    /**
     * 編集作業の初期化を行う.
     * 
     * @param parent
     *            編集操作の親オブジェクト.
     */
    public void dynamicallyEditInitialize(TransformGroup parent) {
        if (!isDynamicallyEditable() || !initializationNecessary()) {
            return;
        }
    }

    /**
     * 編集中の, 途中の操作を行う(例: マウスドラッグ中)
     * 
     * @param diff
     *            前回からの変更
     * @param parent
     *            編集操作の親オブジェクト.
     */
    public void dynamicallyEditIntermediateState(Transform3D diff,
            TransformGroup parent, InputEvent event) {
        if (!isDynamicallyEditable() || !intermediateStateNecessary()) {
            return;
        }

        logger.debug("dynamically editing scene (intermediate state) ");
        preIntermediateState(diff, parent, event);
        Transform3D parentTransform = new Transform3D();
        parent.getTransform(parentTransform);
        Vector3d parentTranslate = new Vector3d();
        Matrix3d parentRotate = new Matrix3d();
        parentTransform.get(parentRotate, parentTranslate);
        parentTransform.invert();

        Vector3d diffTranslate = new Vector3d();
        Matrix3d diffRotate = new Matrix3d();
        diff.get(diffRotate, diffTranslate);

        Transform3D bufferTransform = new Transform3D();
        transformBuffer.getTransform(bufferTransform);

        Vector3d bufferTranslate = new Vector3d();
        Matrix3d bufferRotate = new Matrix3d();
        bufferTransform.get(bufferRotate, bufferTranslate);

        Point3d point = new Point3d();
        point.x = diffTranslate.x + parentTranslate.x;
        point.y = diffTranslate.y + parentTranslate.y;
        point.z = diffTranslate.z + parentTranslate.z;
        parentTransform.transform(point);

        bufferTranslate.x = bufferTranslate.x + point.x;
        bufferTranslate.y = bufferTranslate.y + point.y;
        bufferTranslate.z = bufferTranslate.z + point.z;

        bufferTransform.setTranslation(bufferTranslate);
        bufferTransform.setRotation(bufferRotate);

        transformBuffer.setTransform(bufferTransform);
        // logger.debug("bufferTranslate: "+bufferTranslate+" buffer: "+buffer.getClass().getName());
        // logger.debug("bufferRotate: "+bufferRotate);
        // logger.debug("buffer: "+buffer);

        buffer.detach();
        parent.addChild(buffer);

        postIntermediateState(diff, parent, event);
    }

    /**
     * called every time after dynamicalEditIntermediateState. override this
     * method to perform any post-processing.
     */
    protected void postIntermediateState(Transform3D diff,
            TransformGroup parent, InputEvent event) {
    }

    /**
     * called every time before dynamicalEditIntermediateState. override this
     * method to perform any pre-processing.
     */
    protected void preIntermediateState(Transform3D diff,
            TransformGroup parent, InputEvent event) {
    }

    /**
     * 編集操作確定後に呼ばれる.
     * 
     * @param parent
     *            編集操作の親オブジェクト.
     */
    public void dynamicallyEditFinalize(TransformGroup parent) {
        if (!isDynamicallyEditable() || !finalizationNecessary()) {
            return;
        }
    }

    protected TransformGroup transformBuffer;

    public TransformGroup getTransformBuffer() {
        return transformBuffer;
    }

    protected BranchGroup buffer;

    public BranchGroup getBuffer() {
        return buffer;
    }

    public abstract void createBuffer();
}
