/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/12/18 17:48:00
!  AUTHOR(S): KOGA, Junichiro
!  File : CrystalSystemEditor.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.plugins.viewer.edit;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.border.TitledBorder;

import ciss.phase_viewer.acviewer.ConfigData;
import ciss.phase_viewer.acviewer.ConfigDataUpdateEvent;
import ciss.phase_viewer.acviewer.MainPanel;
import ciss.phase_viewer.acviewer.scenegraphelements.CellObject;
import ciss.phase_viewer.acviewer.scenegraphelements.TGAtom;
import ciss.phase_viewer.atomcoord.AtomCoords;
import ciss.phase_viewer.atomcoord.AtomList;
import ciss.phase_viewer.atomcoord.Cell;
import ciss.phase_viewer.atomcoord.VolumetricData;
import ciss.phase_viewer.atomcoord.symmetry.BravaisLattice;

/**
 * 結晶系の表示方法などを制御するGUI.
 * 
 * @author KOGA, Junichiro
 * 
 */
public class CrystalSystemEditor extends JPanel implements ConfigData {

    private org.apache.log4j.Logger logger = org.apache.log4j.Logger
            .getLogger(CrystalSystemEditor.class.getName());

    private JToggleButton drawPrimitiveButton;

    private JToggleButton drawSubLatAtomButton;

    private MainPanel parent;

    private BravaisLattice bravaisLattice;

    private String[] latticeSystemChoice;

    private JComboBox latticeSystemCombo;

    private JButton stripButton;

    private JCheckBox cbsave;

    private JButton toggleUCtype;

    private boolean unitCellTypeIsBravais = true;

    private JComboBox comboUnitCellType;

    private String[] unitCellTypes = { "primitive", "Bravais" };

    private JLabel labelCrytalSystem;

