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

import java.util.StringTokenizer;
import java.util.Vector;

public class Output000Parser extends OldOutputParser {

    /** number of columns */
    private int numColumns = 2;

    /** number of rows */
    private int numRows;

    /** switch for total energy */
    private boolean totalEnergy = false;

    /** switch for KI */
    private boolean ki = false;

    /** swich for HA */
    private boolean ha = false;

    /** switch for XC */
    private boolean xc = false;

    /** switch for LO */
    private boolean lo = false;

    /** switch for NL */
    private boolean nl = false;

    /** switch for EW */
    private boolean ew = false;

    /** switch for PC */
    private boolean pc = false;

    /** switch for edeltb */
    private boolean edeltb = false;

    /** counter for iteration_electronic */
    private int iter_elec = 0;

    /** counter for iteration_ionic */
    private int iter_ionic = 1;

    /** parser for energy */
    public static final int TYPE_ENERGY = 0;

    /** parser for CPU statistics */
    public static final int TYPE_CPU = 1;

    /** parser for charge data */
    public static final int TYPE_CHARGE = 2;

    /** specify type of parser */
    private int type;

    /** identifier */
    private String identTOTAL = "TOTAL ENERGY FOR";

    /** identifier */
    private String identKI = "KI=";

    /** identifier */
    private String identHA = "HA=";

    /** identifier */
    private String identXC = "XC=";

    /** identifier */
    private String identLO = "LO=";

    /** identifier */
    private String identNL = "NL=";

    /** identifier */
    private String identEW = "EW=";

    /** identifier */
    private String identPC = "PC=";

    /** identifier */
    private String identIter = "ITER=";

    /** identifier */
    private String identIterIon = "! iteration_ionic";

    /** identifier */
    private String identEdeltb = "! edeltb =";

    /** identifier */
    private String identCPU = "<< CPU Time Consumption";

    /** flag necessary for reading block data */
    private int readingBlock = 0;

    /** flag necessary for reading cpu stats */
    private int readingCPU = 0;

    /** flag necessary for reading charge data */
    private int readingCharge = 0;

    /** String for iteration count, used in parsing of CPU-stat */
    private String cpuIterCount;

    /** int for iteration count, used in parsing charge data */
    private int chargeIterCount;

    /** identifier for chrage data */
    private String identCharge = "!NEW total charge";

    /**
     * 初期化などを, 欲しいパーサーの種類に応じて行う.
     * 
     * @param filename
     *            パースしたいF_ENFファイル.
     * @param type
     *            パースしたいデータの種類. TYPE_ENERGY, TYPE_CPU, TYPE_CHARGEのいずれかを選択する.
     */
    public Output000Parser(String filename, int type) {
        super(filename);
        this.type = type;
        String cr = OldOutputParser.CR;
        if (type == TYPE_ENERGY) {
            addHeader("# energy_stdout" + OldOutputParser.CR);
            addColumnName("iter_ionic");
            addColumnName("iter_electronic");
        } else if (type == TYPE_CPU) {
            addHeader("# CPU_statistics_stdout" + OldOutputParser.CR);
        } else if (type == TYPE_CHARGE) {
            addHeader("# charge_data_stdout" + OldOutputParser.CR);
        }
    }

    public void setTotalEnergy(boolean totalEnergy) {
        this.totalEnergy = totalEnergy;
    }

    public boolean getTotalEnergy() {
        return this.totalEnergy;
    }

    public void setKI(boolean ki) {
        this.ki = ki;
    }

    public boolean getKI() {
        return this.ki;
    }

    public void setHA(boolean ha) {
        this.ha = ha;
    }

    public boolean getHA() {
        return this.ha;
    }

    public void setXC(boolean xc) {
        this.xc = xc;
    }

    public boolean getXC() {
        return this.xc;
    }

    public void setLO(boolean lo) {
        this.lo = lo;
    }

    public boolean getLO() {
        return this.lo;
    }

    public void setNL(boolean nl) {
        this.nl = nl;
    }

