/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2005/08/16, 21:25
!  AUTHOR(S): KOGA, Junichiro
!  File : PhononPanel.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.projectmanipulator.phase.preparationpanel;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;

import org.apache.log4j.Logger;

import ciss.phase_viewer.acviewer.fbz.FBZ;
import ciss.phase_viewer.acviewer.fbz.FBZData;
import ciss.phase_viewer.acviewer.fbz.Kpoint;
import ciss.phase_viewer.acviewer.fbz.KpointGenerator;
import ciss.phase_viewer.common.PhaseUtils;
import ciss.phase_viewer.common.Utils;
import ciss.phase_viewer.inputinterface.InputInterface;
import ciss.phase_viewer.inputinterface.inputinterfacetable.InputInterfaceTable;
import ciss.phase_viewer.plugins.projectmanipulator.phase.PhaseInputItems;
import ciss.phase_viewer.primitiveguis.ChoicePanelPhase;
import ciss.phase_viewer.primitiveguis.InputPanelPhase;
import ciss.phase_viewer.projectbrowser.ProjectInfo;
import ciss.phase_viewer.projectbrowser.ProjectManipulator;

/**
 * 
 * @author KOGA, Junichiro
 */
public class PhononPanel extends ProjectManipulator {
    private Logger logger = Logger.getLogger(PhononPanel.class.getName());

    private String phbandcontrol = "phbandcontrol";

    private String projdir;

    /** Creates a new instance of PhononPanel */
    public PhononPanel(ProjectInfo projectInfo) {
        super(projectInfo);
    }

    public void init() {
        setLayout(new BorderLayout());
        add(new SubPanel(projectInfo.getInputInterface()), BorderLayout.NORTH);
        projdir = projectInfo.getProjectDirectory();
    }

    public void initializeProject() {
    }

    private ChoicePanelPhase cppsw_phonon;

    class SubPanel extends PhaseInputItems implements KpointGenerator {
        SubPanel(InputInterface inputInterface) {
            super(inputInterface);
        }

        public void createGUI() {
            String tag_phonon = "Phonon.";
            setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

            JPanel gammaPoint = new JPanel();
            gammaPoint.setBorder(new TitledBorder("Gamma point"));
            gammaPoint.setLayout(new BoxLayout(gammaPoint, BoxLayout.Y_AXIS));

            String[] point_group = {
                    ciss.phase_viewer.primitiveguis.ChoicePanelPhase.NO_SELECTION,
                    "Oh", "O", "Td", "Th", "T", "D4h", "D4", "D2d", "C4v",
                    "C4h", "S4", "C4", "D2h", "D2", "C2v", "D6h", "D6", "D3h",
                    "C6v", "C6h", "C3h", "C6", "D3d", "D3", "C3v", "S6", "C3",
                    "C2h", "Cs", "C2", "Ci", "C1" };

            String[] sw_phonon = new String[] { tag_phonon + "sw_phonon" };
            cppsw_phonon = new ChoicePanelPhase(sw_phonon, inputInterface,
                    "phonon", ON_OFF, ON_OFF_DUPLI, this);

            cppsw_phonon.getComboBox().addActionListener(new ActionListener() {

                public void actionPerformed(ActionEvent arg0) {
                    // TODO Auto-generated method stub
                    if (cppsw_phonon.getComboBox().getSelectedIndex() == 1)
                        inputInterface.getInputInterfacePrimitiveEntry(
                                "Phonon.sw_vibrational_modes").setValue("on");
                    else
                        inputInterface.getInputInterfacePrimitiveEntry(
                                "Phonon.sw_vibrational_modes").setValue("off");
                }

            });

            cppsw_phonon.getComboBox().setSelectedIndex(
                    cppsw_phonon.getComboBox().getSelectedIndex());

            String[] tag_point_group = new String[] { tag_phonon
                    + "point_group" };
            ChoicePanelPhase cpppoint_group = new ChoicePanelPhase(
                    tag_point_group, inputInterface, "point group",
                    point_group, this);
            String[] sw_calc_force = new String[] { tag_phonon
                    + "sw_calc_force" };
            ChoicePanelPhase cppsw_calc_force = new ChoicePanelPhase(
                    sw_calc_force, inputInterface, "calculate force", ON_OFF,
                    ON_OFF_DUPLI, this);
            JPanel p1 = new JPanel();
            p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS));
            p1.add(cppsw_phonon);
            p1.add(cpppoint_group);
            p1.add(cppsw_calc_force);

