/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on ----
!  AUTHOR(S): KOGA, Junichiro
!  File : BondObject.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.bond;

import javax.media.j3d.Appearance;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.LineAttributes;
import javax.media.j3d.Material;
import javax.media.j3d.TransparencyAttributes;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;

import org.apache.log4j.Logger;

import ciss.phase_viewer.acviewer.scenegraphelements.CylinderCreatorTG;
import ciss.phase_viewer.acviewer.scenegraphelements.DynamicallyEditableBG;
import ciss.phase_viewer.acviewer.scenegraphelements.SceneGraphElement;
import ciss.phase_viewer.acviewer.scenegraphelements.atom.AtomObject;
import ciss.phase_viewer.settings.GlobalProperties;
import ciss.phase_viewer.settings.PropertiesManager;

public class BondObject extends DynamicallyEditableBG {
    private Logger logger = Logger.getLogger(BondObject.class.getName());
    public static int COVBOND = 0;
    public static int HBOND = 1;

    private int mode = COVBOND;

    private double[] nearestNeighbor;
    private float[] bondColor;
    private int numNodes = 30;
    private double bondWidth = 0.1d;

    private CylinderCreatorTG cylindercreate;
    private BranchGroup bondBranch;

    private int index = 0;

    private GlobalProperties gp = PropertiesManager
            .getGlobalProperties(PropertiesManager.PROPERTIES_ACV);

    public BondObject(double[] nearestNeighbor) {
        super();
        this.nearestNeighbor = nearestNeighbor;
        bondBranch = new BranchGroup();
        bondBranch.setCapability(BranchGroup.ALLOW_DETACH);
    }

    private AtomObject atom1;
    private AtomObject atom2;

    public void setAssociatedAtoms(AtomObject atom1, AtomObject atom2) {
        this.atom1 = atom1;
        this.atom2 = atom2;
    }

    public void setMode(int mode) {
        this.mode = mode;
        if (this.mode == HBOND) {
            try {
                String[] col = gp.getProperty("hbond_color").split(",");
                bondColor = new float[] { Float.parseFloat(col[0]),
                        Float.parseFloat(col[1]), Float.parseFloat(col[2]) };
                String width = gp.getProperty("hbond_width");
                bondWidth = Double.parseDouble(width)
                        * 2.2f
                        * mACVD.getScaleAtom()
                        / (float) (Math.pow((float) (mCD.getNumAt()),
                                1.0f / 3.0f));
            } catch (Exception exc) {
            }
        }
    }

    public int getType() {
        return SceneGraphElement.BOND;
    }

    private Point3d Cyl1Now;
    private Point3d Cyl2Now;
    private int cyl;
    private int linePattern;

    public void create() {
        cyl = CylinderCreatorTG.CYLINDER;
        linePattern = LineAttributes.PATTERN_SOLID;
        if (mode == COVBOND) {
            if (mACVD.getUseWireForBond())
                cyl = CylinderCreatorTG.WIRE;
        }

        if (mode == HBOND) {
            cyl = CylinderCreatorTG.WIRE;
            if (gp.getProperty("hbond_type").equals("dashed"))
                linePattern = LineAttributes.PATTERN_DASH;
            if (gp.getProperty("hbond_type").equals("dotted"))
                linePattern = LineAttributes.PATTERN_DOT;
        }

        Cyl1Now = new Point3d(nearestNeighbor[0], nearestNeighbor[1],
                nearestNeighbor[2]);
        Cyl2Now = new Point3d(nearestNeighbor[3], nearestNeighbor[4],
                nearestNeighbor[5]);

        cylindercreate = new CylinderCreatorTG(Cyl1Now, Cyl2Now, bondWidth,
                new Color3f(bondColor), numNodes, cyl, linePattern);

        BranchGroup group = new BranchGroup();
        group.setCapability(BranchGroup.ALLOW_DETACH);
        group.addChild(cylindercreate);
        this.addChild(group);
    }

