/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2005/10/11, 13:31
!  AUTHOR(S): KOGA, Junichiro
!  File : AtomConfigPanel.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.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JInternalFrame;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;

import org.apache.log4j.Logger;

import ciss.phase_viewer.acviewer.ACVData;
import ciss.phase_viewer.acviewer.ConfigData;
import ciss.phase_viewer.acviewer.ConfigDataUpdateEvent;
import ciss.phase_viewer.acviewer.MainPanel;
import ciss.phase_viewer.acviewer.scenegraphelements.TGAtom;
import ciss.phase_viewer.acviewer.scenegraphelements.atom.ACVAtomEditor;
import ciss.phase_viewer.acviewer.scenegraphelements.atom.AtomSelectionCanvas;
import ciss.phase_viewer.atomcoord.Atom;
import ciss.phase_viewer.atomcoord.AtomCoords;
import ciss.phase_viewer.atomcoord.AtomEditor;
import ciss.phase_viewer.atomcoord.AtomEvent;
import ciss.phase_viewer.atomcoord.AtomListener;
import ciss.phase_viewer.common.Command;
import ciss.phase_viewer.common.MyJMenu;
import ciss.phase_viewer.common.MyJMenuItem;
import ciss.phase_viewer.common.Utils;
import ciss.phase_viewer.inputinterface.InputInterface;
import ciss.phase_viewer.mainpanel.Desk;
import ciss.phase_viewer.mainpanel.InternalFrameChase;
import ciss.phase_viewer.primitiveguis.tableforinputinterface.TableForInputInterface;
import ciss.phase_viewer.primitiveguis.tableforinputinterface.TableRightClickListener;

/**
 * 原子の座標を表示したり編集したりするパネル.
 * 
 * @author
 */
public class AtomConfigPanel extends InternalFrameChase {
    // public class AtomConfigPanel extends FrameChase {
    private Logger logger = Logger.getLogger(AtomConfigPanel.class.getName());
    private MainPanel parent;

    /**
     * @param parent
     *            親パネル.
     */
    public AtomConfigPanel(MainPanel parent) {
        // super("view/edit atomic coordinates",true,true,true,true,new
        // Dimension(600, 600),InternalFrameChase.EAST);
        super("view/edit atomic coordinates", new Dimension(570, 530));
        this.parent = parent;
        parent.addDisposeOnExit(this);
        init();
    }

    private AtomCoordinatesPanel acp;

    private void init() {
        Container cont = getContentPane();
        cont.setLayout(new BoxLayout(cont, BoxLayout.Y_AXIS));
        JTabbedPane tp = new JTabbedPane();
        acp = new AtomCoordinatesPanel(parent);
        tp.addTab("atomic configuration", acp);
        tp.addTab("unit cell", new CellPanel(parent));
        cont.add(tp);
        setJMenuBar(new MenuBar(this));
        setVisible(true);
    }

    public void dispose() {
        super.dispose();
        ((TGAtom) parent.getRootTransform()).removeAtomSelectionCanvas(acp);
    }

    class MenuBar extends JMenuBar {
        private JInternalFrame frame;

        protected MenuBar(JInternalFrame frame) {
            super();
            this.frame = frame;
            init();
        }

