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

import java.awt.Font;

import javax.vecmath.Color3f;

import org.apache.log4j.Logger;

import ciss.phase_viewer.common.ElementDef;
import ciss.phase_viewer.common.ElementInfo;
import ciss.phase_viewer.settings.GlobalProperties;
import ciss.phase_viewer.settings.PropertiesManager;

public class J3DDataManager {
    private Logger logger = Logger.getLogger(J3DDataManager.class.getName());
    public static final int DARKER = 0; /*
                                         * !< mobile原子の表示に関わるint値. この値を指定すると,
                                         * mobile原子は``暗く''表示される.
                                         */
    public static final int BRIGHTER = 1; /*
                                           * !< mobile原子の表示に関わるint値. この値を指定すると,
                                           * mobile原子は``明るく''表示される
                                           */

    public static String[] ATOM_RENDERING_METHODS = { "sphere",
            "filled_circle", "null" };
    private String atomRenderingMethod = ATOM_RENDERING_METHODS[0];

    public static int EDGE_OF_CELL = 0;
    public static int CENTER_OF_CELL = 1;

    private double bondfactor;
    private float bgr;
    private float bgg;
    private float bgb;

    private int numnodes;
    private int numnodesbond;
    private float[] bondcolor;
    private double bondwidth;
    private float[] bgcolor;
    private float scale;
    private float scaleatom;

    private boolean drawcell;
    private float cellwidth;
    private int numnodescell;
    private float cellr;
    private float cellg;
    private float cellb;
    private float[] cellcolor;

    private boolean gettext;
    private boolean legend;
    private boolean axis;
    private String[] label;

    private boolean bmobile;
    private int labelOffset;

    private GlobalProperties propManager;

    private int mobilityDisplayMode;

    private Font font;
    private Color3f fontColor = new Color3f(0, 0, 0);

    private J3DPanel mp;

    private int shiftPolicy;

    private boolean useWireForCell = false;

    /**
     * デフォルト値をセットする. また, 原子配置ビューアーの設定をファイルから読み込んだりもする.
     * 
     * @param propManager
     *            原子配置ビューアーの設定が記述されているacvprefsという設定ファイル
     *            (通常$HOME/.phase-viewer/acvprefs)の情報を読み込む/書き出すオブジェクト
     */
    public J3DDataManager() {
        this.propManager = PropertiesManager
                .getGlobalProperties(PropertiesManager.PROPERTIES_ACV);
        setBondFactor(1.06d);
        setBgColor(0.6f, 0.6f, 0.6f);
        setBondColor(0.0f, 0.2f, 0.2f);
        setBondWidth(0.01d);
        setScale(1.0f);
        setNumNodesAtom(10);
        setNumNodesBond(10);
        setScaleAtom(1.0f);
        setCellWidth(0.005f);
        setNumNodesCell(10);
        setCellColor(1.0f, 1.0f, 1.0f);
        setDrawCell(false);
        setText(false);
        setMobile(false);
        setLabelOffset(3);
        setMobilityDisplayMode(DARKER);
        setFont(new Font("Helvetica", Font.PLAIN, 18));

        readACVPrefs();
        readElementInfo();
        logger.debug("initialized J3DDataManager.");
    }

    public void setAtomRenderingMethod(String method) {
        this.atomRenderingMethod = method;
    }

    public String getAtomRenderingMethod() {
        return this.atomRenderingMethod;
    }

    // set Default values
    public void setDefaults() {
        setBondFactor(1.06d);
        setBgColor(0.6f, 0.6f, 0.6f);
        setScale(1.0f);
    }

    // set scale for the system
    public void setScale(float scale) {
        this.scale = scale;
    }

    public void setFont(Font font) {
        this.font = font;
    }

    public void setFontColor(Color3f fontColor) {
        this.fontColor = fontColor;
    }

    public Font getFont() {
        if (font == null) {
            font = new Font("Helvetica", Font.PLAIN, 18);
        }
        return this.font;
    }

    public Color3f getFontColor() {
        if (fontColor == null)
            fontColor = new Color3f(0.0f, 0.0f, 0.0f);
        return this.fontColor;
    }

    public float getScale() {
        return (this.scale);
    }

    // set scaleatom
    public void setScaleAtom(float scaleatom) {
        this.scaleatom = scaleatom;
    }

    public float getScaleAtom() {
        return (this.scaleatom);
    }