    public BondObject getCopy() {
        nullifyBuffer();
        if (atom1 == null || atom2 == null)
            return null;
        if (!(atom1.isSelected() && atom2.isSelected())) {
            return null;
        }
        double[] neib = new double[6];
        double[] d1 = atom1.getPosDouble();
        double[] d2 = atom2.getPosDouble();
        neib[0] = d1[0];
        neib[1] = d1[1];
        neib[2] = d1[2];
        neib[3] = d2[0];
        neib[4] = d2[1];
        neib[5] = d2[2];
        nearestNeighbor = neib;

        double[] nn = new double[nearestNeighbor.length];
        for (int i = 0; i < nearestNeighbor.length; i++) {
            nn[i] = nearestNeighbor[i];
        }
        BondObject copy = new BondObject(nn);

        Appearance app = new Appearance();
        Material material = new Material();
        material.setDiffuseColor(new Color3f(bondColor));
        material.setShininess(120.0f);
        app.setMaterial(material);

        float transparency = 0.6f;
        try {
            transparency = Float.parseFloat(gp
                    .getProperty("transparency_of_temporary_atom"));
        } catch (Exception exc) {
        }
        TransparencyAttributes ta = new TransparencyAttributes(
                TransparencyAttributes.BLENDED, 0.0f);
        ta.setTransparency(transparency);
        app.setTransparencyAttributes(ta);

        Point3d Cyl1 = new Point3d(nearestNeighbor[0], nearestNeighbor[1],
                nearestNeighbor[2]);
        Point3d Cyl2 = new Point3d(nearestNeighbor[3], nearestNeighbor[4],
                nearestNeighbor[5]);
        // transformBuffer = new
        // CylinderCreatorTG(Cyl1,Cyl2,bondWidth,app,numNodes);
        transformBuffer = new CylinderCreatorTG(Cyl1Now, Cyl2Now, bondWidth,
                new Color3f(bondColor), numNodes, cyl, linePattern);
        copy.addChild(transformBuffer);
        copy.setIndex(index);

        return copy;
    }

    protected boolean intermediateStateNecessary() {
        return buffer != null && transformBuffer != null;
    }

    public void recreate(double[] nearestNeighbor) {
        logger.debug("recreating bond");
        if (cylindercreate == null) {
            return;
        }
        Point3d Cyl1 = new Point3d(nearestNeighbor[0], nearestNeighbor[1],
                nearestNeighbor[2]);
        Point3d Cyl2 = new Point3d(nearestNeighbor[3], nearestNeighbor[4],
                nearestNeighbor[5]);
        // if ( Cyl1Now.epsilonEquals(Cyl1,0.00005) &&
        // Cyl2Now.epsilonEquals(Cyl2,0.00005) ) {
        // return;
        // }
        // this.nearestNeighbor = nearestNeighbor;
        // removeAllChildren();
        // create();

        // Point3d Cyl1 = new Point3d( nearestNeighbor[0], nearestNeighbor[1],
        // nearestNeighbor[2]);
        // Point3d Cyl2 = new Point3d( nearestNeighbor[3], nearestNeighbor[4],
        // nearestNeighbor[5]);
        if (mCD.forceUpdate()) {
            logger.debug("use wire for bond: " + mACVD.getUseWireForBond());
            if (mACVD.getUseWireForBond()) {
                cylindercreate.setMode(CylinderCreatorTG.WIRE);
            } else {
                cylindercreate.setMode(CylinderCreatorTG.CYLINDER);
            }
            cylindercreate.setRadius(mACVD.getBondWidth());
            cylindercreate.setColor(new Color3f(mACVD.getBondColor()));
        }
        cylindercreate.recreate(Cyl1, Cyl2, mCD.forceUpdate());
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public int getIndex() {
        return this.index;
    }

    public void setBondColor(float[] bondColor) {
        this.bondColor = bondColor;
    }

    public void setNumNodes(int numNodes) {
        this.numNodes = numNodes;
    }

    public void setBondWidth(double bondWidth) {
        this.bondWidth = bondWidth;
    }

    public void createBuffer() {
        buffer = getCopy();
    }

    public void nullifyBuffer() {
        buffer = null;
        transformBuffer = null;
    }

}
