/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/01/25, 17:49
!  AUTHOR(S): KOGA, Junichiro
!  File : XYZExporter.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.atomcoord.io;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeListener;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.HashMap;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;

import org.apache.log4j.Logger;

import ciss.phase_viewer.atomcoord.Atom;
import ciss.phase_viewer.atomcoord.AtomCoords;
import ciss.phase_viewer.atomcoord.AtomList;
import ciss.phase_viewer.atomcoord.Cell;
import ciss.phase_viewer.mainpanel.InternalFrameChase;

/**
 * AtomCoordsオブジェクトをXYZ形式にエクスポート. 一行目: 原子数 二行目(一応cell): ax ay az bx by bz cx cy
 * cz (可能な場合) 三行目以降: elemname posx posy posz forcx forcy forcz (if force is
 * available)
 * 
 * @author
 */
public class XYZExporter implements Exporter {
    private Logger logger = Logger.getLogger(XYZExporter.class.getName());

    /** Creates a new instance of XYZExporter */
    public XYZExporter() {
    }

    public boolean writeAtomCoordsTo(
            ciss.phase_viewer.atomcoord.AtomCoords[] coords, String fileName) {
        logger.info("exporting atomic coordinates in xyz-format to file "
                + fileName);
        if (coords == null || coords.length == 0) {
            return false;
        }

        PrintWriter writer = null;
        int numFrame = coords.length;
        if (options.get(XYZOptionsPanel.FRAME) != null) {
            targetFrame = ((FrameCombo) options.get(XYZOptionsPanel.FRAME))
                    .getTargetFrame(numFrame);
        }

        try {
            writer = new PrintWriter(new BufferedWriter(
                    new FileWriter(fileName)));
            for (int i = 0; i < coords.length; i++) {
                if (i != targetFrame && targetFrame >= 0) {
                    continue;
                }
                logger.info("doing frame no. " + i);
                boolean ret = writeCoordsTo(coords[i], writer, i);
                if (!ret) {
                    return false;
                }
            }
        } catch (Exception exc) {
            logger.error("failed export");
            exc.printStackTrace();
            return false;
        } finally {
            try {
                writer.close();
            } catch (Exception e) {
            }
        }
        logger.info("...done");
        return true;
    }

    private boolean writeCoordsTo(AtomCoords coords, PrintWriter writer, int i) {
        String numAt = String.valueOf(coords.getNumAt());
        Cell cell = coords.getCell(0);
        String strcell = "frame no. " + String.valueOf(i);
        if (cell != null) {
            String[][] array = cell.getCell();
            try {
                strcell += " cell: " + array[0][0] + " " + array[0][1] + " "
                        + array[0][2] + " " + array[1][0] + " " + array[1][1]
                        + " " + array[1][2] + " " + array[2][0] + " "
                        + array[2][1] + " " + array[2][2];
            } catch (Exception exc) {
                strcell = "frame no. " + String.valueOf(i);
            }
        }

        writer.println(numAt);
        writer.println(strcell);
        AtomList list = coords.getAtomList();
        for (int iat = 0; iat < list.size(); iat++) {
            Atom at = list.getAtomAt(iat);
            String ele = at.getElementName();
            String[] pos = at.getPos();
            double[] dforce = at.getForceDouble();
            String vector = " ";
            if (type.equals(XYZOptionsPanel.XMAKEMOL)) {
                vector = " atom_vector ";
            }
            if (dforce != null && dforce.length >= 3) {
                writer.println(ele + " " + pos[0] + " " + pos[1] + " " + pos[2]
                        + vector + dforce[0] * doubleforce + " " + dforce[1]
                        * doubleforce + " " + dforce[2] * doubleforce);
            } else {
                writer.println(ele + " " + pos[0] + " " + pos[1] + " " + pos[2]);
            }
        }
        return true;
    }

    private PropertyChangeListener listener;

    public void createOptionsPanel(boolean heavy,
            PropertyChangeListener listener, String fileName) {
        this.listener = listener;
        if (!heavy) {
            XYZOptions opts = new XYZOptions(this, listener);
        } else {
            XYZHeavyOptions hopts = new XYZHeavyOptions(this, listener);
        }
    }