    // bg color
    public void setBgColor(float bgr, float bgg, float bgb) {
        this.bgr = bgr;
        this.bgg = bgg;
        this.bgb = bgb;
        bgcolor = new float[3];

        bgcolor[0] = this.bgr;
        bgcolor[1] = this.bgg;
        bgcolor[2] = this.bgb;
    }

    public float[] getBgColor() {
        return (this.bgcolor);
    }

    // bond factor
    public void setBondFactor(double bondfactor) {
        this.bondfactor = bondfactor;
    }

    public double getBondFactor() {
        return (this.bondfactor);
    }

    public int getNumEl() {
        return einfo.getElementDef().length;
    }

    // element
    public void setElement(String element, int i) {
        einfo.getElementDef()[i].setSymbol(element);
    }

    public String[] getElement() {
        String[] ret = new String[einfo.getElementDef().length];
        for (int i = 0; i < ret.length; i++) {
            ret[i] = einfo.getElementDef()[i].getSymbol();
        }
        return ret;
    }

    private boolean wireForBond = false;

    public int getShiftPolicy() {
        return shiftPolicy;
    }

    public void setUseWireForBond(boolean wireForBond) {
        this.wireForBond = wireForBond;
    }

    public boolean getUseWireForBond() {
        return wireForBond;
    }

    // cov.radius
    public void setCovRad(double covrad, int i) {
        einfo.getElementDef()[i].setCovalentRadius(covrad);
    }

    public double[] getCovRad() {
        double[] ret = new double[einfo.getElementDef().length];
        for (int i = 0; i < ret.length; i++) {
            ret[i] = einfo.getElementDef()[i].getCovalentRadius();
        }
        return ret;
    }

    // radius
    public void setRad(float rad, int i) {
        einfo.getElementDef()[i].setRadius(rad);
    }

    public float[] getRad() {
        float[] ret = new float[einfo.getElementDef().length];
        for (int i = 0; i < ret.length; i++) {
            ret[i] = einfo.getElementDef()[i].getRadius();
        }
        return ret;
    }

    // atom color
    public void setColor(float[] color, int i) {
        einfo.getElementDef()[i].setColor(color);
    }

    public float[][] getColor() {
        float[][] ret = new float[einfo.getElementDef().length][3];
        for (int i = 0; i < ret.length; i++) {
            ret[i] = einfo.getElementDef()[i].getColor();
        }
        return ret;
    }

    // number of nodes for atom
    public void setNumNodesAtom(int numnodes) {
        this.numnodes = numnodes;
    }

    public int getNumNodesAtom() {
        return (this.numnodes);
    }

    // number of nodes for bond
    public void setNumNodesBond(int numnodesbond) {
        this.numnodesbond = numnodesbond;
    }

    public int getNumNodesBond() {
        return (this.numnodesbond);
    }

    // bond color
    public void setBondColor(float bndcolorr, float bndcolorb, float bndcolorg) {
        bondcolor = new float[3];
        this.bondcolor[0] = bndcolorr;
        this.bondcolor[1] = bndcolorb;
        this.bondcolor[2] = bndcolorg;
    }

    public float[] getBondColor() {
        return (this.bondcolor);
    }

    // bond width
    public void setBondWidth(double bondwidth) {
        this.bondwidth = bondwidth;
    }

    public double getBondWidth() {
        return (bondwidth);
    }

    // draw cell or not
    public void setDrawCell(boolean drawcell) {
        this.drawcell = drawcell;
    }

    public boolean getDrawCell() {
        return (this.drawcell);
    }

    // num. of nodes for cell
    public void setNumNodesCell(int numnodescell) {
        this.numnodescell = numnodescell;
    }

    public int getNumNodesCell() {
        return (this.numnodescell);
    }

    // cellwidth
    public void setCellWidth(float cellwidth) {
        this.cellwidth = cellwidth;
    }

    public float getCellWidth() {
        return (this.cellwidth);
    }

    // cellcolor
    public void setCellColor(float cellr, float cellg, float cellb) {
        cellcolor = new float[3];
        this.cellcolor[0] = cellr;
        this.cellcolor[1] = cellg;
        this.cellcolor[2] = cellb;
    }

    public float[] getCellColor() {
        return (this.cellcolor);
    }

    // set text
    public void setText(boolean gettext) {
        this.gettext = gettext;
    }

    public boolean getText() {
        return (this.gettext);
    }

