/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/10/17, 14:58
!  AUTHOR(S): KOGA, Junichiro
!  File : BasicWiz.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.projectmanipulator.phase.inputwizard;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;

import org.apache.log4j.Logger;

import ciss.phase_viewer.atomcoord.AtomCoords;
import ciss.phase_viewer.atomcoord.Cell;
import ciss.phase_viewer.atomcoord.symmetry.BravaisLattice;
import ciss.phase_viewer.common.PhaseUtils;
import ciss.phase_viewer.input.InputWizard;
import ciss.phase_viewer.input.InputWizardController;
import ciss.phase_viewer.inputinterface.Input;
import ciss.phase_viewer.inputinterface.InputInterface;
import ciss.phase_viewer.inputinterface.InputInterfacePrimitiveEntry;
import ciss.phase_viewer.inputinterface.inputinterfacetable.InputInterfaceTable;
import ciss.phase_viewer.plugins.projectmanipulator.phase.PhaseInputItems;
import ciss.phase_viewer.primitiveguis.ChoicePanelPhase;
import ciss.phase_viewer.primitiveguis.InputPanelPhase;
import ciss.phase_viewer.primitiveguis.tableforinputinterface.TableForInputInterface;

/**
 * 計算条件の, 細かい設定を半自動で決める.
 * 
 * @author
 */
public class BasicWiz extends PhaseInputItems implements InputWizard {
    private Logger logger = Logger.getLogger(BasicWiz.class.getName());

    private JPanel panel;

    protected InputInterface input;

    protected boolean isMetallic = false;

    protected boolean spin = false;

    protected AtomCoords coords;

    protected String optMethod = "bfgs";

    protected double defaultDeltaForce = 5.e-4;

    protected int defaultNumBands = 0;

    protected int[] defaultKmesh = { 1, 1, 1 };

    protected double defaultDE = 1.e-9;

    protected String defaultInitWF = "random_numbers";

    protected double defaultCutoffWF = 12.5d;

    protected double defaultCutoffCD = 50.d;

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

    public String process() {
        if (optimize != null && optimize.isSelected()) {
            InputInterfaceTable atomcd = input
                    .getInputInterfaceTable("structure.atom_list.atoms");
            int mobileInd = atomcd.getIndexFor("mobile");
            logger.debug("mobileInd: " + mobileInd);
            Vector data = atomcd.getTableData();
            for (int i = 0; i < data.size(); i++) {
                String[] row = (String[]) data.get(i);
                row[mobileInd] = "1";
            }
            InputInterfacePrimitiveEntry str = input
                    .getInputInterfacePrimitiveEntry("structure_evolution.method");
            str.setValue("bfgs");
            InputInterfacePrimitiveEntry forc2diis = input
                    .getInputInterfacePrimitiveEntry("structure_evolution.gdiis.c_forc2gdiis");
            forc2diis.setValue("0.05");
            InputInterfacePrimitiveEntry inim = input
                    .getInputInterfacePrimitiveEntry("structure_evolution.gdiis.initial_method");
            inim.setValue("cg");
        }
        InputInterfacePrimitiveEntry cond = input
                .getInputInterfacePrimitiveEntry("control.condition");
        cond.setValue("initial");

        InputInterfacePrimitiveEntry printout_basic = input
                .getInputInterfacePrimitiveEntry("printoutlevel.base");
        printout_basic.setValue("1");
        InputInterfacePrimitiveEntry printout_para = input
                .getInputInterfacePrimitiveEntry("printoutlevel.parallel_debug");
        printout_para.setValue("0");

        if (stress != null && stress.isSelected()) {
            input.getInputInterfacePrimitiveEntry(
                    "structure_evolution.stress.sw_stress").setValue("on");
        }

        return "processed basic input";
    }

    public void setInput(Input input) {
        this.input = (InputInterface) input;
        setInputInterface(this.input);
    }

    public boolean hasPrevious() {
        return true;
    }

    public boolean hasNext() {
        return true;
    }

    public boolean hasFinished() {
        return true;
    }

    public String getName() {
        return "basic configuration";
    }

    public JPanel getGUI() {
        createGUI();
        return this;
    }

    private JCheckBox optimize;

    private JCheckBox stress;

    private InputPanelPhase ippforce;

