/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/01/19, 20:19
!  AUTHOR(S): KOGA, Junichiro
!  File : CIFImporter.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.File;

import javax.swing.JOptionPane;

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.atomcoord.pmodel.Cif;
import ciss.phase_viewer.atomcoord.pmodel.Pmodel;
import ciss.phase_viewer.atomcoord.pmodel.PmodelException;
import ciss.phase_viewer.atomcoord.pmodel.SpaceGroup;
import ciss.phase_viewer.mainpanel.Desk;

/**
 * CIF形式で記述された原子配置ををインポートするクラス
 * 
 * @author
 */
public class CIFImporter implements Importer {
    private Logger logger = Logger.getLogger(CIFImporter.class.getName());

    public CIFImporter() {
    }

    private String[] getCIFBlockTitles(String cifFile) {
        try {
            return Cif.getDataBlockTitle(cifFile);
        } catch (PmodelException e1) {
            e1.printStackTrace();
            return null;
        }
    }

    public AtomCoords[] getAtomCoordsFrom(String fileName) {

        logger.info("parsing cif file... " + fileName);
        Pmodel pmodel = new Pmodel();

        try {
            pmodel.readCIF(fileName, selectedData);
        } catch (PmodelException e1) {
            e1.printStackTrace();
            logger.error("failed to read CIF : " + fileName);
            return null;
        }

        if (pmodel.getNumSymmetryEquivPosInCif() > 1)
            try {
                pmodel.makeSpaceGroup();
            } catch (PmodelException e) {
                logger.error("failed to generate space group from CIF : "
                        + fileName);
                return null;
            }
        else if (pmodel.getIntTablesNum() > 0) {
            try {
                pmodel.makeSpaceGroup(selectedChoice);
            } catch (PmodelException e) {
                logger.error("failed to generate space group from CIF : "
                        + fileName);
                return null;
            }
        } else {
            logger.error("cannot detect symmetry informations");
            return null;
        }
        try {
            pmodel.makeLattice();
        } catch (PmodelException e) {
            e.printStackTrace();
            logger.error("failed to generate lattice from CIF : " + fileName);
            return null;
        }

        String[] symbols = pmodel.getSymbol();
        boolean hasNumbers = false;
        for (int i = 0; i < symbols.length; i++)
            if (symbols[i].matches(".*\\d+.*")) {
                hasNumbers = true;
                break;
            }
        boolean strip = false;
        if (hasNumbers)
            strip = JOptionPane.showInternalConfirmDialog(Desk.getDesktop()
                    .getSelectedFrame(), "strip numbers from symbol?",
                    "strip numbers", JOptionPane.YES_NO_OPTION,
                    JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION;

        AtomCoords coords = new AtomCoords();
        coords.isCart(true);
        coords.setUnit(AtomCoords.ANGSTROM);

        AtomList list = coords.getAtomList();

        // get cellinfo
        double[][] cellVec = pmodel.getCellVec();

        double[] av = new double[3];
        double[] bv = new double[3];
        double[] cv = new double[3];
        for (int i = 0; i < 3; i++) {
            av[i] = cellVec[0][i];
            bv[i] = cellVec[1][i];
            cv[i] = cellVec[2][i];
        }
        Cell cellv = new Cell(av, bv, cv);
        coords.setCell(cellv);

        int NumAt = pmodel.getNumberOfAtoms();
        double[][] fposs = pmodel.getInternalPosition();
        for (int i = 0; i < fposs.length; i++) {
            logger.debug("fractional pos " + i + " " + fposs[i][0] + ", "
                    + fposs[i][1] + ", " + fposs[i][2]);
        }
        for (int i = 0; i < NumAt; i++) {
            String element = symbols[i];
            if (strip)
                element = element.split("\\d+")[0].split("\\(")[0];
            logger.debug("atom :" + i + " name: " + element);
            double[] cpos = new double[3];
            for (int j = 0; j < 3; j++) {
                cpos[j] = 0d;
                for (int k = 0; k < 3; k++)
                    cpos[j] = cpos[j] + cellVec[k][j] * fposs[i][k];
            }
            Atom at = new Atom(element, cpos);
            list.addAtom(at);
        }

        logger.debug(list);

        return new AtomCoords[] { coords };
    }

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

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

    class CIFFileFilter 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(".cif")) {
                    return true;
                } else {
                    return false;
                }
            }

            return false;
        }

        public String getDescription() {
            return "Crystallographic Information File (*.cif)";
        }
    }

    public boolean hasOptions() {
        return true;
    }

    private int selectedData = 1;
    private int selectedChoice = 0;

    public void createOptionsPanel(boolean isheavy,
            PropertyChangeListener listener, String fileName) {
        String[] titles = getCIFBlockTitles(fileName);
        if (titles == null || titles.length == 0)
            selectedData = 0;
        else if (titles.length == 1)
            selectedData = 1;
        else {
            Object ret = JOptionPane.showInternalInputDialog(Desk.getDesktop()
                    .getSelectedFrame(), "select data", "select data",
                    JOptionPane.INFORMATION_MESSAGE, null, titles, titles[0]);
            if (ret != null)
                for (int i = 0; i < titles.length; i++)
                    if (titles[i] == ret)
                        selectedData = i + 1;
        }

        Pmodel pmodel = new Pmodel();
        try {
            pmodel.readCIF(fileName, selectedData);
        } catch (PmodelException e1) {
            e1.printStackTrace();
            listener.propertyChange(null);
            return;
        }

        if (pmodel.getNumSymmetryEquivPosInCif() <= 1
                && pmodel.getIntTablesNum() > 0) {
            int maxChoice = SpaceGroup.getMaxChoice(pmodel.getIntTablesNum());
            if (maxChoice > 1) {
                Integer[] choices = new Integer[maxChoice];
                for (int i = 0; i < maxChoice; i++)
                    choices[i] = new Integer(i);
                Object ret = JOptionPane.showInternalInputDialog(Desk
                        .getDesktop().getSelectedFrame(), "select choice",
                        "select choice", JOptionPane.INFORMATION_MESSAGE, null,
                        choices, choices[0]);
                if (ret != null)
                    selectedChoice = ((Integer) ret).intValue();
            }
        }

        listener.propertyChange(null);
    }

    public void setOptions(java.util.HashMap options) {
    }

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

}