    // label
    public void setLabel(String[] label) {
        this.label = label;
    }

    public String[] getLabel() {
        return (this.label);
    }

    // legend
    public void setLegend(boolean legend) {
        this.legend = legend;
    }

    public boolean getLegend() {
        return (this.legend);
    }

    // axis
    public void setAxis(boolean axis) {
        this.axis = axis;
    }

    public boolean getAxis() {
        return (this.axis);
    }

    // mobility
    public void setMobile(boolean bmobile) {
        this.bmobile = bmobile;
    }

    public boolean getMobile() {
        return (this.bmobile);
    }

    public void setMobilityDisplayMode(int mobilityDisplayMode) {
        this.mobilityDisplayMode = mobilityDisplayMode;
    }

    public int getMobilityDisplayMode() {
        return this.mobilityDisplayMode;
    }

    public void setLabelOffset(int labelOffset) {
        this.labelOffset = labelOffset;
    }

    public int getLabelOffset() {
        return this.labelOffset;
    }

    public void setUseWireForCell(boolean wc) {
        this.useWireForCell = wc;
    }

    public boolean getUseWireForCell() {
        return this.useWireForCell;
    }

    /**
     * 設定ファイルから原子配置表示に関わる設定を読み込む.
     */
    private void readACVPrefs() {
        setBondFactor(Double.parseDouble(propManager.getProperty("bondfactor")
                .trim()));
        setBgColor(
                Float.parseFloat(propManager.getProperty("bgcolor_r").trim()),
                Float.parseFloat(propManager.getProperty("bgcolor_g").trim()),
                Float.parseFloat(propManager.getProperty("bgcolor_b").trim()));
        setBondColor(
                Float.parseFloat(propManager.getProperty("bondcolor_r").trim()),
                Float.parseFloat(propManager.getProperty("bondcolor_g").trim()),
                Float.parseFloat(propManager.getProperty("bondcolor_b").trim()));
        setBondWidth(Double.parseDouble(propManager.getProperty("bondwidth")
                .trim()));
        setUseWireForBond(new Boolean(propManager.getProperty("usewireforbond")
                .trim()).booleanValue());
        setUseWireForCell(new Boolean(propManager.getProperty("usewireforcell")
                .trim()).booleanValue());
        setScale(Float.parseFloat(propManager.getProperty("scale").trim()));
        setNumNodesAtom(Integer.parseInt(propManager
                .getProperty("numnodesatom").trim()));
        setNumNodesBond(Integer.parseInt(propManager
                .getProperty("numnodesbond").trim()));
        setScaleAtom(Float.parseFloat(propManager.getProperty("scaleatom")
                .trim()));
        setDrawCell(Boolean.valueOf(propManager.getProperty("drawcell").trim())
                .booleanValue());
        setCellWidth(Float.parseFloat(propManager.getProperty("cellwidth")
                .trim()));
        setCellColor(
                Float.parseFloat(propManager.getProperty("cellcolor_r").trim()),
                Float.parseFloat(propManager.getProperty("cellcolor_g").trim()),
                Float.parseFloat(propManager.getProperty("cellcolor_b").trim()));
        setNumNodesCell(Integer.parseInt(propManager
                .getProperty("numnodescell").trim()));
        setText(Boolean.valueOf(propManager.getProperty("setlabel").trim())
                .booleanValue());
        setLegend(Boolean.valueOf(propManager.getProperty("setlegend").trim())
                .booleanValue());
        setAxis(Boolean.valueOf(propManager.getProperty("setaxis").trim())
                .booleanValue());
        setMobile(Boolean.valueOf(
                propManager.getProperty("showmobility").trim()).booleanValue());
        setLabelOffset(Integer.parseInt(propManager.getProperty("labeloffset")
                .trim()));
        setMobilityDisplayMode(Integer.parseInt(propManager.getProperty(
                "mobilitydisplaymode").trim()));
        setFont(new Font(propManager.getProperty("font_name"),
                Integer.parseInt(propManager.getProperty("font_style")),
                Integer.parseInt(propManager.getProperty("font_size"))));
        String[] sfontColor = propManager.getProperty("font_color").split(",");
        setFontColor(new Color3f(Float.parseFloat(sfontColor[0]),
                Float.parseFloat(sfontColor[1]),
                Float.parseFloat(sfontColor[2])));
        setAtomRenderingMethod(propManager.getProperty("atomobject"));
        try {
            setShiftPolicy(Integer.parseInt(propManager
                    .getProperty("atom_shift_policy")));
        } catch (Exception exc) {
        }
    }

