/*
 !=======================================================================
 !
 !  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
 !
 !  Created on 2006/05/10, 18:24
 !  AUTHOR(S): KOGA, Junichiro
 !
 !  The license of the code and contact address:
 !  See the files, COPYRIGHT and LICENSE (or LICENSE_J.pdf)
 !
 !=======================================================================
 */

package ciss.phase_viewer.plugins.projectmanipulator.phase.preparationpanel.atomconfig;

import java.awt.BorderLayout;
import java.awt.Dimension;
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.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Vector;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.TitledBorder;

import org.apache.log4j.Logger;

import ciss.phase_viewer.common.ExternalProgramExecuter;
import ciss.phase_viewer.common.Utils;
import ciss.phase_viewer.inputinterface.InputInterface;
import ciss.phase_viewer.inputinterface.InputInterfaceEntry;
import ciss.phase_viewer.inputinterface.InputInterfaceEntryChangeEvent;
import ciss.phase_viewer.inputinterface.InputInterfaceEntryChangeListener;
import ciss.phase_viewer.inputinterface.InputInterfacePrimitiveEntry;
import ciss.phase_viewer.mainpanel.DefaultInternalFrameChase;
import ciss.phase_viewer.plugins.projectmanipulator.phase.PhaseInputItems;
import ciss.phase_viewer.primitiveguis.ChoicePanelPhase;
import ciss.phase_viewer.primitiveguis.tableforinputinterface.TableForInputInterface;
import ciss.phase_viewer.projectbrowser.ProjectInfo;
import ciss.phase_viewer.projectbrowser.ProjectManipulator;

/**
 * 対称性編集用GUI.
 * 
 * @author
 */
public class SymmetryPanel extends ProjectManipulator {
    private Logger logger = Logger.getLogger(SymmetryPanel.class.getName());

    private File projDir;

    private InputInterface inputInterface;

    /** Creates a new instance of SymmetryPanel */
    public SymmetryPanel(ProjectInfo projectInfo) {
        super(projectInfo);
        projDir = new File(projectInfo.getProjectDirectory());
        inputInterface = projectInfo.getInputInterface();
        JScrollPane scr = new JScrollPane();
        scr.getViewport().setView(
                new SymmetryPanelPanel(projectInfo.getInputInterface()));
        add(scr);
    }

    public void init() {
    }

    public void initializeProject() {
    }

    private JPanel pchecksym;

    private JPanel pshow;