    public void createGUI() {
        removeAll();
        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        JPanel panel1 = new JPanel();
        panel1.setLayout(new BoxLayout(panel1, BoxLayout.X_AXIS));
        panel1.setBorder(new TitledBorder("num. bands and kmesh"));
        String[] specband = { "accuracy.num_bands" };
        InputPanelPhase numbands = new InputPanelPhase(specband,
                inputInterface, "num. bands", InputPanelPhase.NONE, 8, this);
        JPanel pb = new JPanel();
        pb.add(numbands);
        String[] kmeshSpec = { "accuracy.ksampling.mesh" };
        TableForInputInterface kmeshTable = new TableForInputInterface(
                kmeshSpec, inputInterface, null, this);
        kmeshTable.getModel().addTableModelListener(this);
        numbands.getTextField().setText(String.valueOf(defaultNumBands));
        kmeshTable.setValueAt(String.valueOf(defaultKmesh[0]), 0, 1);
        kmeshTable.setValueAt(String.valueOf(defaultKmesh[1]), 0, 2);
        kmeshTable.setValueAt(String.valueOf(defaultKmesh[2]), 0, 3);
        String[] kmethodSpec = { "accuracy.ksampling.method" };
        String[] kmethodChoice = { "monk", "mesh", "gamma" };
        ChoicePanelPhase cppkmethod = new ChoicePanelPhase(kmethodSpec,
                inputInterface, "method", kmethodChoice, this);
        cppkmethod.getComboBox().setSelectedIndex(0);
        JPanel ptable = new JPanel();
        ptable.setLayout(new BoxLayout(ptable, BoxLayout.X_AXIS));
        ptable.setBorder(new TitledBorder("kmesh"));
        ptable.add(cppkmethod);
        ptable.add(kmeshTable.getPanel());
        panel1.add(pb);
        panel1.add(ptable);

        JPanel panel2 = new JPanel();
        panel2.setBorder(new TitledBorder("cutoff and convergence"));
        panel2.setLayout(new BoxLayout(panel2, BoxLayout.X_AXIS));
        String[] wfspec = { "accuracy.cutoff_wf" };
        String[] cdspec = { "accuracy.cutoff_cd" };
        String[] convspec = { "accuracy.scf_convergence.delta_total_energy" };
        InputPanelPhase ippwf = new InputPanelPhase(wfspec, inputInterface,
                "wave function cutoff", InputPanelPhase.ENERGY, 6, this);
        InputPanelPhase ippcd = new InputPanelPhase(cdspec, inputInterface,
                "charge density cutoff", InputPanelPhase.ENERGY, 6, this);
        InputPanelPhase ippconv = new InputPanelPhase(convspec, inputInterface,
                "SCF convergence", InputPanelPhase.ENERGY, 6, this);
        ippwf.getTextField().setText(String.valueOf(defaultCutoffWF));
        ippcd.getTextField().setText(String.valueOf(defaultCutoffCD));
        ippconv.getTextField().setText(String.valueOf(defaultDE));
        JPanel pwf = new JPanel();
        JPanel pcd = new JPanel();
        JPanel pconv = new JPanel();
        pwf.add(ippwf);
        pcd.add(ippcd);
        pconv.add(ippconv);
        panel2.add(pwf);
        panel2.add(pcd);
        panel2.add(pconv);

        JPanel panel3 = new JPanel();
        panel3.setLayout(new BoxLayout(panel3, BoxLayout.X_AXIS));
        panel3.setBorder(new TitledBorder("structural optimization"));
        optimize = new JCheckBox("optimize structure");
        String[] forceconvspec = { "accuracy.force_convergence.max_force" };
        ippforce = new InputPanelPhase(forceconvspec, inputInterface,
                "force convergence", InputPanelPhase.FORCE, 8, this);
        ippforce.getTextField().setText(String.valueOf(defaultDeltaForce));
        ippforce.setEnabled(false);

        stress = new JCheckBox("calculate stress tensor");

        JPanel pforce = new JPanel();
        pforce.add(ippforce);
        panel3.add(optimize);
        panel3.add(pforce);
        panel3.add(stress);

        optimize.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                ippforce.setEnabled(optimize.isSelected());
            }
        });

        add(panel1);
        add(panel2);
        add(panel3);
    }

    public String getDescription() {
        return "edit basic configuration";
    }

    public void setProperties(HashMap properties) {
        try {
            isMetallic = new Boolean(properties.get("metallic").toString())
                    .booleanValue();
            spin = new Boolean(properties.get("spin").toString())
                    .booleanValue();
            coords = (AtomCoords) properties.get("atomcoords");
        } catch (Exception exc) {
        }
        logger.debug("coords: " + coords);
        defaultNumBands = PhaseUtils.getDefaultNumBands(coords, isMetallic,
                spin);
        logger.debug("default num. bands: " + defaultNumBands);

        Cell newcell = null;
        if (!inputInterface
                .getInputInterfacePrimitiveEntry("structure.unit_cell_type")
                .getValue().equalsIgnoreCase("primitive")) {
            Cell cell = coords.getCell(1);
            if (cell == null)
                coords.convertCell(Cell.CELL_ABC);
            cell = coords.getCell(1);
            double[][] dcell = cell.getDouble();

            double[][] aa = BravaisLattice.getBravaisLattice(dcell[0][0],
                    dcell[0][1], dcell[0][2], dcell[1][0], dcell[1][1],
                    dcell[1][2],
                    BravaisLattice.getLatticeSystemFrom(inputInterface))
                    .getPrimitiveLatticeVector();
            if (aa != null)
                newcell = new Cell(aa[0], aa[1], aa[2]);
        }

        if (newcell == null)
            newcell = coords.getCell(0);

        defaultKmesh = PhaseUtils.getDefaultKmesh(newcell, isMetallic);
        logger.debug("default kmesh: " + defaultKmesh[0] + ", "
                + defaultKmesh[1] + ", " + defaultKmesh[2]);

        boolean hasUSPP = PhaseUtils.hasUSPP(coords);
        if (hasUSPP) {
            defaultCutoffCD = defaultCutoffWF * 9.d;
        } else {
            defaultCutoffCD = defaultCutoffWF * 4.d;
        }
        logger.debug("default cutoff, wf: " + defaultCutoffWF + ", cd: "
                + defaultCutoffCD);
    }

    public void setParent(InputWizardController parent) {
    }

}
