/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on ----
!  AUTHOR(S): KOGA, Junichiro
!  File : LineEditor.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.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.StringTokenizer;
import java.util.Vector;

public class LineEditor {

    public static final int NOT_FOUND = -1; /* !< 検索時に指定の文字列を見つけられなかったときに返すint値 */

    /** the string to be editted */
    private String fullString;

    /** reference to each line */
    private Vector vecLine;

    /** number of lines */
    private int numLines;

    /**
     * エディットしたい文字列を指定する. ここで指定した文字列は改行コードをもとに区分けされ, 後々の処理に使用される.
     * 
     * @param fullString
     *            扱いたい文字列
     */
    public LineEditor(String fullString) {
        this.fullString = fullString;
        divideIntoLines();
    }

    /**
     * 扱いたい文字列を設定するためのメソッド.
     * 
     * @uml.property name="fullString"
     */
    public void setFullString(String fullString) {
        this.fullString = fullString;
        divideIntoLines();
    }

    /**
     * 文字列を取得する. このクラス内で施された編集を 反映した文字列が返される.
     * 
     * @return このクラスが保持する文字列.
     * 
     * @uml.property name="fullString"
     */
    public String getFullString() {
        fullString = new String();
        for (int i = 0; i < numLines; i++) {
            fullString = fullString + (String) vecLine.get(i)
                    + System.getProperty("line.separator");
        }
        return this.fullString;
    }

    /**
     * 今扱っている文字列の行数を取得する.
     * 
     * @return 文字列の行数.
     * 
     * @uml.property name="numLines"
     */
    public int getNumLines() {
        return this.numLines;
    }

    /** divide into lines */
    private void divideIntoLines() {
        vecLine = new Vector();
        String str;
        StringTokenizer st = new StringTokenizer(fullString,
                System.getProperty("line.separator"));
        numLines = st.countTokens();
        for (int i = 0; i < numLines; i++) {
            vecLine.addElement(st.nextToken());
        }
    }

    /**
     * 指定の行の文字列を返す. もし「指定の行」が 不正だった場合nullを返す. 具体的には, index
     * が0より小さい場合や総行数よりも大きい場合.
     * 
     * @param index
     *            何行目が欲しいかを指定する.
     * @return index行のテキスト.
     */
    public String getLine(int index) {
        if (!testIndex(index)) {
            return null;
        }

        return (String) vecLine.get(index);
    }

    /**
     * 頭から検索し, 一番はじめにヒットした行を返す.
     * 
     * @param searchString
     *            検索したい文字列.
     * @return 見つかった行. 見つからなかった場合NOT_FOUNDを返す.
     */
    public int find(String searchString) {
        int i;
        for (i = 0; i < numLines; i++) {
            if (((String) vecLine.get(i)).trim().startsWith(searchString)) {
                break;
            }
        }
        if (i == numLines) {
            return NOT_FOUND;
        }
        return i;
    }

    /**
     * 指定の行から検索し, 一番はじめにヒットした行を返す.
     * 
     * @param istart
     *            検索をはじめる行.
     * @param searchString
     *            検索したい文字列.
     * @return 見つかった行. 見つからなかった場合NOT_FOUNDを返す.
     */
    public int find(int istart, String searchString) {
        int i;

        if (istart >= numLines) {
            return NOT_FOUND;
        }

        for (i = istart; i < numLines; i++) {
            if (((String) vecLine.get(i)).trim().startsWith(searchString)) {
                break;
            }
        }

        if (i == numLines) {
            return NOT_FOUND;
        }

        return i;
    }

    /**
     * 頭から検索し, 一番はじめにヒットした行を返す. この際, case-insensativeな検索をする.
     * 
     * @param searchString
     *            検索したい文字列.
     * @return 見つかった行. 見つからなかった場合NOT_FOUNDを返す.
     */
    public int findIgnoreCase(String searchString) {
        int i;
        for (i = 0; i < numLines; i++) {
            if (((String) vecLine.get(i)).trim().toLowerCase()
                    .startsWith(searchString.trim().toLowerCase())) {
                break;
            }
        }
        if (i == numLines) {
            return NOT_FOUND;
        }
        return i;
    }

    /**
     * 指定の行から検索し, 一番はじめにヒットした行を返す. この際, case-insensativeな検索をする.
     * 
     * @param istart
     *            検索をはじめる行.
     * @param searchString
     *            検索したい文字列.
     * @return 見つかった行. 見つからなかった場合NOT_FOUNDを返す.
     */
    public int findIgnoreCase(int istart, String searchString) {
        int i;

        if (!testIndex(istart)) {
            return NOT_FOUND;
        }

        for (i = istart; i < numLines; i++) {
            if (((String) vecLine.get(i)).trim().toLowerCase()
                    .startsWith(searchString.trim().toLowerCase())) {
                break;
            }
        }
        if (i == numLines) {
            return NOT_FOUND;
        }
        return i;
    }

    /**
     * 文字列の置換を行う.
     * 
     * @param index
     *            置換したい行.
     * @param replaceString
     *            置換したい内容.
     */
    public void replaceLine(int index, String replaceString) {
        if (!testIndex(index)) {
            return;
        }

        vecLine.remove(index);
        vecLine.add(index, replaceString);
        numLines = vecLine.size();
    }

    /**
     * 文字列を足す.
     * 
     * @param index
     *            足したい行.
     * @param addString
     *            足したい内容.
     */
    public void addLine(int index, String addString) {
        if (!testIndex(index)) {
            return;
        }

        vecLine.add(index, addString);
        numLines = vecLine.size();
    }

    /**
     * 文字列を削除する.
     * 
     * @param index
     *            削除したい行.
     */
    public void deleteLine(int index) {
        if (!testIndex(index)) {
            return;
        }

        vecLine.remove(index);
        numLines = vecLine.size();
    }

    /** test index */
    private boolean testIndex(int index) {
        if (index >= numLines) {
            return false;
        } else if (index < 0) {
            return false;
        }

        return true;
    }

    /** テスト用メイン */
    public static void main(String args[]) {
        String str = new String();
        String string = new String();

        try {
            FileReader freader = new FileReader(args[0]);
            BufferedReader breader = new BufferedReader(freader);
            while ((str = breader.readLine()) != null) {
                string = string + str + System.getProperty("line.separator");
            }
            freader.close();
        } catch (IOException e) {
            System.out.println("failed read from file: " + args[0]);
        }

        LineEditor lineeditor = new LineEditor(string);

        for (int i = 0; i < lineeditor.getNumLines(); i++) {
        }
        System.out.println(lineeditor.findIgnoreCase(
                lineeditor.findIgnoreCase("ek_convergence"), "}"));
        System.out.println(lineeditor.findIgnoreCase(args[1]));
    }

}
