/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/01/19, 20:33
!  AUTHOR(S): KOGA, Junichiro
!  File : XYZImporter.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.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Vector;

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.common.ConstParameters;

/**
 * 「XYZ形式」のファイルをインポートするクラス.
 * 
 * @author
 */
public class XYZImporter implements Importer {
    private DecimalFormat formater = ConstParameters.formater;
    private Logger logger = Logger.getLogger(XYZImporter.class.getName());

    public XYZImporter() {
    }

    public ciss.phase_viewer.atomcoord.AtomCoords[] getAtomCoordsFrom(
            String fileName) {
        String mol2 = new File(fileName).getParent()
                + System.getProperty("file.separator") + "grid.mol2";
        Cell cell_from_mol2 = null;
        if (new File(mol2).exists()) {
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new FileReader(mol2));
                String line = "";
                while ((line = reader.readLine()) != null) {
                    line = line.trim();
                    if (line.equals("grid file")) {
                        String tripos_atom = reader.readLine();
                        if (tripos_atom == null) {
                            break;
                        }
                        tripos_atom = tripos_atom.trim();
                        if (!tripos_atom.equals("@<TRIPOS>ATOM")) {
                            break;
                        }
                        double[][] cellvector = new double[8][3];
                        for (int i = 0; i < 8; i++) {
                            String foo = reader.readLine().trim();
                            String[] array = foo.split("\\s+");
                            cellvector[i][0] = Double.parseDouble(array[2]);
                            cellvector[i][1] = Double.parseDouble(array[3]);
                            cellvector[i][2] = Double.parseDouble(array[4]);
                        }
                        double[][] cell_double = new double[3][3];
                        for (int i = 0; i < 3; i++) {
                            cell_double[0][i] = cellvector[4][i]
                                    - cellvector[0][i];
                            cell_double[1][i] = cellvector[2][i]
                                    - cellvector[0][i];
                            cell_double[2][i] = cellvector[1][i]
                                    - cellvector[0][i];
                        }
                        cell_from_mol2 = new Cell(cell_double[0],
                                cell_double[1], cell_double[2]);
                    }
                }
            } catch (Exception exc) {
                logger.error(exc);
                exc.printStackTrace();
            } finally {
                try {
                    reader.close();
                } catch (IOException ioe) {
                }
            }
        }

        BufferedReader br = null;
        Vector vec = new Vector();
        try {
            FileReader reader = new FileReader(fileName);
            br = new BufferedReader(reader);
            String str = new String();
            logger.info("parsing xyz file... " + fileName);
            while (true) {
                String strnum = br.readLine();
                if (strnum == null) {
                    break;
                }
                AtomCoords coords = new AtomCoords();
                AtomList list = coords.getAtomList();
                coords.setUnit(AtomCoords.ANGSTROM);
                coords.isCart(true);
                int NumAt = Integer.parseInt(strnum.trim());
                str = br.readLine();
                if (str == null) {
                    break;
                }
                String[] comments = str.trim().split("\\s+");

                if (cell_from_mol2 != null) {
                    coords.setCell(cell_from_mol2);
                } else if (str.startsWith("frame no.") && comments.length >= 13) {
                    String[] avec = { comments[4], comments[5], comments[6] };
                    String[] bvec = { comments[7], comments[8], comments[9] };
                    String[] cvec = { comments[10], comments[11], comments[12] };
                    Cell cell = new Cell(avec, bvec, cvec);
                    coords.setCell(cell);
                }

                for (int i = 0; i < NumAt; i++) {
                    str = br.readLine();
                    if (str == null) {
                        break;
                    }
                    logger.debug("line " + i + ": " + str);
                    String[] c = str.trim().split("\\s+");
                    String[] co = new String[3];
                    String element = new String();
                    if (c.length < 4) {
                        logger.warn("invalid data found at line " + i);
                        return null;
                    } else {
                        element = c[0];
                        for (int j = 1; j < 4; j++) {
                            try {
                                Double.parseDouble(c[j]);
                            } catch (NumberFormatException nfe) {
                                logger.warn("non-numerical data for coordinates found at line"
                                        + i);
                                return null;
                            }
                            co[j - 1] = c[j];
                        }
                    }
                    Atom atom = new Atom(element, co);
                    logger.debug("atom: " + atom);
                    if (c.length >= 7) {
                        String[] force = new String[3];
                        force[0] = c[4];
                        force[1] = c[5];
                        force[2] = c[6];
                        atom.setForce(force);
                    }
                    list.addAtom(atom);
                }
                vec.addElement(coords);
            }
        } catch (Exception exc) {
            logger.warn("invalid xyz file");
            return null;
        } finally {
            try {
                br.close();
            } catch (IOException ioe) {
            }
        }
        if (vec.size() == 0) {
            return null;
        }

        if (options.get(XYZOptionsPanel.FRAME) != null) {
            targetFrame = ((FrameCombo) options.get(XYZOptionsPanel.FRAME))
                    .getTargetFrame(vec.size());
        }
        if (targetFrame < 0) {
            AtomCoords[] ret = new AtomCoords[vec.size()];
            vec.copyInto(ret);
            return ret;
        } else {
            return new AtomCoords[] { (AtomCoords) vec.get(targetFrame) };
        }
    }

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

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

    public boolean hasOptions() {
        return true;
    }

    private PropertyChangeListener listener;

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

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

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

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

    public boolean isImportable(String fileName) {
        if (new File(fileName).isDirectory()) {
            return false;
        }
        return getFileFilter().accept(new File(fileName));
    }
}

class XYZFileFilter extends javax.swing.filechooser.FileFilter {
    public boolean accept(File f) {
        if (f.isDirectory()) {
            return true;
        }

        String fileName = f.getName().toLowerCase();

        if (fileName != null) {
            if (fileName.endsWith(".xyz") || fileName.endsWith(".tr2")
                    || fileName.endsWith(".trj2") || fileName.endsWith(".tj2")) {
                return true;
            } else {
                return false;
            }
        }

        return false;
    }

    public String getDescription() {
        return "XYZ file, Trajectory file (*.xyz, *.tr2)";
    }
}