    class SymmetryPanelPanel extends PhaseInputItems implements
            InputInterfaceEntryChangeListener {
        private TableForInputInterface tbl_tspace;

        SymmetryPanelPanel(InputInterface inputInterface) {
            super(inputInterface);
        }

        private boolean checkingSymmetry = false;
        private JButton checksym;

        public void createGUI() {
            inputInterface.addInputInterfaceEntryChangeListener(this);
            JPanel pall = new JPanel();
            pall.setLayout(new BoxLayout(pall, BoxLayout.Y_AXIS));

            JPanel pone = new JPanel();
            // pone.setLayout(new BoxLayout(pone, BoxLayout.X_AXIS));
            pone.setLayout(new GridLayout(1, 4));
            String struc = "structure.";
            String[] ctspecs = { struc + "unit_cell_type" };
            String[] ctchoice = { NO_SELECTION, "Primitive", "Bravais" };
            ChoicePanelPhase cppcelltype = new ChoicePanelPhase(ctspecs,
                    inputInterface, "unit cell type", ctchoice, this);
            String symmtag = "structure.symmetry.";
            String[] methodspec = { symmtag + "method" };
            String[] methodchoice = { NO_SELECTION, "automatic" };
            ChoicePanelPhase cppmethod = new ChoicePanelPhase(methodspec,
                    inputInterface, "method", methodchoice, this);
            pone.add(cppcelltype);
            pone.add(cppmethod);

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

            String[] crystalspec = { "structure.symmetry.crystal_structure" };
            String[] crystals = { NO_SELECTION, "diamond", "hexagonal", "fcc",
                    "bcc", "hcp", "simple_cubic" };
            ChoicePanelPhase crystal = new ChoicePanelPhase(crystalspec,
                    inputInterface, "crystal structure", crystals, this);

            String[] invsymspec = { "structure.symmetry.sw_inversion" };
            String[] on_off_forc = { "off", "on" };
            ChoicePanelPhase invsym = new ChoicePanelPhase(invsymspec,
                    inputInterface, "inversion", on_off_forc, this);
            // p_cryst.add(crystal);
            // p_cryst.add(invsym);
            pone.add(invsym);

            JPanel p_tspace = new JPanel();
            p_tspace.setLayout(new BoxLayout(p_tspace, BoxLayout.Y_AXIS));
            p_tspace.setBorder(new TitledBorder("tspace"));

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

            String[] latticesymmspec = {
                    "structure.symmetry.tspace.lattice_system",
                    "structure.symmetry.tspace.system" };
            String[] latticesymmchoi = { NO_SELECTION, "primitive",
                    "facecentered", "bodycentered", "basecentered",
                    "rhombohedral", "hexagonal" };
            ChoicePanelPhase latticesymm = new ChoicePanelPhase(
                    latticesymmspec, inputInterface, "lattice system",
                    latticesymmchoi, this);

            String[] genspec = { "structure.symmetry.tspace.num_generators" };
            String[] NUM_GEN = { NO_SELECTION, "1", "2", "3" };
            ChoicePanelPhase gen = new ChoicePanelPhase(genspec,
                    inputInterface, "number of generators", NUM_GEN, this);
            // p_tspace_misc.add(latticesymm);
            // p_cryst.add(latticesymm);
            pone.add(latticesymm);
            // p_tspace_misc.add(gen);

            p_tspace.add(p_tspace_misc);
            p_tspace.add(Box.createVerticalGlue());

            String[] gentablespec = { "structure.symmetry.tspace.generators" };
            JPanel p_tspace_table = new JPanel();
            p_tspace_table.setBorder(new TitledBorder("generators"));

            tbl_tspace = new TableForInputInterface(gentablespec,
                    inputInterface, this);
            tbl_tspace.setColumnSelectionAllowed(true);
            tbl_tspace.setRowSelectionAllowed(true);

            JScrollPane scrPane = new JScrollPane();
            scrPane.getViewport().setView(tbl_tspace.getPanel());
            scrPane.setPreferredSize(new Dimension(500, 70));
            p_tspace_table.add(scrPane);

            p_tspace.add(p_tspace_table);

            int[] intarray = new int[] { 0 };
            latticesymm.registerDisabableGUI(intarray, gen);
            latticesymm.registerDisabableGUI(intarray, tbl_tspace);

            pall.add(pone);
            // pall.add(p_cryst);
            // pall.add(p_tspace);

            setLayout(new BorderLayout());
            add(pall, BorderLayout.NORTH);
            ((JComboBox) ((DefaultCellEditor) tbl_tspace.getColumnModel()
                    .getColumn(0).getCellEditor()).getComponent())
                    .addActionListener(new TSpaceRotComboListener(tbl_tspace));

            checksym = new JButton("check symmetry");
            JPanel ppchecksym = new JPanel();
            ppchecksym.add(checksym);
            pchecksym = new JPanel();
            pchecksym.add(ppchecksym, BorderLayout.WEST);
            pshow = new JPanel();
            pshow.setLayout(new BoxLayout(pshow, BoxLayout.Y_AXIS));
            // pchecksym.add(pshow,BorderLayout.CENTER);

            add(pchecksym, BorderLayout.SOUTH);

            checksym.addActionListener(new ActionListener() {

                public void actionPerformed(ActionEvent e) {
                    new Thread(new SymmetryChecker()).start();
                }

            });
        }

        class SymmetryChecker implements Runnable {
            private String phase_prep = System.getProperty("pviewer.home")
                    + System.getProperty("file.separator") + "bin"
                    + System.getProperty("file.separator") + "phase_prep";

            private DefaultInternalFrameChase panel;

            public void run() {
                if (checkingSymmetry)
                    return;

                checkingSymmetry = true;
                File tmpinput = null;
                try {
                    tmpinput = File.createTempFile("input", null, projDir);
                } catch (IOException ioe) {
                    logger.error("failed to create tmp input file!");
                    checkingSymmetry = false;
                    return;
                }
                if (tmpinput == null) {
                    logger.error("failed to create tmp input file!");
                    checkingSymmetry = false;
                    return;
                }

                inputInterface.saveTo(tmpinput);

                boolean isMesh = inputInterface
                        .getInputInterfacePrimitiveEntry(
                                "accuracy.ksampling.method").getValue().trim()
                        .equalsIgnoreCase("mesh");
                File fname = new File(projDir.getAbsolutePath()
                        + System.getProperty("file.separator")
                        + "file_names.data");
                File tmpfname = new File(fname.getAbsolutePath() + "__");
                if (!fname.exists()) {
                    checkingSymmetry = false;
                    return;
                }
                try {
                    ExternalProgramExecuter.copyBinary(fname.getAbsolutePath(),
                            tmpfname.getAbsolutePath());
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                    checkingSymmetry = false;
                    return;
                }

                BufferedReader reader = null;
                FileWriter writer = null;
                try {
                    reader = Utils.getReader(fname.getAbsolutePath());
                    String li = "";
                    String ac = "";
                    boolean swapinp = false;
                    while ((li = reader.readLine()) != null) {
                        if (!li.trim().startsWith("F_INP")) {
                            ac += li + System.getProperty("line.separator");
                        } else {
                            ac += "F_INP='./" + tmpinput.getName() + "'"
                                    + System.getProperty("line.separator");
                            swapinp = true;
                        }
                    }
                    if (!swapinp)
                        ac += "F_INP='./" + tmpinput.getName() + "'";
                    writer = new FileWriter(fname);
                    writer.write(ac, 0, ac.length());
                } catch (IOException ioe) {
                    try {
                        ExternalProgramExecuter.copyBinary(
                                tmpfname.getAbsolutePath(),
                                fname.getAbsolutePath());
                    } catch (IOException ioerr) {
                        ioerr.printStackTrace();
                    }
                    ioe.printStackTrace();
                    checkingSymmetry = false;
                    return;
                } finally {
                    try {
                        writer.flush();
                        writer.close();
                    } catch (IOException e) {
                        // TODO 自動生成された catch ブロック
                        e.printStackTrace();
                    }
                }

                try {
                    String exe = phase_prep;
                    if (Utils.isWindows())
                        exe += ".exe";
                    BufferedReader[] rd = ExternalProgramExecuter.executeGetBR(
                            exe, projDir);
                    while (rd[0].readLine() != null)
                        ;
                    while (rd[1].readLine() != null)
                        ;
                    rd[0].close();
                    rd[1].close();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                } finally {
                    try {
                        ExternalProgramExecuter.copyBinary(
                                tmpfname.getAbsolutePath(),
                                fname.getAbsolutePath());
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                    }
                }

                logger.info("end of symmetry check");
                File[] files = projDir.listFiles(new FilenameFilter() {
                    private String mat = "output\\d+";

                    public boolean accept(File arg0, String arg1) {
                        if (arg1.matches(mat))
                            return true;
                        return false;
                    }
                });

                tmpinput.delete();
                tmpfname.delete();
                if (files == null || files.length == 0) {
                    checkingSymmetry = false;
                    return;
                }

                Arrays.sort(files);
                File foo = files[files.length - 1];
                BufferedReader rd = null;
                rd = Utils.getReader(foo.getAbsolutePath());
                Vector show = new Vector();
                if (rd != null) {
                    String line = "";
                    try {
                        while ((line = rd.readLine()) != null) {
                            line = line.trim();
                            if (line.startsWith("Bravais lattice:"))
                                show.add(line);
                            if (line.startsWith("Crystallographic"))
                                show.add(line);
                            if (line.startsWith("Space group"))
                                show.add(line);
                            if (line.startsWith("number of k-points in full BZ"))
                                show.add(line);
                            // if (line
                            // .startsWith("number of k-points in irreducible BZ"))
                            // show.add(line);
                            if (line.startsWith("=== k-points generated ===")) {
                                // && isMesh) {
                                rd.readLine();
                                int numK = 0;
                                while (true) {
                                    try {
                                        Double.parseDouble(rd.readLine().trim()
                                                .split("\\s+")[0]);
                                        numK++;
                                    } catch (Exception exc) {
                                        break;
                                    }
                                }
                                show.add("number of generated k-points = "
                                        + String.valueOf(numK));
                            }
                        }
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                    } finally {
                        try {
                            rd.close();
                        } catch (IOException ioe) {
                            ioe.printStackTrace();
                        }
                    }
                }

                String[] res = new String[show.size()];
                JPanel pan = new JPanel();
                pan.setLayout(new BoxLayout(pan, BoxLayout.Y_AXIS));
                show.copyInto(res);
                pshow.removeAll();
                pshow.setLayout(new BoxLayout(pshow, BoxLayout.Y_AXIS));
                if (res != null)
                    for (int i = 0; i < res.length; i++) {
                        JPanel ptmp = new JPanel();
                        ptmp.add(new JLabel(res[i]));
                        pshow.add(ptmp);
                    }
                // pchecksym.add(pan,BorderLayout.CENTER);
                panel = new DefaultInternalFrameChase("symmetry",
                        new Dimension(250, 200));
                panel.getContentPane()
                        .setLayout(
                                new BoxLayout(panel.getContentPane(),
                                        BoxLayout.Y_AXIS));
                panel.getContentPane().add(pshow);
                JButton btn = new JButton("dismiss");
                JPanel pbtn = new JPanel();
                pbtn.add(btn);
                panel.getContentPane().add(pbtn);
                btn.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent ae) {
                        panel.dispose();
                    }
                });

                revalidate();

                foo.delete();

                checkingSymmetry = false;
            }
        }

        public void inputInterfaceEntryChanged(InputInterfaceEntryChangeEvent e) {
            String tag = e.getTag();
            if (tag == null
                    || !tag.equalsIgnoreCase("structure.symmetry.tspace")) {
                return;
            }
            InputInterfaceEntry ent = e.getEntry();
            if (ent == null || !(ent instanceof InputInterfacePrimitiveEntry)) {
                return;
            }

            if (!((InputInterfacePrimitiveEntry) ent).getName()
                    .equalsIgnoreCase("lattice_system")) {
                return;
            }
            ciss.phase_viewer.common.Utils.stop(tbl_tspace);
            tbl_tspace.updateCellEditor(0);
            ((JComboBox) ((DefaultCellEditor) tbl_tspace.getColumnModel()
                    .getColumn(0).getCellEditor()).getComponent())
                    .addActionListener(new TSpaceRotComboListener(tbl_tspace));
        }

        public void inputInterfaceInitializing() {
        }

        public void inputInterfaceInitialized() {
        }
    }
}