            String[] displacement = new String[] { tag_phonon + "displacement" };
            InputPanelPhase ippdisplacement = new InputPanelPhase(displacement,
                    inputInterface, "displacement", InputPanelPhase.NONE, 7,
                    this);
            String[] norder = new String[] { tag_phonon + "norder" };
            InputPanelPhase ippnorder = new InputPanelPhase(norder,
                    inputInterface, "norder", InputPanelPhase.NONE, 7, this);
            String[] sw_polynomial_fit = new String[] { tag_phonon
                    + "sw_polynomial_fit" };
            ChoicePanelPhase cppsw_polynomial_fit = new ChoicePanelPhase(
                    sw_polynomial_fit, inputInterface, "polynomial fit",
                    ON_OFF, ON_OFF_DUPLI, this);
            JPanel ptmp = new JPanel();
            ptmp.setLayout(new GridLayout());
            ptmp.add(cppsw_polynomial_fit);
            JPanel p2 = new JPanel();
            // p2.setLayout(new BoxLayout(p2, BoxLayout.X_AXIS));
            p2.setLayout(new GridLayout(1, 3));
            p2.add(ippdisplacement);
            p2.add(ippnorder);
            p2.add(ptmp);

            int[] disable = new int[] { 0, 2 };

            cppsw_phonon.registerDisabableGUI(disable, cpppoint_group);
            cppsw_phonon.registerDisabableGUI(disable, cppsw_calc_force);
            cppsw_phonon.registerDisabableGUI(disable, ippdisplacement);
            cppsw_phonon.registerDisabableGUI(disable, ippnorder);
            cppsw_phonon.registerDisabableGUI(disable, cppsw_polynomial_fit);
            gammaPoint.add(p1);
            gammaPoint.add(p2);

            JPanel phononDispersion = new JPanel();
            phononDispersion.setBorder(new TitledBorder("phonon dispersion"));
            phononDispersion.setLayout(new BoxLayout(phononDispersion,
                    BoxLayout.Y_AXIS));

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

            JPanel type = new JPanel();
            String[] sw_ph_type = new String[] { tag_phonon + "method",
                    tag_phonon + "calc_type" };
            String[] ph_choice = new String[] { NO_SELECTION, "band", "dos" };
            ChoicePanelPhase cppsw_ph_type = new ChoicePanelPhase(sw_ph_type,
                    inputInterface, "method", ph_choice, this);
            type.add(cppsw_ph_type);
            JPanel pslsize = new JPanel();
            pslsize.setBorder(new TitledBorder("size of superlattice"));
            pslsize.setLayout(new BoxLayout(pslsize, BoxLayout.X_AXIS));
            String[] slsizex = new String[] { tag_phonon + "lattice.l1" };
            String[] slsizey = new String[] { tag_phonon + "lattice.l2" };
            String[] slsizez = new String[] { tag_phonon + "lattice.l3" };
            InputPanelPhase ippslsizex = new InputPanelPhase(slsizex,
                    inputInterface, "l1", InputPanelPhase.NONE, 5, this);
            InputPanelPhase ippslsizey = new InputPanelPhase(slsizey,
                    inputInterface, "l2", InputPanelPhase.NONE, 5, this);
            InputPanelPhase ippslsizez = new InputPanelPhase(slsizez,
                    inputInterface, "l3", InputPanelPhase.NONE, 5, this);
            pslsize.add(ippslsizex);
            pslsize.add(ippslsizey);
            pslsize.add(ippslsizez);
            firstRow.add(type);
            firstRow.add(pslsize);

            JPanel secondRow = new JPanel();
            secondRow.setLayout(new BoxLayout(secondRow, BoxLayout.X_AXIS));
            JPanel pband = new JPanel();
            pband.setBorder(new TitledBorder("phonon band"));
            JButton fbzbutton = new JButton("boot FBZ viewer");
            pband.add(fbzbutton);

            JPanel pdos = new JPanel();
            pdos.setBorder(new TitledBorder("phonon DOS"));
            pdos.setLayout(new BoxLayout(pdos, BoxLayout.X_AXIS));

            String[] specde = new String[] { tag_phonon + "dos.deltaE" };
            InputPanelPhase ippde = new InputPanelPhase(specde, inputInterface,
                    "dE", InputPanelPhase.ENERGY, 5, this);
            JPanel pde = new JPanel();
            pde.add(ippde);

            JPanel mesh = new JPanel();
            mesh.setLayout(new BoxLayout(mesh, BoxLayout.X_AXIS));
            mesh.setBorder(new TitledBorder("mesh"));
            String[] specnx = new String[] { tag_phonon + "dos.mesh.nx" };
            String[] specny = new String[] { tag_phonon + "dos.mesh.ny" };
            String[] specnz = new String[] { tag_phonon + "dos.mesh.nz" };