    private ElementInfo einfo;

    public void setShiftPolicy(int shiftPolicy) {
        this.shiftPolicy = shiftPolicy;
    }

    private void readElementInfo() {
        einfo = ElementInfo.getElementInfo();
    }

    public ElementInfo getEInfo() {
        return this.einfo;
    }

    /**
     * ``新元素''の情報を足しこむメソッド.
     * 
     * @param nameNew
     *            新元素の名前
     * @param radiusNew
     *            新元素の半径
     * @param covalentradiusNew
     *            新元素のcovariant radius
     * @param elementcolorNew
     *            新元素の色
     */
    public void addElementInfo(String nameNew, float radiusNew,
            double covalentradiusNew, float[] elementcolorNew) {
        ElementDef def = new ElementDef();
        def.setSymbol(nameNew);
        def.setRadius(radiusNew);
        def.setCovalentRadius(covalentradiusNew);
        def.setColor(elementcolorNew);
        einfo.addElementDef(def);
    }

    /**
     * このクラスに保持されている表示に関わる設定や元素情報を 設定ファイルに書き出すメソッド.
     */
    public void writeACVData() {
        writeACVPrefs();
        writeElemInfo();
    }

    private void writeACVPrefs() {
        propManager.setProperty("bgcolor_r", Float.toString(getBgColor()[0]));
        propManager.setProperty("bgcolor_g", Float.toString(getBgColor()[1]));
        propManager.setProperty("bgcolor_b", Float.toString(getBgColor()[2]));
        propManager.setProperty("bondfactor", Double.toString(getBondFactor()));
        propManager.setProperty("bondwidth", Double.toString(getBondWidth()));
        propManager.setProperty("usewireforbond",
                String.valueOf(getUseWireForBond()));
        propManager.setProperty("scale", Float.toString(getScale()));
        propManager.setProperty("scaleatom", Float.toString(getScaleAtom()));
        propManager.setProperty("numnodesatom",
                Integer.toString(getNumNodesAtom()));
        propManager.setProperty("numnodesbond",
                Integer.toString(getNumNodesBond()));
        propManager.setProperty("numnodescell",
                Integer.toString(getNumNodesCell()));
        propManager.setProperty("drawcell", Boolean.toString(getDrawCell()));
        propManager.setProperty("usewireforcell",
                String.valueOf(getUseWireForCell()));
        propManager.setProperty("cellwidth", Float.toString(getCellWidth()));
        propManager.setProperty("cellcolor_r",
                Float.toString(getCellColor()[0]));
        propManager.setProperty("cellcolor_g",
                Float.toString(getCellColor()[1]));
        propManager.setProperty("cellcolor_b",
                Float.toString(getCellColor()[2]));
        propManager.setProperty("setlabel", Boolean.toString(getText()));
        propManager.setProperty("setaxis", Boolean.toString(getAxis()));
        propManager.setProperty("setlegend", Boolean.toString(getLegend()));
        propManager.setProperty("showmobility", Boolean.toString(getMobile()));
        propManager.setProperty("bondcolor_r",
                Float.toString(getBondColor()[0]));
        propManager.setProperty("bondcolor_g",
                Float.toString(getBondColor()[1]));
        propManager.setProperty("bondcolor_b",
                Float.toString(getBondColor()[2]));
        propManager.setProperty("labeloffset",
                Integer.toString(getLabelOffset()));
        propManager.setProperty("mobilitydisplaymode",
                Integer.toString(getMobilityDisplayMode()));
        font = getFont();
        propManager.setProperty("font_name", font.getName());
        propManager.setProperty("font_style", String.valueOf(font.getStyle()));
        propManager.setProperty("font_syze", String.valueOf(font.getSize()));
        propManager.setProperty("font_color",
                String.valueOf(fontColor.x) + "," + String.valueOf(fontColor.y)
                        + "," + String.valueOf(fontColor.z));
        propManager.setProperty("atomobject", atomRenderingMethod);

        propManager.storeProperty();
    }

    private void writeElemInfo() {
        einfo.toDisk();
    }

    public void setParent(J3DPanel mp) {
        this.mp = mp;
    }

    public J3DPanel getParent() {
        return this.mp;
    }

}
