/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on ----
!  AUTHOR(S): KOGA, Junichiro
!  File : ProcessViewer.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.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.Timer;
import javax.swing.border.TitledBorder;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameListener;

import org.apache.log4j.Logger;

import ciss.phase_viewer.common.MyMessageBox;
import ciss.phase_viewer.mainpanel.InternalFrameChase;
import ciss.phase_viewer.ssh.Execute;

/**
 * プロセスをProcessManagerから取得し, それを画面に表示するGUIを提供するクラス. プロセスに停止信号を送るためのボタンなども配備する.
 * 
 * @author KOGA Junichiro,
 */

public class ProcessViewer extends InternalFrameChase {
    private static Logger logger = Logger.getLogger(ProcessViewer.class
            .getName());

    /** refresh rate */
    private final int REFRESH = 5000;

    /** timer */
    private Timer timer;

    /** list and list model */
    private JList list;

    private DefaultListModel listModel;

    /** size of this */
    private int x = 650;

    private int y = 450;

    /** location of this */
    private int locX = 200;

    private int locY = 150;

    private MyMessageBox mbox = new MyMessageBox();

    /** buttons */
    private JButton btnreload = new JButton("reload");

    private JButton btnclose = new JButton("close");

    private JButton btnkillTerm = new JButton("kill  -TERM");

    private JButton btnkillKill = new JButton("kill  -KILL");
    private ProcessManager processManager;

    /** specifies the column associated to PID */
    private int pidIndex = 0;

    /** process vector */
    private Vector process;

    /** scroll pane */
    private JScrollPane scrPane;

    private Vector procvec;

    private boolean isRemote = false;
    private Execute execute;

    private String username;

    /**
     * プロセスビューアー用GUIを作成する. プロセス情報の更新に使用するタイマーの 定義なども行う. タイマーの起動は, 呼び出し元が
     * 行う必要がある.
     */
    public ProcessViewer() {
        super("process viewer", true, true, true, true);
        init();
    }

    public ProcessViewer(Execute execute, String username) {
        super("process viewer", true, true, true, true);
        this.execute = execute;
        this.username = username;
        this.isRemote = true;
        init();
    }

    public void dispose() {
        if (timer != null) {
            timer.stop();
        }
        timer = null;
        super.dispose();
    }

    private void init() {
        this.setSize(x, y);

        Container cont = this.getContentPane();
        cont.setLayout(new BoxLayout(cont, BoxLayout.Y_AXIS));

        listModel = new DefaultListModel();

        processManager = new ProcessManager(execute, username);
        process = processManager.getProcess();
        if (process != null) {
            timer = new Timer(REFRESH, new ActionListener() {
                public void actionPerformed(ActionEvent ev) {
                    redraw();
                }
            });
        }
        cont.add(createListModelAndList());
        cont.add(createButtonsPanel());
        addInternalFrameListener(new InternalFrameListener() {
            public void internalFrameActivated(InternalFrameEvent e) {
            }

            public void internalFrameClosed(InternalFrameEvent e) {
                execute.disconnect();
            }

            public void internalFrameClosing(InternalFrameEvent e) {
            }

            public void internalFrameDeactivated(InternalFrameEvent e) {
            }

            public void internalFrameDeiconified(InternalFrameEvent e) {
            }

            public void internalFrameIconified(InternalFrameEvent e) {
            }

            public void internalFrameOpened(InternalFrameEvent e) {
            }

        });
    }

    /**
     * プロセス情報更新のタイミングを制御するタイマーを起動する.
     */
    public void start() {
        logger.debug("process viewer start");
        timer.start();
    }

    private JPanel createProcessViewer() {
        JPanel p = new JPanel();
        return p;
    }

    private JPanel createButtonsPanel() {
        JPanel p = new JPanel();
        p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));

        p.add(btnreload);
        p.add(btnclose);
        p.add(btnkillTerm);
        p.add(btnkillKill);

        btnclose.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        });

        btnreload.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                redraw();
            }
        });

        btnkillTerm.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                processManager.killProcess(getPID(list.getSelectedIndex()),
                        "TERM");
                redraw();
            }
        });

        btnkillKill.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                processManager.killProcess(getPID(list.getSelectedIndex()),
                        "KILL");
                redraw();
            }
        });

        return p;
    }

    private void redraw() {
        if (process != null) {
            process.clear();
        }
        try {
            Thread.sleep(200);
        } catch (Exception e) {
        }

        process = processManager.getProcess();

        DefaultListModel model = (DefaultListModel) list.getModel();
        model.clear();

        if (process != null) {
            for (int i = 1; i < process.size(); i++) {
                model.addElement(process.get(i));
            }
        } else {
            logger.error("process is null!");
        }
    }

    private int getPID(int selected) {
        // System.out.println("selected index: "+selected);
        String psstring = (String) listModel.get(selected);
        StringTokenizer st = new StringTokenizer(psstring);
        Vector vector = new Vector();
        int ret = 0;
        // System.out.println("psstring: "+psstring);
        // System.out.println("pidIndex: "+pidIndex);

        while (st.hasMoreTokens()) {
            vector.addElement(st.nextToken());
        }
        try {
            ret = Integer.parseInt((String) vector.get(pidIndex));
        } catch (NumberFormatException ne) {
            mbox.setText("failed to get PID");
            ret = -1;
        }

        return ret;
    }

    private JPanel createListModelAndList() {

        if (process != null) {
            for (int i = 1; i < process.size(); i++) {
                listModel.addElement(process.get(i));
            }
        }

        list = new JList(listModel);
        list.setFont(new Font("Monospaced", Font.PLAIN, 12));
        // list.setPreferredSize(new Dimension(x-200,y-90));

        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        list.setSelectedIndex(0);

        String title = "";
        try {
            title = (String) process.get(0);
        } catch (ArrayIndexOutOfBoundsException aio) {
            logger.error("invalid output");
            dispose();
        } catch (NullPointerException npe) {
            logger.error("invalid output");
            dispose();
        }

        StringTokenizer st = new StringTokenizer(title);
        int count = 0;

        while (st.hasMoreTokens()) {
            if (st.nextToken().trim().equalsIgnoreCase("PID")) {
                break;
            }
            count++;
        }
        pidIndex = count;

        scrPane = new JScrollPane(list);
        scrPane.setPreferredSize(new Dimension(x - 20, y - 90));
        JPanel p = new JPanel();
        TitledBorder border = new TitledBorder(title);
        border.setTitleFont(new Font("Monospaced", Font.PLAIN, 12));
        p.setBorder(border);
        p.add(scrPane);

        return p;
    }
}
