// $Id: mpstat.java,v 1.2 1999/11/09 09:38:57 m-hirano Exp $
// $RWC_Release: Omni-1.6 $
// $RWC_Copyright:
//  Omni Compiler Software Version 1.5-1.6
//  Copyright (C) 2002 PC Cluster Consortium
//  
//  This software is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License version
//  2.1 published by the Free Software Foundation.
//  
//  Omni Compiler Software Version 1.0-1.4
//  Copyright (C) 1999, 2000, 2001.
//   Tsukuba Research Center, Real World Computing Partnership, Japan.
//  
//  Please check the Copyright and License information in the files named
//  COPYRIGHT and LICENSE under the top  directory of the Omni Compiler
//  Software release kit.
//  
//  
//  $
/* mpstat.java  (Mar  1 1998)  -*-Mode: C;-*- */
/*  originally written by matu@trc.rwcp.or.jp */
/* (Mar 23 1999) use Runtime by msato@trc.rwcp.or.jp */
/* (Apr 2 1999) modified little by kazuto.kubota@toshiba.co.jp */

/* graphic display of mpstat output */
import java.lang.*;
import java.net.*;
import java.io.*;
import java.applet.Applet;
import java.awt.*;
import java.util.*;

final public class mpstat extends java.applet.Applet
{
    mpstat_bars[] panels;
    String[] hosts = { "localhost" };
    int rows=1;
    int cols=1;
    int cellw=150;
    int cellh=140;

    public void init() {
	/* init as an applet */
	cols = Integer.parseInt(getParameter("cols"));
	rows = Integer.parseInt(getParameter("rows"));
	cellw = Integer.parseInt(getParameter("cellw"));
	cellh = Integer.parseInt(getParameter("cellh"));
	hosts = mpstat_bars.chop(getParameter("hosts"));
	make_bars();
    }

    void make_bars() {
	while(hosts.length > rows*cols) rows++;
	setLayout(new GridLayout(rows, cols));
	panels = new mpstat_bars[hosts.length];
	int i = 0;
      CELLS:
	for ( int r = 0 ; r < rows ; r++ ) {
	    for ( int c = 0 ; c < cols ; c++ ) {
		mpstat_bars panel = new mpstat_bars(hosts[i], cellw, cellh);
		panel.setVisible(true);
		add(panel);
		panels[i] = panel;
		i++;
		if ( i >= hosts.length )
		    break CELLS;
	    }
	}
    }

    public void start() {
	/*System.out.println("applet start...");*/
	for ( int i = 0 ; i < hosts.length ; i++ ) {
	    panels[i].start();
	}
    }

    public void stop() {
	/*System.out.println("applet stop");*/
	for ( int i = 0 ; i < hosts.length ; i++ ) {
	    panels[i].stop();
	}
    }

    public void destroy() {
	/*System.out.println("applet destroy");*/
    }

    public void paint() {
	/*System.out.println("applet paint");*/
    }

    /*
    public void paint() {
	for ( int i = 0 ; i < panels.length ; i++ ) {
	    panels[i].repaint();
	}
    }
    */

    public static void main(String[] args) {
	/* mpstat(cols rows cellw cellh hosts...) */
	Frame f = new Frame("MPSTAT");
	mpstat stat = new mpstat();

	String hosts_args = "";
	for(int ac = 0; ac < args.length; ac++){
	    String arg = args[ac];
	    if(arg.equals("-cols")) stat.cols = Integer.parseInt(args[++ac]);
	    else if(arg.equals("-rows")) stat.rows = Integer.parseInt(args[++ac]);
	    else if(arg.equals("-cellw")) stat.cellw = Integer.parseInt(args[++ac]);
	    else if(arg.equals("-cellh")) stat.cellh = Integer.parseInt(args[++ac]);
	    else if(arg.equals("-help")) Usage();
	    else hosts_args += " "+arg;
	}

	if(hosts_args.length() != 0) stat.hosts = mpstat_bars.chop(hosts_args);
	stat.make_bars();

	f.add(stat, "Center");
	f.pack();
	f.show();
	stat.start();
    }

    static void Usage(){
	System.err.println("mpstat moninor program: jmpstat options hosts ...");
	System.err.println("if trun is runing, monitor using trun 5555");
	System.err.println("otherwise, monior using 'rsh hosts mpstat 1'");
	System.err.println(" options:");
	System.err.println("  -cols <n> : number of columns in cell (default 1)");
	System.err.println("  -rows <n> : number of rows in cell (default 1)");
	System.err.println("  -cellw <n> : cell width in pixels (default 150)");
	System.err.println("  -cellh <n> : cell hight (default 140)");
	System.err.println("  hosts ... : list of hosts to be monitored");
	System.err.println("  -help: display this message");
	System.exit(0);
    }
}

