/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/07/18, 18:31
!  AUTHOR(S): KOGA, Junichiro
!  File : FBZ.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.fbz;

import java.awt.BorderLayout;
import java.awt.event.KeyListener;

import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3f;

import org.apache.log4j.Logger;

import ciss.phase_viewer.acviewer.ACVButtons;
import ciss.phase_viewer.acviewer.ACVMenuBar;
import ciss.phase_viewer.acviewer.BaseJ3DPanel;
import ciss.phase_viewer.acviewer.ChaseTransformGroup;
import ciss.phase_viewer.acviewer.J3DDataManager;
import ciss.phase_viewer.acviewer.PluginParser;
import ciss.phase_viewer.acviewer.keylistener.J3DKeyListener;
import ciss.phase_viewer.acviewer.mouselistener.MyMouseRotate;
import ciss.phase_viewer.acviewer.mouselistener.MyMouseTranslate;
import ciss.phase_viewer.acviewer.scenegraphelements.SceneGraphElement;
import ciss.phase_viewer.acviewer.scenegraphelements.SceneGraphElementCreator;
import ciss.phase_viewer.atomcoord.VolumetricData;

import com.sun.j3d.utils.behaviors.mouse.MouseWheelZoom;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;

/**
 * 第一ブリユアンゾーンを表示するモジュールの一番上のクラス
 * 
 * @author
 */
public class FBZ extends BaseJ3DPanel {
    private Logger logger = Logger.getLogger(FBZ.class.getName());
    private float[][] reciprocalLatticeVector = new float[3][3];
    private Transform3D translateorigin = new Transform3D();

    private FBZData data;