        private void init() {
            MyJMenu file = new MyJMenu("File", KeyEvent.VK_F);
            MyJMenuItem exit = new MyJMenuItem("exit", KeyEvent.VK_X);
            file.add(exit);
            add(file);

            exit.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    frame.dispose();
                }
            });

        }
    }

    class AtomCoordinatesPanel extends JPanel implements TableModelListener,
            ListSelectionListener, TableRightClickListener, AtomListener,
            AtomSelectionCanvas, ConfigData {
        private Logger logger = Logger.getLogger(AtomCoordinatesPanel.class
                .getName());
        private MainPanel parent;
        private InputInterface inputInterface;
        private ACVData data;
        private TableForInputInterface tfatom;
        private AtomCoords coords;

        private JScrollPane scrPane;

        protected AtomCoordinatesPanel(MainPanel parent) {
            this.parent = parent;
            this.data = parent.getData();
            this.inputInterface = data.getInputInterface();
            ((TGAtom) this.parent.getRootTransform())
                    .addAtomSelectionCanvas(this);
            // coords = data.getFirstFrame();
            coords = parent.getCD().getAtomCoords();
            setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
            logger.debug("at AtomCoordinatesPanel.init()");
            try {
                init();
            } catch (Exception exc) {
                exc.printStackTrace();
            }
            logger.debug("AtomCoordinatesPanel initialized.");
        }

        private void init() {
            parent.getCD().register(this);
            add(createAtomTable());
            add(createButtons());
        }

        private JPanel createAtomTable() {
            JPanel p_atom_all = new JPanel();
            p_atom_all.setLayout(new BoxLayout(p_atom_all, BoxLayout.Y_AXIS));

            String[] atmtag = new String[] { data.getTag() };
            int[] map = { 0, 1, 2, 3, 4 };
            tfatom = new TableForInputInterface(coords, atmtag, inputInterface,
                    map, this);

            ((DefaultTableModel) tfatom.getModel()).addTableModelListener(this);

            JPanel panelAtom = new JPanel();
            panelAtom.setLayout(new BoxLayout(panelAtom, BoxLayout.Y_AXIS));
            panelAtom.add(tfatom.getPanel());

            scrPane = new JScrollPane();
            scrPane.getViewport().setView(tfatom.getPanel());
            p_atom_all.add(scrPane);

            tfatom.addTableRightClickListener(this);

            return p_atom_all;
        }

        private JTextField textselect;

        private JPanel createButtons() {
            JPanel p = new JPanel();
            p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));

            p.add(buttons1());
            // p.add(buttons2());

            return p;
        }

        private JPanel buttons1() {
            textselect = new JTextField(7);
            JButton btnselect = new JButton("select");
            JPanel pselect = new JPanel();
            pselect.setLayout(new BoxLayout(pselect, BoxLayout.X_AXIS));
            pselect.add(textselect);
            pselect.add(btnselect);

            btnselect.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    String foo = textselect.getText();
                    if (foo == null || foo.trim().length() == 0) {
                        return;
                    }
                    if (!Utils.isNumber(foo)) {
                        logger.error("enter a positve integer.");
                        return;
                    }
                    selectAtomTableRow(tfatom.getLocation(),
                            Integer.parseInt(foo));
                }
            });

            JButton btneditatom = new JButton("edit selected atom");
            btneditatom.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    int row = tfatom.getSelectedRow();
                    if (row >= 0) {
                        bootAtomEditor(row);
                    } else {
                        logger.info("no atom selected.");
                    }
                }
            });

            JButton btnremove = new JButton("remove selected atom");
            btnremove.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    removeSelectedAtom();
                }
            });

            JButton btnadd = new JButton("add new atom");
            btnadd.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    addNewAtom();
                }
            });

            JPanel paneledit = new JPanel();
            paneledit.setLayout(new BoxLayout(paneledit, BoxLayout.X_AXIS));
            paneledit.setBorder(new TitledBorder("edit atomic configuration"));

            paneledit.add(pselect);
            paneledit.add(btneditatom);
            paneledit.add(btnadd);
            paneledit.add(btnremove);

            return paneledit;
        }

        private JPanel buttons2() {
            JPanel panel = new JPanel();
            panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));

            JButton btnsave = new JButton("save");
            btnsave.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    coords.atomCoords2InputInterface(parent.getData()
                            .getInputInterface(), parent.getData().getTag());
                }
            });
            panel.add(btnsave);

            JButton btnundo = new JButton("undo");
            btnundo.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    coords.getAtomList().undo();
                }
            });
            panel.add(btnundo);

            JButton btnredo = new JButton("redo");
            btnredo.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    coords.getAtomList().redo();
                }
            });
            panel.add(btnredo);

            return panel;
        }

        public void tableChanged(TableModelEvent e) {
            Command command = (Command) e.getSource();
            command.execute(e);

            // if ( tfatom != null ) {
            // if ( ((TableModelForInputInterface)
            // tfatom.getModel()).batchUpdate() ) {
            // return;
            // }
            // }

            logger.debug("coords: " + coords);
            parent.getCD().setCoords(coords);
        }

        public void valueChanged(ListSelectionEvent e) {
            if (selecting)
                return;
            logger.debug("list selection!");
            logger.debug(e);
            int last = e.getLastIndex();
            parent.selectedRow(tfatom.getSelectedRow());
        }

        /**
         * テーブルが右クリックされた際に呼ばれる.
         * 
         * @param point
         *            右クリックされた際のその行のマウスポインターの位置.
         * @param command
         *            どんな処理を施すかを指定する文字列. 設定ファイルに書いてある内容を見ること.
         */
        public void tableRightClicked(Point point, String command) {
            if (command.equals("edit")) {
                bootAtomEditor(tfatom.rowAtPoint(point));
            } else if (command.equals("delete")) {
                ((DefaultTableModel) tfatom.getModel()).removeRow(tfatom
                        .rowAtPoint(point));
            } else if (command.equals("select")) {
                String res = JOptionPane.showInputDialog(Desk.getDesktop(),
                        "enter a row number", "row selection",
                        JOptionPane.INFORMATION_MESSAGE);
                if (!Utils.isNumber(res)) {
                    logger.error("enter a positve integer.");
                    return;
                }
                selectAtomTableRow(point, Integer.parseInt(res));
            } else if (command.equals("new")) {
                bootAtomEditor(tfatom.rowAtPoint(point), true);
            }
        }

        private void bootAtomEditor(int row) {
            bootAtomEditor(row, false);
        }

        private void bootAtomEditor(int row, boolean newAtom) {
            Atom atom = coords.getAtomList().getAtomAt(row);
            logger.debug(atom);
            ACVAtomEditor editor = new ACVAtomEditor(inputInterface
                    .getInputInterfaceTableSpecManager()
                    .getTableSpec(data.getTag()).getTableColumns(), atom,
                    newAtom, row, "edit attributes for atom no. "
                            + new Integer(row + 1), new Dimension(400, 250),
                    parent);
            editor.addAtomListener(this);
            parent.addDisposeOnExit(editor);
        }

        private void selectAtomTableRow(Point point, int num) {
            int old = tfatom.rowAtPoint(point);
            if (num == 0) {
                num = 1;
            }
            if (num >= tfatom.getRowCount()) {
                logger.error("exceeded max. row number.");
                return;
            }
            tfatom.setRowSelectionInterval(num - 1, num - 1);
            int rowHeight = tfatom.getRowHeight();
            int geta = rowHeight * (tfatom.getSelectedRow() - old);
            Point newPoint = new Point(point.x, point.y + geta);
            scrPane.getViewport().setViewPosition(newPoint);
            revalidate();
        }

        public void atomStateChanged(AtomEvent e) {
            coords.saveState();
            Atom atom = e.getAtom();
            int ind = e.getIndex();
            if (ind < 0) {
                try {
                    ind = coords.getAtomList().size();
                } catch (Exception exc) {
                    logger.error("atom coords not allocated?");
                }
            }

            if (ind < coords.getNumAt()) {
                coords.getAtomList().replaceAtomAt(ind, atom);
            } else {
                coords.getAtomList().addAtom(atom);
            }
            logger.debug("atom now: " + coords.getAtomList().getAtomAt(ind));
            logger.debug(e);

            parent.getCD().setCoords(coords);

            selectAtomTableRow(tfatom.getLocation(), ind + 1);
            coords.finalizeState();
        }

        private void addNewAtom() {
            AtomEditor editor = new AtomEditor(inputInterface
                    .getInputInterfaceTableSpecManager()
                    .getTableSpec(data.getTag()).getTableColumns(),
                    "edit attributes for new atom", new Dimension(400, 250));
            editor.addAtomListener(this);
        }

        private void removeSelectedAtom() {
            int[] rows = tfatom.getSelectedRows();
            if (rows != null) {
                for (int i = 0; i < rows.length; i++) {
                    int targetRow = rows[i];
                    ((DefaultTableModel) tfatom.getModel())
                            .removeRow(targetRow);
                }
            }
        }

        public void configDataUpdate() {
            if (tfatom != null) {
                coords = parent.getCD().getAtomCoords();
                tfatom.removeListeners();
                coords.updateTable(tfatom.getModel(), null);
                tfatom.restoreListeners();
            }
        }

        public void configDataUpdate(boolean rescaleOnUpdate,
                ConfigDataUpdateEvent e) {
            configDataUpdate();
        }

        public boolean needsUpdate() {
            return true;
        }

        private boolean selecting = false;

        public void selected(
                ciss.phase_viewer.acviewer.scenegraphelements.atom.AtomObject obj) {
            logger.debug("selected atom: " + obj.getIDint());
            selecting = true;
            selectAtomTableRow(tfatom.getLocation(), obj.getIDint());
            selecting = false;
        }

        public void deselected(
                ciss.phase_viewer.acviewer.scenegraphelements.atom.AtomObject obj) {
        }

        public void deselectAll() {
        }

    }

}
