/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/11/14 20:35:05
!  AUTHOR(S): KOGA, Junichiro
!  File : CrystalStudioASCIIImporter.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.util.HashMap;
import java.util.Vector;

import javax.swing.filechooser.FileFilter;

import org.apache.log4j.Logger;

import ciss.phase_viewer.atomcoord.Atom;
import ciss.phase_viewer.atomcoord.AtomCoords;
import ciss.phase_viewer.atomcoord.Cell;
import ciss.phase_viewer.common.Utils;

public class CrystalStudioASCIIImporter implements Importer {
    private Logger logger = Logger.getLogger(CrystalStudioASCIIImporter.class
            .getName());

    public CrystalStudioASCIIImporter() {
    }

    private BufferedReader reader = null;

    public AtomCoords[] getAtomCoordsFrom(String fileName) {
        coords = new AtomCoords();
        try {
            try {
                reader = new BufferedReader(new FileReader(fileName));
                String line = "";
                while ((line = reader.readLine()) != null) {
                    if (!parseLine(line.trim()))
                        return null;
                }
            } catch (IOException ioe) {
                logger.error("failed read from : " + fileName);
                ioe.printStackTrace();
            } finally {
                try {
                    reader.close();
                } catch (IOException io) {
                }
            }
            coords.convert(AtomCoords.TO_CART, AtomCoords.TO_ANG);
        } catch (Exception exc) {
            exc.printStackTrace();
        }
        if (coords.getNumAt() != 0) {
            return new AtomCoords[] { coords };
        } else {
            return null;
        }
    }

    private AtomCoords coords;

    private boolean readCell = false;

    private boolean isCart = false;

    private int unit = AtomCoords.ANGSTROM;

    private Vector elemSpec = new Vector();

    class Elem {
        String elemName = "X";

        int numAtoms = 0;

        String bondType = "";

        public String toString() {
            return "elementName: " + elemName + " num.atoms: "
                    + String.valueOf(numAtoms) + " bond type: " + bondType;
        }
    }

    private boolean parseLine(String line) {
        if (line.startsWith("#") || line.length() == 0)
            return true;
        if (!readCell && line.startsWith("Original")) {
            try {
                String avec = reader.readLine();
                String bvec = reader.readLine();
                String cvec = reader.readLine();
                logger.debug("avec, bvec, cvec: ");
                logger.debug(avec);
                logger.debug(bvec);
                logger.debug(cvec);
                String[] av = avec.trim().split("\\s+");
                String[] bv = bvec.trim().split("\\s+");
                String[] cv = cvec.trim().split("\\s+");
                double[] dav = new double[3];
                double[] dbv = new double[3];
                double[] dcv = new double[3];
                try {
                    for (int i = 0; i < 3; i++) {
                        dav[i] = Double.parseDouble(av[i]);
                        dbv[i] = Double.parseDouble(bv[i]);
                        dcv[i] = Double.parseDouble(cv[i]);
                    }
                } catch (NumberFormatException nfe) {
                    return false;
                } catch (ArrayIndexOutOfBoundsException aobe) {
                    return false;
                }

                Cell cell = new Cell(av, bv, cv);
                coords.setCell(cell);

                String cellang = reader.readLine(); // skip this one
                logger.debug("cell ang: " + cellang);

                String cart_and_unit = reader.readLine();
                String[] dat = cart_and_unit.trim().split("\\s+");
                if (dat[0].equalsIgnoreCase("cartesian"))
                    isCart = true;
                else if (dat[0].equalsIgnoreCase("fractional"))
                    isCart = false;
                if (dat.length >= 2 && dat[1].length() >= 1) {
                    String stru = dat[1].substring(1, dat[1].length() - 1);
                    if (stru.equalsIgnoreCase("angstrom"))
                        unit = AtomCoords.ANGSTROM;
                    else if (stru.equalsIgnoreCase("bohr"))
                        unit = AtomCoords.BOHR;
                }
                String[] spec = reader.readLine().trim().split(",");
                for (int i = 0; i < spec.length; i++) {
                    Elem el = new Elem();
                    String[] spec_ = spec[i].trim().split("\\s+");
                    for (int j = 0; j < spec_.length; j++) {
                        if (Utils.isNumber(spec_[j])) {
                            el.numAtoms = Integer.parseInt(spec_[j]);
                        } else if (j != 0 && !Utils.isNumber(spec_[j])) {
                            el.bondType = spec_[j];
                        } else {
                            if (spec_[j].indexOf("+") >= 0)
                                el.elemName = spec_[j].split("\\+")[0];
                            else if (spec_[j].indexOf("-") >= 0)
                                el.elemName = spec_[j].split("\\-")[0];
                            else
                                el.elemName = spec_[j];
                        }
                    }
                    logger.debug("elem spec: " + el);
                    elemSpec.add(el);
                }
                readCell = true;
            } catch (ArrayIndexOutOfBoundsException aiobe) {
                logger.error("not enough data: " + line);
                return false;
            } catch (IOException ioe) {
                logger.error("failed read");
                return false;
            } catch (NumberFormatException nfe) {
                logger.error("could not convert " + line + " to a number.");
                return false;
            } catch (NullPointerException npe) {
                logger.error("not enough data.");
                return false;
            }

            coords.isCart(isCart);
            coords.setUnit(unit);

            try {
                for (int i = 0; i < elemSpec.size(); i++) {
                    Elem e = (Elem) elemSpec.get(i);
                    String elemName = e.elemName;
                    for (int j = 0; j < e.numAtoms; j++) {
                        String[] co = reader.readLine().trim().split("\\s+");
                        double[] tmpdouble = new double[3];
                        for (int k = 0; k < co.length; k++) {
                            logger.debug("pos " + k + " : " + co[k]);
                            try {
                                tmpdouble[k] = Double.parseDouble(co[k]);
                            } catch (NumberFormatException exc) {
                                return true;
                            }
                        }
                        Atom atom = new Atom(elemName, tmpdouble);
                        coords.getAtomList().addAtom(atom);
                    }
                }
            } catch (IOException ioe) {
                logger.error("not enough data.");
                return false;
            }
        }

        return true;
    }

    public boolean isImportable(String fileName) {
        return !new File(fileName).isDirectory();
    }

    public void createOptionsPanel(boolean heavy,
            PropertyChangeListener listener, String fileName) {
    }

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

            public boolean accept(File f) {
                return true;
            }

            public String getDescription() {
                return "Crystal Studio file";
            }

        };
    }

    public String getType() {
        return "Crystal Studio file";
    }

    public boolean hasOptions() {
        return false;
    }

    public void setOptions(HashMap options) {
    }
}