final class mpstat_bars extends java.awt.Canvas
implements Runnable {
    static int port = 5555;
    static int x = 20;
    static int y = 100 + 25;
    static int w = 20;
    static int gap = 30;
    static int h = 100;

    Thread thread;
    int running = 0;
    String host;
    mpstat_tcpcon tcpcon;
    int n_cpus = 0;
    int max_cpu_id = -1;
    int[] id2n;
    int[] idl;
    int[] sys;
    int[] usr;

    public mpstat_bars(String host0, int w, int h) {
	super();
	host = host0;
	setSize(w, h);
    }

    public synchronized void start() {
	thread = new Thread(this);
	thread.start();
	running = 1;
    }

    public synchronized void stop() {
	running = 0;
    }

    synchronized boolean check_running() {
	return running == 1;
    }

    public void run() {
	tcpcon = new mpstat_tcpcon(host);
	if ( tcpcon.ins == null ) {
	    tcpcon = null;
	    System.out.println("fail to connect to " + host);
	    return;
	}

	while ( check_running() ) {
	    update_graph();
	    /*
	    //thread.yield();
	    try {
		thread.sleep(100);
	    } catch (InterruptedException e) {}
	    */
	}

	tcpcon.done();
	tcpcon = null;
    }

    void update_graph() {
	String s = tcpcon.recv();
	String[] v = chop(s);
	if ( Character.isDigit(v[0].charAt(0)) ) {
	    int cpu = Integer.parseInt(v[0]);
	    
	    if ( cpu > max_cpu_id ) {
		int[] tmp = new int[cpu+1];
		for ( int i = 0; i <= max_cpu_id; i++ ) {
		    tmp[i] = id2n[i];
		}
		tmp[cpu] = n_cpus;
		id2n = new int[cpu+1];
		for ( int i = 0; i <= cpu; i++ ) {
		    id2n[i] = tmp[i];
		}
		max_cpu_id = cpu;
		n_cpus++;
		idl = new int[n_cpus];
		sys = new int[n_cpus];
		usr = new int[n_cpus];
	    } else {
		idl[id2n[cpu]] = Integer.parseInt(v[15]);
		sys[id2n[cpu]] = Integer.parseInt(v[13]);
		usr[id2n[cpu]] = Integer.parseInt(v[12]);
		
		if ( cpu == max_cpu_id ) {
		    //System.out.println("mpstat: " + host + " repaint");
		    repaint();
		}
	    }
	}
    }
    
    public void update(Graphics g) {
	paint(g);
    }

    public void paint(Graphics g) {
	for ( int cpu = 0 ; cpu < n_cpus ; cpu++ ) {
	    draw_graph(g, cpu);
	}
    }

    void draw_graph(Graphics g, int cpu) {
	g.setColor(Color.black);
	g.drawString(host, 20, 20);
	g.drawLine(x, (y + 1), x + (n_cpus - 1) * gap + w, (y + 1));
	g.setColor(Color.red);
	g.fillRect(x + gap * cpu, y - (usr[cpu]),
		   w, usr[cpu]);
	g.setColor(Color.yellow);
	g.fillRect(x + gap * cpu, y - (usr[cpu] + sys[cpu]),
		   w, sys[cpu]);
	g.setColor(Color.blue);
	g.fillRect(x + gap * cpu, y - (usr[cpu] + sys[cpu] + idl[cpu]),
		   w, idl[cpu]);
    }

    public static String[] chop(String s) {
	int len = s.length();
	char[] cv = s.toCharArray();
	Vector chops = new Vector();
	int b = -1;
	int e;

	for ( e = 0 ; e < len ; e++ ) {
	    char c = cv[e];
	    if ( (c == ' ' || c == '\t' || c == '\r'
		  || c == ',' || c == ':') ) {
		if ( b != -1 ) {
		    chops.addElement(s.substring(b, e));
		    b = -1;
		}
	    } else {
		if ( b == -1 ) {
		    b = e;
		}
	    }
	}
	if ( b != -1 ) {
	    chops.addElement(s.substring(b, e));
	}
	String[] val = new String[chops.size()];
	for ( int i = 0 ; i < chops.size() ; i++ ) {
	    val[i] = (String)chops.elementAt(i);
	}
	return val;
    }
}

final class mpstat_tcpcon {
    String host;
    DataOutputStream outs;
    DataInputStream ins;

    public mpstat_tcpcon(String host) {
	this.host = host;
	try {
	    Socket sock = new Socket(host, mpstat_bars.port);
	    outs = new DataOutputStream(sock.getOutputStream());
	    ins = new DataInputStream(sock.getInputStream());
	    return;
	} catch(Exception e){ }
	try {
	    Runtime r = Runtime.getRuntime();
	    Process p = r.exec("rsh "+host+" mpstat 1");
	    outs = new DataOutputStream(p.getOutputStream());
	    ins = new DataInputStream(p.getInputStream());
	    return;
	} catch(Exception e){
	    System.out.println("Exception: " + e);
	}
    }

    public String recv() {
	StringBuffer st = new StringBuffer();
	try {
	    for (;;) {
		int c = ins.readUnsignedByte();
		if ( c == '\n' )
		    break;
		st.append(new Character((char)c));
	    }
	} catch(Exception e) {
	    System.out.println("Exception: " + e);
	}
	return st.toString();
    }

    public void done() {
	try {
	    if(outs != null) outs.close();
	    if(ins != null) ins.close();
	} catch(Exception e) {
	    System.out.println("Exception: " + e);
	}
    }
}