            InputPanelPhase ippnx = new InputPanelPhase(specnx, inputInterface,
                    "nx", InputPanelPhase.NONE, 5, this);
            InputPanelPhase ippny = new InputPanelPhase(specny, inputInterface,
                    "ny", InputPanelPhase.NONE, 5, this);
            InputPanelPhase ippnz = new InputPanelPhase(specnz, inputInterface,
                    "nz", InputPanelPhase.NONE, 5, this);
            mesh.add(ippnx);
            mesh.add(ippny);
            mesh.add(ippnz);

            pdos.add(pde);
            pdos.add(mesh);

            secondRow.add(pband);
            secondRow.add(pdos);

            phononDispersion.add(firstRow);
            phononDispersion.add(secondRow);

            add(gammaPoint);
            // add(phononDispersion);

            fbzbutton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    bootFBZViewer();
                }
            });

            int[] disable_dispersion = new int[] { 0 };
            int[] disable_band = new int[] { 0, 2 };
            int[] disable_dos = new int[] { 0, 1 };

            cppsw_phonon.registerDisabableGUI(disable, cppsw_ph_type);
            cppsw_phonon.registerDisabableGUI(disable, ippslsizex);
            cppsw_phonon.registerDisabableGUI(disable, ippslsizex);
            cppsw_phonon.registerDisabableGUI(disable, ippslsizey);
            cppsw_phonon.registerDisabableGUI(disable, ippslsizez);
            cppsw_phonon.registerDisabableGUI(disable, fbzbutton);
            cppsw_phonon.registerDisabableGUI(disable, ippde);
            cppsw_phonon.registerDisabableGUI(disable, ippnx);
            cppsw_phonon.registerDisabableGUI(disable, ippny);
            cppsw_phonon.registerDisabableGUI(disable, ippnz);

            cppsw_ph_type.registerDisabableGUI(disable_dispersion, ippslsizex);
            cppsw_ph_type.registerDisabableGUI(disable_dispersion, ippslsizey);
            cppsw_ph_type.registerDisabableGUI(disable_dispersion, ippslsizez);
            cppsw_ph_type.registerDisabableGUI(disable_dispersion, fbzbutton);
            cppsw_ph_type.registerDisabableGUI(disable_dispersion, ippde);
            cppsw_ph_type.registerDisabableGUI(disable_dispersion, ippnx);
            cppsw_ph_type.registerDisabableGUI(disable_dispersion, ippny);
            cppsw_ph_type.registerDisabableGUI(disable_dispersion, ippnz);

            cppsw_ph_type.registerDisabableGUI(disable_band, fbzbutton);
            cppsw_ph_type.registerDisabableGUI(disable_dos, ippde);
            cppsw_ph_type.registerDisabableGUI(disable_dos, ippnx);
            cppsw_ph_type.registerDisabableGUI(disable_dos, ippny);
            cppsw_ph_type.registerDisabableGUI(disable_dos, ippnz);
        }

        public void generateKpoints(Kpoint[] kpoints, double dk) {

            logger.debug("generating kpoints");
            if (kpoints != null)
                for (int i = 0; i < kpoints.length; i++)
                    logger.debug("kpoint no. " + i + ": " + kpoints[i]);
            Vector vec = new Vector();
            for (int i = 0; i < kpoints.length; i++) {
                if (vec.indexOf(kpoints[i]) < 0)
                    vec.addElement(kpoints[i]);
            }
            InputInterfaceTable special_points = inputInterface
                    .getInputInterfaceTable("phonon.special_points");
            special_points.setTableIdentifiers(new String[] { "no", "k1", "k2",
                    "k3" });
            special_points.initializeData();
            for (int i = 0; i < vec.size(); i++) {
                Kpoint kp = (Kpoint) vec.get(i);
                logger.debug("adding kpoint: " + kp);
                double[] kpoin = kp.getDouble();
                String[] data = new String[] { String.valueOf(i + 1),
                        String.valueOf(kpoin[0]), String.valueOf(kpoin[1]),
                        String.valueOf(kpoin[2]) };
                special_points.insertTableDataRow(data, i);
            }
            inputInterface.selectRoot();

            PrintWriter writer = Utils.getPrintWriter(projdir
                    + System.getProperty("file.separator") + phbandcontrol);

            InputInterfaceTable symmetry_lines = inputInterface
                    .getInputInterfaceTable("phonon.symmetry_lines");
            symmetry_lines.setTableIdentifiers(new String[] { "k1", "k2",
                    "num_division" });
            symmetry_lines.initializeData();
            int sum = 1;
            for (int i = 0; i < kpoints.length - 1; i++) {
                int k1 = vec.indexOf(kpoints[i]) + 1;
                int k2 = vec.indexOf(kpoints[i + 1]) + 1;
                double distance = kpoints[i].getDistanceFrom(kpoints[i + 1]);
                int div = 5;
                try {
                    div = (int) (0.5 * distance / dk);
                } catch (Exception exc) {
                }
                if (div == 0)
                    div = 1;
                int tmpsum = sum + div;
                String s1 = kpoints[i].getSymbol();
                String s2 = kpoints[i + 1].getSymbol();

                if (writer != null)
                    writer.println(sum + " " + tmpsum + " " + s1 + " " + s2);

                sum = tmpsum;

                symmetry_lines.insertTableDataRow(
                        new String[] { String.valueOf(k1), String.valueOf(k2),
                                String.valueOf(div) }, i);
            }

            if (writer != null) {
                writer.flush();
                writer.close();
            }

            inputInterface.selectRoot();
        }

        public void saveInput(Kpoint[] kpoints, double deltak) {
            logger.debug("saving input");
            for (int i = 0; i < kpoints.length; i++)
                logger.debug("kpoint no. " + i + ": " + kpoints[i]);
        }

        private void bootFBZViewer() {
            double[][] reclat = PhaseUtils
                    .getReciprocalLatticeFrom(inputInterface);
            FBZData data = new FBZData();
            data.reciprocalLattice = reclat;
            data.baseDir = projdir;
            data.kpointGenerator = this;
            new FBZ(data);
        }

        public Kpoint[] getKpointsFrom(String file) {
            logger.debug("reading kpoints from file");
            Kpoint[] ret = null;
            try {

                InputInterfaceTable speacial_points = inputInterface
                        .getInputInterfaceTable("phonon.special_points");
                Vector data = speacial_points.getTableData();
                if (data == null || data.size() == 0)
                    return null;
                Kpoint[] kps = new Kpoint[data.size()];
                HashMap map = new HashMap();
                for (int i = 0; i < data.size(); i++) {
                    String[] strdata = (String[]) data.get(i);
                    String ident = strdata[0];
                    float k1 = Float.parseFloat(strdata[1]);
                    float k2 = Float.parseFloat(strdata[2]);
                    float k3 = Float.parseFloat(strdata[3]);
                    kps[i] = new Kpoint(new float[] { k1, k2, k3 });
                    map.put(ident, kps[i]);
                    logger.debug("read kpoint: " + kps[i]);
                }

                try {
                    InputInterfaceTable symmetry_lines = inputInterface
                            .getInputInterfaceTable("phonon.symmetry_lines");
                    Vector symline = symmetry_lines.getTableData();
                    if (symline == null || symline.size() == 0)
                        return null;

                    ret = new Kpoint[symline.size() + 1];

                    String[] firstData = (String[]) symline.get(0);
                    ret[0] = (Kpoint) map.get(firstData[0]);
                    logger.debug("first k-point: " + ret[0]);
                    for (int i = 0; i < symline.size(); i++) {
                        String[] strdata = (String[]) symline.get(i);
                        String id2 = strdata[1];
                        ret[i + 1] = (Kpoint) map.get(id2);
                        logger.debug("sym. line: " + strdata[0] + " "
                                + strdata[1] + " " + strdata[2]);
                        logger.debug("map.get(id2): " + ret[i + 1]);
                    }
                    File controlfile = new File(projdir
                            + System.getProperty("file.separator")
                            + phbandcontrol);
                    if (controlfile.exists()) {
                        BufferedReader rd = Utils.getReader(controlfile
                                .getAbsolutePath());
                        String line = "";
                        try {
                            int count = 0;
                            while ((line = rd.readLine()) != null) {
                                String[] dat = line.trim().split("\\s+");
                                String str = "";
                                for (int i = 0; i < dat.length; i++) {
                                    str += dat[i] + " ";
                                }
                                logger.debug("str: " + str);

                                if (dat.length >= 4) {
                                    String ident = dat[2];
                                    ret[count].setSymbol(ident);
                                    count++;
                                    if (count == symline.size()) {
                                        ret[count].setSymbol(dat[3]);
                                        break;
                                    }
                                }
                            }
                        } catch (IOException ioe) {
                            ioe.printStackTrace();
                        }
                        try {
                            rd.close();
                        } catch (IOException ioe) {
                        }
                    }

                } catch (Exception exc) {
                    exc.printStackTrace();
                }

                logger.debug("final kpoints: ");
                for (int i = 0; i < ret.length; i++) {
                    logger.debug("no. " + i + " : " + ret[i]);
                }

            } catch (NumberFormatException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ArrayIndexOutOfBoundsException aobe) {
                aobe.printStackTrace();
            }
            return ret;
        }

    }
}
