/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/11/15 16:01:33
!  AUTHOR(S): KOGA, Junichiro
!  File : FENERGMonitor.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.ekcal.file;

import java.awt.Color;
import java.awt.Dimension;
import java.util.Vector;

import org.apache.log4j.Logger;

import ciss.phase_viewer.atomcoord.Cell;
import ciss.phase_viewer.file.ChaseFile;
import ciss.phase_viewer.file.SimpleMonitor;
import ciss.phase_viewer.graph.GraphPanel;
import ciss.phase_viewer.graph.SimpleChart;
import ciss.phase_viewer.graph.XYData;
import ciss.phase_viewer.inputinterface.DataManager;
import ciss.phase_viewer.inputinterface.InputInterface;
import ciss.phase_viewer.projectbrowser.ProjectInfo;

public class FENERGMonitor extends SimpleMonitor {
    private Logger logger = Logger.getLogger(FENERGMonitor.class.getName());

    private double[][] reclat;

    private double[] prevk = new double[] { 0, 0, 0 };

    private double dk = 0d;

    private int numBands = -1;

    private int spin = 1;

    public FENERGMonitor(ProjectInfo projectInfo) {
        super(projectInfo);
        init();
    }

    private void init() {
        String finp = projectInfo.getProjectDirectory()
                + System.getProperty("file.separator")
                + projectInfo.getChaseFileManager().getFile("F_INP")
                        .getFileName();
        DataManager dm = new DataManager(finp);
        if (!dm.parse()) {
            logger.error("invalid input file");
            return;
        }
        InputInterface inputInterface = dm.getInputInterface();
        try {
            numBands = Integer.parseInt(inputInterface
                    .getInputInterfacePrimitiveEntry("accuracy.num_bands")
                    .getValue());
        } catch (NumberFormatException npe) {
            logger.error("invalid num_bands");
        }

        Cell cell = Cell.createFrom(inputInterface);
        if (cell == null) {
            logger.error("invalid cell");
            return;
        }

        logger.debug("cell");
        logger.debug(cell);

        reclat = cell.getReciprocalLattice();

        logger.debug("num_bands: " + numBands);
        if (reclat != null) {
            logger.debug("reclat1: " + reclat[0][0] + " " + reclat[0][1] + " "
                    + reclat[0][2]);
            logger.debug("reclat2: " + reclat[1][0] + " " + reclat[1][1] + " "
                    + reclat[1][2]);
            logger.debug("reclat3: " + reclat[2][0] + " " + reclat[2][1] + " "
                    + reclat[2][2]);
        } else {
            logger.debug("failed to obtain reciprocal lattice...");
        }

        String mag = inputInterface
                .getInputInterfacePrimitiveEntry("structure.magnetic_state")
                .getValue().trim();
        if (mag.equalsIgnoreCase("af") || mag.equalsIgnoreCase("antiferro")
                || mag.equalsIgnoreCase("ferro"))
            spin = 2;

        eigs = new double[numBands * spin];
    }

    protected String getFileToMonitor() {
        return getChaseFile().getFileName();
    }

    public ChaseFile getChaseFile() {
        return projectInfo.getChaseFileManager().getFile("F_ENERG");
    }

    private boolean readingEig = false;

    private final String startTag = "===";

    private double[] eigs;

    private int eigCount = 0;

    private Vector dataVector = new Vector();

    private Vector dkVector = new Vector();

    private boolean readK = false;

    private double hartree2eV = 27.2114;