    public boolean getNL() {
        return this.nl;
    }

    public void setEW(boolean ew) {
        this.ew = ew;
    }

    public boolean getEW() {
        return this.ew;
    }

    public void setPC(boolean pc) {
        this.pc = pc;
    }

    public boolean getPC() {
        return this.pc;
    }

    public void setEdeltb(boolean edeltb) {
        this.edeltb = edeltb;
    }

    public boolean getEdeltb() {
        return this.edeltb;
    }

    /**
     * 条件に応じたカラム数を決定する.
     */
    public void calculateNumColumns() {
        if (type == TYPE_ENERGY) {

            if (totalEnergy) {
                numColumns++;
                addColumnName("total_enery");
            }

            if (ki) {
                numColumns++;
                addColumnName("KI_energy");
            }

            if (ha) {
                numColumns++;
                addColumnName("HA_energy");
            }

            if (xc) {
                numColumns++;
                addColumnName("XC_energy");
            }

            if (lo) {
                numColumns++;
                addColumnName("LO_energy");
            }

            if (nl) {
                numColumns++;
                addColumnName("NL_energy");
            }

            if (ew) {
                numColumns++;
                addColumnName("EW_energy");
            }

            if (pc) {
                numColumns++;
                addColumnName("PC_energy");
            }

            if (edeltb) {
                numColumns++;
                addColumnName("edeltb");
            }

            setNumColumns(numColumns);

        } else if (type == TYPE_CPU) {
            addColumnName("iteration");
            addColumnName("rank");
            addColumnName("name_of_subroutine");
            addColumnName("time(sec)");
            addColumnName("percentage(%)");
            setNumColumns(5);
        } else if (type == TYPE_CHARGE) {
            addColumnName("iteration");
            addColumnName("up");
            addColumnName("down");
            addColumnName("sum");
            setNumColumns(4);
        } else {
            System.out.println("invalid specification for argument 'type'");
        }
    }

    /**
     * データをパースするメソッド. どのタイプのパーサーを 使用するかあらかじめ決まっている.
     * 
     * @param str
     *            パースしたいファイルを指定.
     */
    public void parseString(String str) {
        if (type == TYPE_ENERGY) {
            extractEnergy(str);
        } else if (type == TYPE_CPU) {
            extractCPUStats(str);
        } else if (type == TYPE_CHARGE) {
            extractChargeData(str);
        } else {
            System.out.println("invalid type");
        }
    }

    /**
     * @param str
     *            the string to be searched
     */
    private void extractEnergy(String str) {
        StringTokenizer st = new StringTokenizer(str);
        String strdata = new String();

        if (str.trim().startsWith(identTOTAL)) {
            iter_elec++;
            addDataColumn(Integer.toString(iter_ionic));
            addDataColumn(Integer.toString(iter_elec));
            readingBlock = 1;
            while (st.hasMoreTokens()) {
                strdata = st.nextToken();
                if (strdata.equals(identIter) && totalEnergy) {
                    addDataColumn(st.nextToken());
                }
            }
        } else if (str.trim().startsWith(identKI) && readingBlock == 1) {
            while (st.hasMoreTokens()) {
                strdata = st.nextToken();
                if (strdata.equals(identKI) && ki) {
                    addDataColumn(st.nextToken());
                } else if (strdata.equals(identHA) && ha) {
                    addDataColumn(st.nextToken());
                } else if (strdata.equals(identXC) && xc) {
                    addDataColumn(st.nextToken());
                } else if (strdata.equals(identLO) && lo) {
                    addDataColumn(st.nextToken());
                }
            }
        } else if (str.trim().startsWith(identNL) && readingBlock == 1) {
            while (st.hasMoreTokens()) {
                strdata = st.nextToken();
                if (strdata.equals(identNL) && nl) {
                    addDataColumn(st.nextToken());
                } else if (strdata.equals(identEW) && ew) {
                    addDataColumn(st.nextToken());
                } else if (strdata.equals(identPC) && pc) {
                    addDataColumn(st.nextToken());
                }
            }
            /* readingBlock = 2; */
        } else if (str.trim().startsWith(identEdeltb) && readingBlock == 1) {
            while (st.hasMoreTokens()) {
                strdata = st.nextToken();
                if (strdata.startsWith("(=")) {
                    strdata = st.nextToken();
                    strdata = strdata.replace('D', 'E');
                    strdata = strdata.replace('d', 'E');
                    addDataColumn(strdata);
                    break;
                }
            }
            readingBlock = 2;
        } else if (str.trim().startsWith(identIterIon)) {
            iter_ionic++;
        }

        if (readingBlock == 2) {
            addDataRow();
            readingBlock = 0;
        }

        if (str.trim().startsWith("EFermi")) {
            addHeader("#" + str + OldOutputParser.CR);
        }
    }