    public boolean hasOptions() {
        return true;
    }

    public String getType() {
        return "XYZ";
    }

    public javax.swing.filechooser.FileFilter getFileFilter() {
        return new XYZFileFilter();
    }

    private FrameCombo select;

    private HashMap options = new HashMap();
    private double doubleforce = 1.0;
    private String type = XYZOptionsPanel.GENERIC;
    private int targetFrame = 0;

    public void setOptions(java.util.HashMap options) {
        if (options == null) {
            return;
        }
        this.options = options;
        try {
            String forceFactor = options.get(XYZOptionsPanel.FORCE).toString();
            doubleforce = Double.parseDouble(forceFactor);
        } catch (Exception exc) {
            logger.debug(exc);
        }

        try {
            type = options.get(XYZOptionsPanel.TYPE).toString();
        } catch (Exception exc) {
        }
        logger.debug("type: " + type);
    }

}

class XYZOptions extends InternalFrameChase {
    XYZOptions(AtomCoordsIO parent, PropertyChangeListener listener) {
        super("Options", true, true, true, true, new Dimension(330, 120));
        getContentPane().add(new XYZOptionsPanel(this, parent, listener));
    }
}

class XYZHeavyOptions extends InternalFrameChase {
    XYZHeavyOptions(AtomCoordsIO parent, PropertyChangeListener listener) {
        super("Options", new Dimension(330, 120));
        getContentPane().add(new XYZOptionsPanel(this, parent, listener));
        pack();
        setVisible(true);
    }
}

class XYZOptionsPanel extends JPanel {
    private Logger logger = Logger.getLogger(XYZOptionsPanel.class);
    private JInternalFrame iframe;
    private JFrame jframe;
    private AtomCoordsIO io;

    static String GENERIC = "generic";
    static String XMAKEMOL = "xmakemol";
    private String[] TYPE_CHOICE = { GENERIC, XMAKEMOL };
    static String TYPE = "type";
    static String FRAME = "frame";
    static String FORCE = "force";

    private PropertyChangeListener listener;

    XYZOptionsPanel(JInternalFrame iframe, AtomCoordsIO io,
            PropertyChangeListener listener) {
        this.iframe = iframe;
        this.io = io;
        this.listener = listener;
        init();
    }

    XYZOptionsPanel(JFrame jframe, AtomCoordsIO io,
            PropertyChangeListener listener) {
        this.jframe = jframe;
        this.io = io;
        this.listener = listener;
        init();
    }

    private JTextField forceFactor;
    private JComboBox comboType;
    private FrameCombo frameCombo;

    private void init() {
        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        JPanel p = new JPanel();
        p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
        JPanel ptype = new JPanel();
        ptype.setBorder(new TitledBorder("type"));
        comboType = new JComboBox(TYPE_CHOICE);
        ptype.add(comboType);
        JPanel pforce = new JPanel();
        pforce.setBorder(new TitledBorder("force factor"));
        forceFactor = new JTextField(3);
        pforce.add(forceFactor);
        forceFactor.setText("1");

        frameCombo = new FrameCombo();

        p.add(ptype);
        p.add(pforce);
        p.add(frameCombo);
        add(p);

        JPanel btns = new JPanel();
        btns.setLayout(new BoxLayout(btns, BoxLayout.X_AXIS));
        JButton ok = new JButton("ok");
        JButton can = new JButton("cancel");
        btns.add(ok);
        btns.add(can);
        add(btns);
        ok.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                HashMap map = new HashMap();
                map.put(FORCE, forceFactor.getText().trim());
                map.put(FRAME, frameCombo);
                map.put(TYPE, comboType.getSelectedItem().toString());
                io.setOptions(map);
                if (iframe == null) {
                    jframe.dispose();
                } else {
                    iframe.dispose();
                }
                listener.propertyChange(null);
            }
        });
        can.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                if (iframe == null) {
                    jframe.dispose();
                } else {
                    iframe.dispose();
                }
                logger.info("operation canceled.");
            }
        });
    }

}