    protected void doGraph(String[] lines) {
        if (eigs == null || numBands <= 0 || reclat == null || drawingChart)
            return;

        for (int i = 0; i < lines.length; i++) {
            logger.debug("parsing line: " + lines[i]);
            if (lines[i].trim().startsWith(startTag)) {
                logger.debug("readingEig=true");
                readingEig = true;
            }
            if (!readingEig)
                continue;
            String[] ar = lines[i].trim().split("\\s+");
            double[] kv = new double[3];
            if (!readK && ar[0].startsWith("ik") && ar.length >= 7) {
                kv[0] = Double.parseDouble(ar[4]);
                kv[1] = Double.parseDouble(ar[5]);
                kv[2] = Double.parseDouble(ar[6].replaceAll("\\)", ""));
                double[] kvec = new double[3];
                for (int j = 0; j < 3; j++)
                    for (int k = 0; k < 3; k++)
                        kvec[j] += kv[k] * reclat[j][k];

                dk += Math.sqrt(Math.pow(kvec[0] - prevk[0], 2)
                        + Math.pow(kvec[1] - prevk[1], 2)
                        + Math.pow(kvec[2] - prevk[2], 2));
                dkVector.addElement(new Double(dk));
                prevk = kvec;

                logger.debug("kv: " + kv[0] + ", " + kv[1] + ", " + kv[2]);
                readK = true;
                continue;
            }
            try {
                Double.parseDouble(ar[0]);
            } catch (NumberFormatException nfe) {
                continue;
            }
            for (int j = 0; j < ar.length; j++) {
                try {
                    eigs[eigCount] = Double.parseDouble(ar[j]) * hartree2eV;
                    eigCount++;
                } catch (NumberFormatException nfe) {
                    continue;
                }
            }
            if (eigCount >= numBands * spin) {
                for (int ii = 0; ii < eigs.length; ii++)
                    logger.debug("eigen value no. " + ii + ": " + eigs[ii]);
                readingEig = false;
                readK = false;
                eigCount = 0;
                dataVector.add(eigs);
            }
        }

        if (dataVector.size() == 0 && xyData == null)
            return;

        if (xyData == null) {
            xyData = new XYData[numBands * spin];
            for (int ispin = 0; ispin < spin; ispin++) {
                Color color = Color.red;
                int seriesIndex = 0;
                String yname = "eigenvalue (eV)";
                if (ispin == 1) {
                    color = Color.blue;
                    yname = "";
                    seriesIndex = 1;
                }
                for (int i = 0; i < numBands; i++) {
                    int ind = i + ispin * numBands;
                    logger.debug("at index: " + ind);
                    xyData[ind] = new XYData("band no. " + String.valueOf(i));
                    xyData[ind].xAxisName = "|k|";
                    xyData[ind].seriesIndex = ind;
                    xyData[ind].seriesColor = color;
                    xyData[ind].yAxisName = yname;
                }
            }
            logger.debug("instanciated XYData[]");
        }

        if (drawingChart) {
            dataVector = new Vector();
            dkVector = new Vector();
            return;
        }

        for (int i = 0; i < dkVector.size(); i++) {
            double kv = ((Double) dkVector.get(i)).doubleValue();
            double[] ei = (double[]) dataVector.get(i);
            for (int j = 0; j < ei.length; j++) {
                xyData[j].add(kv, ei[j]);
            }
        }

        // for (int i = 0; i < dataVector.size(); i++) {
        // double[] ei = (double[]) dataVector.get(i);
        // for (int j = 0; j < ei.length; j++) {
        // xyData[j].add(dk, ei[j]);
        // }
        // }

        dataVector = new Vector();
        dkVector = new Vector();

        if (!graph)
            return;

        logger.debug("creating graph");

        if (graphPanel == null) {
            SimpleChart simpleChart = new SimpleChart(xyData);
            simpleChart.setSize(new Dimension(400, 600));
            simpleChart.setTitle("monitoring " + fileName);
            simpleChart.setChartTitle("eigenvalue");
            simpleChart.createLegend(false);
            simpleChart.setChartProgressListener(this);
            graphPanel = new GraphPanel(simpleChart);
            graphPanel.addInternalFrameListener(this);
        }
        if (!graphPanel.isVisible())
            graphPanel.setVisible(true);

    }
}