    /**
     * 逆格子ベクトルを引数に取るコンストラクター
     * 
     * @param vec
     *            逆格子ベクトル; 第一要素がb1,b2,b3のいずれかを表し, 第二要素がx,y,zを表す.
     */
    public FBZ(double[][] vec) {
        super("FBZ viewer", defaultSize);
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                reciprocalLatticeVector[i][j] = (float) vec[i][j];
            }
        }
        init();
        this.setJMenuBar(new ACVMenuBar(this));
        setVisible(true);
    }

    /**
     * @param data
     *            FBZ用データ
     */
    public FBZ(FBZData data) {
        super("FBZ viewer", defaultSize);
        this.data = data;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                reciprocalLatticeVector[i][j] = (float) data.reciprocalLattice[i][j];
            }
        }
        parentDir = data.baseDir;

        init();
        this.setJMenuBar(new ACVMenuBar(this));
        setVisible(true);
    }

    /**
     * 第一ブリユアンゾーン表示に必要と思しきデータを保持するオブジェクトを返す. nullの場合も有り得るので注意
     * 
     * @return 第一ブリユアンゾーン表示に必要な情報
     */
    public FBZData getFBZData() {
        return data;
    }

    public boolean supportsFrame() {
        return false;
    }

    /**
     * 逆格子ベクトルの配列を返す.
     * 
     * @return 逆格子ベクトル; 第0要素でb1,b2,b3を指定し, 第一要素でx,y,zを指定.
     */
    public float[][] getReciprocalLatticeVector() {
        return reciprocalLatticeVector;
    }

    protected String getExportFileNamePrefix() {
        return "FBZ";
    }

    protected String getPluginPath() {
        return PluginParser.PLUGIN_KSPACE;
    }

    private float scale = -100.f;
    private float scalescale = 1.2f;

    private WignerSeitzCell wscell;
    private ChaseTransformGroup rootTransform;

    /**
     * 一番上位のTransformGroupを返す. WignerSeitz cellやマウスbehaviorなんかが登録されている
     * 
     * @return
     */
    public TransformGroup getRootTransform() {
        return rootTransform;
    }

    public TransformGroup[] getRotatingTransform() {
        return new TransformGroup[] { rootTransform, objTransformAxis };
    }

    private TransformGroup objTransformAxis;
    private ACVButtons btns;

    private void init() {
        /* ちょっとスケール */
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (Math.abs(reciprocalLatticeVector[i][j]) > scale) {
                    scale = reciprocalLatticeVector[i][j];
                }
            }
        }
        scale *= scalescale;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                reciprocalLatticeVector[i][j] /= scale;
            }
        }

        /* 軸用 */
        translateorigin.set(new Vector3f(-0.8f, -0.7f, 0.0f));

        /* WSCellオブジェクトインスタンス化 */
        Point3f[] point3f = new Point3f[3];
        for (int i = 0; i < 3; i++) {
            point3f[i] = new Point3f(reciprocalLatticeVector[i]);
        }
        wscell = new WignerSeitzCell(point3f[0], point3f[1], point3f[2],
                parentDir, data.kpointGenerator);

        /* BranchGroupにシーングラフを足しこんでいく */
        rootBranch = new BranchGroup();
        rootBranch.setCapability(BranchGroup.ALLOW_DETACH);
        rootBranch.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
        rootBranch.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
        rootBranch.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);

        rootTransform = new FBZTransform(this);
        rootTransform.setCapability(TransformGroup.ALLOW_CHILDREN_READ);
        rootTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        rootTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
        rootTransform.setCapability(TransformGroup.ENABLE_PICK_REPORTING);
        rootTransform.setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);
        rootTransform.setCapability(TransformGroup.ALLOW_CHILDREN_WRITE);
        rootTransform.addChild(wscell);
        rootBranch.addChild(rootTransform);

        /* mouse behavior */
        MyMouseRotate myMouseRotate = null;
        if (BaseJ3DPanel.useJCanvas3D())
            myMouseRotate = new MyMouseRotate(getJCanvas3D());
        else
            myMouseRotate = new MyMouseRotate();

        myMouseRotate.setTransformGroup(rootTransform);
        myMouseRotate.setSchedulingBounds(new BoundingSphere());
        rootBranch.addChild(myMouseRotate);

        MyMouseTranslate myMouseTranslate = null;
        if (BaseJ3DPanel.useJCanvas3D())
            myMouseTranslate = new MyMouseTranslate(getJCanvas3D());
        else
            myMouseTranslate = new MyMouseTranslate();
        myMouseTranslate.setTransformGroup(rootTransform);
        myMouseTranslate.setSchedulingBounds(new BoundingSphere());
        rootBranch.addChild(myMouseTranslate);

        MouseZoom myMouseZoom = null;
        if (BaseJ3DPanel.useJCanvas3D())
            myMouseZoom = new MouseZoom(getJCanvas3D());
        else
            myMouseZoom = new MouseZoom();
        myMouseZoom.setTransformGroup(rootTransform);
        myMouseZoom.setSchedulingBounds(new BoundingSphere());
        rootBranch.addChild(myMouseZoom);

        MouseWheelZoom myMouseWheelZoom = null;
        if (BaseJ3DPanel.useJCanvas3D())
            myMouseWheelZoom = new MouseWheelZoom(getJCanvas3D());
        else
            myMouseWheelZoom = new MouseWheelZoom();
        myMouseWheelZoom.setTransformGroup(rootTransform);
        myMouseWheelZoom.setSchedulingBounds(new BoundingSphere());
        rootBranch.addChild(myMouseWheelZoom);

        /* この辺は流用 */
        J3DDataManager mACVD = new J3DDataManager();
        SceneGraphElementCreator creator = new SceneGraphElementCreator(mACVD,
                null);
        rootBranch.addChild(creator.getSceneGraphElement(SceneGraphElement.BG));
        rootBranch.addChild(creator
                .getSceneGraphElement(SceneGraphElement.LIGHT));

        if (mACVD.getAxis()) {
            /* x,y,z軸表示 */
            Transform3D translateorigin = new Transform3D();
            translateorigin.set(new Vector3f(-0.8f, -0.7f, 0.0f));
            objTransformAxis = creator
                    .getSceneGraphElement(SceneGraphElement.AXIS);
            objTransformAxis.setTransform(translateorigin);
            MyMouseRotate myMouseRotateAxis = new MyMouseRotate();
            myMouseRotateAxis.setTransformGroup(objTransformAxis);
            myMouseRotateAxis.setSchedulingBounds(new BoundingSphere());
            rootBranch.addChild(myMouseRotateAxis);
            rootBranch.addChild(objTransformAxis);
        }

        /* Picker登録 */
        SymmetryPointPicker picker = new SymmetryPointPicker(canvas3d,
                rootBranch, new BoundingSphere(new Point3d(0, 0, 0), 100),
                wscell);
        BranchGroup pickerBG = new BranchGroup();
        pickerBG.addChild(picker);
        rootBranch.addChild(pickerBG);

        /* キーリスナー登録 */
        KeyListener[] listeners = J3DKeyListener.getKeyListeners(this);
        for (int i = 0; i < listeners.length; i++)
            canvas3d.addKeyListener(listeners[i]);

        /* コンパイル */
        rootBranch.compile();

        /* GUIにのっける */
        simpleU.addBranchGraph(rootBranch);

        // getContentPane().setLayout(new BorderLayout());
        // getContentPane().add(jCanvas3D,BorderLayout.CENTER);

        // Panel panel = new Panel();
        // panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        if (btns == null) {
            btns = new ACVButtons(this);
            getContentPane().add(btns, BorderLayout.NORTH);
        }
        // panel.add(btns);
        // panel.add(canvas3d);

        // Container cont = getContentPane();
        // cont.setLayout(new BorderLayout());
        // cont.add(panel);
    }

    /**
     * Wigner-Seitz Cellを取得.
     * 
     * @return Wigner-Seitz Cellのオブジェクト
     */
    public WignerSeitzCell getFBZ() {
        return wscell;
    }

    public VolumetricData[] getAssociatedVolumetricData() {
        return getFBZData().eigenValues;
    }

}
