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

import java.io.BufferedReader;
import java.io.IOException;
import java.util.Vector;

import org.apache.log4j.Logger;

import ciss.phase_viewer.common.ConstParameters;
import ciss.phase_viewer.common.ExternalProgramExecuter;
import ciss.phase_viewer.common.MyMessageBox;
import ciss.phase_viewer.ssh.Execute;

class ProcessManager {
    private static Logger logger = Logger.getLogger(ProcessManager.class
            .getName());

    private MyMessageBox mbox = new MyMessageBox();

    public static final int KILL_TERM = 9; /* !< TERMシグナル用の数値 */
    public static final int KILL_KILL = 15; /* !< KILLシグナル用の数値 */

    private Execute execute;

    private String username;

    protected ProcessManager() {
    }

    protected ProcessManager(Execute execute, String username) {
        this.execute = execute;
        this.username = username;
    }

    /**
     * プロセス取得用メソッド. プロセスの取得には, psコマンドを使用する.
     * Windowsにはpsコマンドは存在しないのでより上位でタスクマネージャーを 呼ぶようにしている.
     * psコマンドのオプションはOSによって方言があるので, 以下のようなコードで対処する. \code String osName =
     * System.getProperty("os.name").toLowerCase().trim(); if (
     * osName.startsWith("hp-ux") || osName.startsWith("aix") ||
     * osName.startsWith("irix") || osName.startsWith("windows") ||
     * osName.startsWith("linux") ) { ret = "ps -u " +
     * System.getProperty("user.name") + " -l"; } else { ret = "ps -uxc"; }
     * \endcode これは, 決して完全なものではないので将来的により汎用的にする予定.
     */
    protected Vector getProcess() {
        Vector processVector = new Vector();
        String ps = "";
        if (execute == null) {
            ps = getpsCommand();
            BufferedReader[] bin = null;
            try {
                bin = ExternalProgramExecuter.executeGetBR(ps);
                processVector = getProcessString(bin[0]);
            } catch (Exception e) {
                return null;
            } finally {
                try {
                    bin[0].close();
                    bin[1].close();
                } catch (IOException ioe) {

                } catch (ArrayIndexOutOfBoundsException ai) {
                }
            }
        } else {
            String pscom = "ps -u " + username + " -l";
            String res = new String();
            res = execute.command(pscom);
            logger.debug("got string: " + res);
            if (res.length() != 0) {
                if (res.trim().startsWith("ps:")) {
                    pscom = "ps -uxc";
                    res = execute.command(pscom);
                    if (res.length() != 0) {
                        if (res.trim().startsWith("ps:")) {
                            return null;
                        }
                    }
                }
                String[] pss = res.split("\\n");
                if (pss.length <= 0) {
                    pss = res.split(System.getProperty("file.separator"));
                    if (pss.length <= 0) {
                        return null;
                    }
                }

                for (int i = 0; i < pss.length; i++) {
                    processVector.add(pss[i]);
                }
            } else {
                return null;
            }
        }
        return processVector;
    }

    /**
     * 指定のプロセスに停止信号を送る.
     * 
     * @param id
     *            プロセスID
     * @param term
     *            送る信号の種類. ProcessManager.KILL_TERMでTERMシグナルを,
     *            ProcessManager.KILL_KILLでKILLシグナルを送る.
     */
    protected void killProcess(int id, String term) {
        if (id >= 0) {
            String kill = "kill -" + term + " " + id;
            logger.info("performing command: " + kill);
            if (execute == null) {
                try {
                    BufferedReader[] br = ExternalProgramExecuter
                            .executeGetBR(kill);
                    writetoStdOut(br[0]);
                    br[0].close();
                    br[1].close();
                } catch (Exception e) {
                    e.printStackTrace();
                    logger.error("failed to kill process " + id);
                }
            } else {
                execute.command(kill);
            }
        } else {
            logger.error("invalid PID");
        }
    }

    private void writetoStdOut(BufferedReader br) {
        String str = new String();
        try {
            while ((str = br.readLine()) != null) {
                logger.info(str);
            }
        } catch (IOException ie) {
            logger.error("failed to read from: " + br);
        }
    }

    private Vector getProcessString(BufferedReader br) {
        String string = new String();
        Vector returnVector = new Vector();
        try {
            while ((string = br.readLine()) != null) {
                returnVector.addElement(string);
            }
        } catch (Exception e) {
            mbox.setText("failed read from stdout");
            return null;
        }

        return returnVector;
    }

    private String getpsCommand() {
        String ret = new String();
        String osName = ConstParameters.osName.toLowerCase().trim();
        if (osName.startsWith("hp-ux") || osName.startsWith("aix")
                || osName.startsWith("irix") || osName.startsWith("windows")
                || osName.startsWith("linux")) {
            ret = "ps -u " + System.getProperty("user.name") + " -l";
        } else {
            ret = "ps -uxc";
        }

        return ret;
    }

}