    public CrystalSystemEditor(MainPanel parent) {
        this.parent = parent;
        this.bravaisLattice = parent.getData().getBravaisLattice();
        this.parent.getCD().register(this);
        JPanel p = new JPanel();
        p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));

        JPanel pcell = new JPanel();
        pcell.setLayout(new BoxLayout(pcell, BoxLayout.X_AXIS));

        JPanel punitcombo = new JPanel();
        punitcombo.setBorder(new TitledBorder("unitcell type"));
        comboUnitCellType = new JComboBox(unitCellTypes);
        punitcombo.add(comboUnitCellType);

        JPanel pprim = new JPanel();
        pprim.setBorder(new TitledBorder("primitive cell"));
        drawPrimitiveButton = new JToggleButton("draw");
        pprim.add(drawPrimitiveButton);
        pcell.add(punitcombo);
        pcell.add(pprim);

        p.add(pcell);

        JPanel pcryst = new JPanel();
        pcryst.setLayout(new GridLayout(1, 2));

        JPanel plabel = new JPanel();
        plabel.setBorder(new TitledBorder("crystal system"));
        labelCrytalSystem = new JLabel();
        plabel.add(labelCrytalSystem);
        latticeSystemCombo = new JComboBox();
        JPanel psystem = new JPanel();
        psystem.setBorder(new TitledBorder("lattice system"));
        psystem.add(latticeSystemCombo);

        pcryst.add(plabel);
        pcryst.add(psystem);
        p.add(pcryst);

        JPanel psub = new JPanel();
        psub.setLayout(new BoxLayout(psub, BoxLayout.X_AXIS));
        psub.setBorder(new TitledBorder("sublattice atoms"));

        stripButton = new JButton("strip");
        JPanel pstrip = new JPanel();
        pstrip.add(stripButton);
        psub.add(pstrip);

        JPanel psublat = new JPanel();
        psublat.setLayout(new BoxLayout(psublat, BoxLayout.X_AXIS));
        cbsave = new JCheckBox("save");
        cbsave.setEnabled(false);
        drawSubLatAtomButton = new JToggleButton("draw");
        psublat.add(drawSubLatAtomButton);
        psublat.add(cbsave);
        psub.add(psublat);

        p.add(psub);

        toggleUCtype = new JButton("toggle unit cell type");
        JPanel ptoggle = new JPanel();
        ptoggle.add(toggleUCtype);
        // p.add(ptoggle);

        if (bravaisLattice != null) {
            String strcryst = bravaisLattice.getCrystalSystem();
            labelCrytalSystem.setText(strcryst);
            latticeSystemChoice = bravaisLattice.getLatticeSystemCandidate();
            bravaisLattice
                    .estimateLatticeSystem(parent.getCD().getAtomCoords());

            if (bravaisLattice.isBravais()) {
                comboUnitCellType.setSelectedIndex(1);
            } else {
                comboUnitCellType.setSelectedIndex(0);
            }

            for (int i = 0; i < latticeSystemChoice.length; i++) {
                latticeSystemCombo.addItem(latticeSystemChoice[i]);
            }
            latticeSystemCombo.setSelectedItem(bravaisLattice
                    .getLatticeSystem());

            drawPrimitiveButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    if (bravaisLattice != null)
                        drawPrimitive(drawPrimitiveButton.isSelected());
                }
            });

            drawSubLatAtomButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    if (drawSubLatAtomButton.isSelected()) {
                        addSubLatticeAtoms();
                        cbsave.setEnabled(true);
                    } else {
                        cbsave.setSelected(false);
                        removeSubLatticeAtoms();
                        cbsave.setEnabled(false);
                    }
                }
            });

            latticeSystemCombo.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    bravaisLattice.setLatticeSystem(latticeSystemCombo
                            .getSelectedItem().toString());
                }
            });

            stripButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    doSubLatticeAtomStrip();
                    latticeSystemCombo.setSelectedItem(bravaisLattice
                            .getLatticeSystem());
                }
            });

            cbsave.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    setSaveSublatAtoms(cbsave.isSelected());
                }
            });

            comboUnitCellType.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    boolean boo = comboUnitCellType.getSelectedIndex() == 0;
                    toggleUnitCellType(boo);
                }
            });

            bravaisLattice.setLatticeSystem(latticeSystemCombo
                    .getSelectedItem().toString());
        }

        add(p);

        updateGUI();

        revalidate();
        setVisible(true);
    }

    private boolean updating = false;

    private void toggleUnitCellType(boolean toprimitive) {
        if (bravaisLattice == null)
            return;
        updating = true;
        if (toprimitive) {
            double[][] primvec = bravaisLattice.getPrimitiveLatticeVector();
            Cell cel = new Cell(primvec[0], primvec[1], primvec[2]);
            AtomCoords coords = parent.getCD().getAtomCoords();
            coords.saveState();

            coords.removeBoundaryAtoms();
            bravaisLattice.stripSubLatticeAtoms(coords);
            coords.removeSubLatticeAtoms();
            coords.setCell(cel);
            int updateType = ConfigDataUpdateEvent.GENERIC;

            VolumetricData[] vdata = parent.getAssociatedVolumetricData();
            if (vdata != null && vdata.length != 0) {
                updateType = ConfigDataUpdateEvent.CELL_CHANGED;
                for (int i = 0; i < vdata.length; i++) {
                    vdata[i].restore();
                }
            }

            parent.getCD().setCoords(coords, updateType);

            coords.finalizeState();

            parent.postRedraw();
            parent.getCD().isRenderingManual(false);

            parent.doUnitCell(true);

            bravaisLattice.isBravais(false);
        } else {
            AtomCoords coords = parent.getCD().getAtomCoords();
            Cell cell = coords.getCell(0);
            double[][] dce = cell.getDouble();
            if (bravaisLattice != null) {
                coords.saveState();
                coords.removeBoundaryAtoms();
                logger.debug("bravais lattice : " + bravaisLattice);
                double[][] cellvec = bravaisLattice.getGenericPrimitiveVector();
                logger.debug("cellvec0 " + cellvec[0][0] + " " + cellvec[0][1]
                        + " " + cellvec[0][2]);
                logger.debug("cellvec1 " + cellvec[1][0] + " " + cellvec[1][1]
                        + " " + cellvec[1][2]);
                logger.debug("cellvec2 " + cellvec[2][0] + " " + cellvec[2][1]
                        + " " + cellvec[2][2]);
                Cell newcell = new Cell(cellvec[0], cellvec[1], cellvec[2]);
                coords.setCell(newcell);

                VolumetricData[] vdata = parent.getAssociatedVolumetricData();
                int updateType = ConfigDataUpdateEvent.GENERIC;
                if (vdata != null && vdata.length != 0) {
                    for (int i = 0; i < vdata.length; i++) {
                        vdata[i].save();
                        bravaisLattice
                                .bravaisVolumetricData2Primitive(vdata[i]);
                    }
                    updateType = ConfigDataUpdateEvent.CELL_CHANGED;
                }
                bravaisLattice.isBravais(true);

                parent.getCD().isRenderingManual(true);
                parent.prepareRedraw();
                parent.doUnitCell(false);
                parent.getCD().setCoords(coords, updateType);
                parent.postRedraw();
                parent.getCD().isRenderingManual(false);
                coords.finalizeState();
            }
        }
        updateGUI();
        updating = false;
    }

    private void updateGUI() {
        if (bravaisLattice == null)
            return;
        boolean enable = comboUnitCellType.getSelectedIndex() == 1;

        drawPrimitiveButton.setEnabled(enable);
        drawPrimitive(enable && drawPrimitiveButton.isSelected());

        stripButton.setEnabled(enable);
        latticeSystemCombo.setEnabled(enable);

        drawSubLatAtomButton.setEnabled(enable);
        if (drawSubLatAtomButton.isSelected() && enable)
            addSubLatticeAtoms();

        cbsave.setEnabled(drawSubLatAtomButton.isSelected() && enable);
        bravaisLattice.isBravais(enable);
        revalidate();
    }

    private void drawPrimitive(boolean draw) {
        CellObject cell = ((TGAtom) parent.getRootTransform()).getCellObject();
        if (draw) {
            cell.addPrimitiveCell();
        } else {
            cell.removePrimitiveCell();
        }
    }

    private void setSaveSublatAtoms(boolean save) {
        AtomCoords coords = parent.getCD().getAtomCoords();
        AtomList list = coords.getAtomList();
        for (int i = 0; i < list.size(); i++)
            list.getAtomAt(i).saveSubLatticeAtom(save);

        if (save)
            bravaisLattice.setLatticeSystem(BravaisLattice.PRIMITIVE);
        else
            bravaisLattice.setLatticeSystem(latticeSystemCombo
                    .getSelectedItem().toString());
    }

    private void addSubLatticeAtoms() {
        AtomCoords coords = parent.getCD().getAtomCoords();
        AtomList list = coords.getAtomList();
        logger.debug("atom list before addition of sublattice atoms:");
        logger.debug(list);

        parent.getCD().isRenderingManual(true);
        coords.saveState();
        coords.removeBoundaryAtoms();
        bravaisLattice.addSubLatticeAtoms(coords);
        logger.debug("atom list after addition of sublattice atoms: ");
        logger.debug(list);
        parent.prepareRedraw();
        parent.getCD().setCoords(coords);
        coords.finalizeState();

        parent.doUnitCell();

        parent.postRedraw();
        parent.getCD().isRenderingManual(false);

    }

    private void removeSubLatticeAtoms() {
        AtomCoords coords = parent.getCD().getAtomCoords();
        parent.getCD().isRenderingManual(true);
        parent.prepareRedraw();
        coords.saveState();
        removeSubLatticeAtomsSub(coords);
        parent.postRedraw();
        parent.getCD().isRenderingManual(false);
        coords.finalizeState();
    }

    private void removeSubLatticeAtomsSub(AtomCoords coords) {
        coords.removeBoundaryAtoms();
        coords.removeSubLatticeAtoms();
        parent.getCD().setCoords(coords);
        parent.doUnitCell();
    }

    private void doSubLatticeAtomStrip() {
        AtomCoords coords = parent.getCD().getAtomCoords();
        coords.saveState();
        parent.getCD().isRenderingManual(true);
        parent.prepareRedraw();
        doSubLatticeAtomStripSub(coords);
        parent.postRedraw();
        parent.getCD().isRenderingManual(false);
        coords.finalizeState();
    }

    private void doSubLatticeAtomStripSub(AtomCoords coords) {
        bravaisLattice.stripSubLatticeAtoms(coords);
        parent.getCD().setCoords(coords);
        parent.doUnitCell();
    }

    public void configDataUpdate() {
    }

    public void configDataUpdate(boolean rescaleOnUpdate,
            ConfigDataUpdateEvent e) {
        // if ( !updating && e.getType()==ConfigDataUpdateEvent.CELL_CHANGED) {
        // boolean boo = comboUnitCellType.getSelectedIndex() == 0;
        // toggleUnitCellType(boo);
        // }
    }

    public boolean needsUpdate() {
        // TODO Auto-generated method stub
        return true;
    }

}