    /**
     * extract cpu statistics from string.
     * 
     * @param str
     *            the string to be searched
     */
    private void extractCPUStats(String str) {
        if (!str.trim().startsWith("Total cpu time")) {
            StringTokenizer st = new StringTokenizer(str);
            String strdata = new String();
            String strdata1 = new String();
            String strdata2 = new String();

            if (readingCPU >= 1 && readingCPU <= 10) {
                addDataColumn(cpuIterCount);
                while (st.hasMoreTokens()) {

                    addDataColumn(st.nextToken());
                    st.nextToken();
                    strdata = st.nextToken();
                    strdata1 = st.nextToken();

                    if (strdata1.startsWith("xc_pot")) {
                        addDataColumn(strdata + "_" + strdata1);

                        strdata = st.nextToken();
                        char[] ch = strdata.toCharArray();
                        strdata = new String(ch, 0, ch.length - 6);

                        strdata1 = st.nextToken();
                        char[] ch0 = strdata1.toCharArray();
                        strdata1 = new String(ch0, 0, ch0.length - 3);

                        addDataColumn(strdata);
                        addDataColumn(strdata1);
                        break;
                    } else {
                        addDataColumn(strdata);

                        char[] ch0 = strdata1.toCharArray();
                        strdata1 = new String(ch0, 0, ch0.length - 6);

                        strdata2 = st.nextToken();
                        char[] ch = strdata2.toCharArray();
                        strdata2 = new String(ch, 0, ch.length - 3);

                        addDataColumn(strdata1);
                        addDataColumn(strdata2);
                        break;
                    }
                }
                Vector col = getDataColumn();
                readingCPU++;
                addDataRow();
            }

            if (str.trim().startsWith(identCPU)) {
                readingCPU++;
                while (st.hasMoreTokens()) {
                    strdata = st.nextToken();
                    if (strdata.equals("Subroutines")) {
                        st.nextToken();
                        String cpuIterCount_wk = st.nextToken();
                        char[] ch = cpuIterCount_wk.toCharArray();
                        cpuIterCount = new String(ch, 0, ch.length - 1);
                    }
                }
            }

            if (readingCPU == 11) {
                readingCPU = 0;
            }
        } else {
            readingCPU = 0;
        }

    }

    /**
     * extract charge data from string.
     * 
     * @param str
     *            the string to be searched
     */
    private void extractChargeData(String str) {
        StringTokenizer st = new StringTokenizer(str);
        String strdata = new String();

        if (str.trim().startsWith(identCharge)) {
            readingCharge = 1;
        }

        if (readingCharge == 1) {
            addDataColumn(Integer.toString(chargeIterCount));
            while (st.hasMoreTokens()) {
                strdata = st.nextToken();
                if (strdata.startsWith("=")) {
                    addDataColumn(st.nextToken());
                    st.nextToken();
                    addDataColumn(st.nextToken());
                    st.nextToken();
                    addDataColumn(st.nextToken());
                }
            }
        }

        if (str.trim().startsWith(identTOTAL)) {
            chargeIterCount++;
        }

        if (readingCharge == 1) {
            addDataRow();
            readingCharge = 0;
        }

    }

}
