package ij.plugin;
import ij.*;
import ij.gui.*;
import ij.process.*;
import ij.macro.Interpreter;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;

/** This plugin continuously plots ImageJ's memory
    utilization. It could also be used as a starting
    point for a video acquisition plugin. Hold down the
    alt/option key when selecting the <code>Monitor Memory</code>
    command and the plugin will use a 640x480 window
    and display the frame rate. Click on the status bar in the
    ImageJ window to force the JVM to do garbage collection.
*/
public class MemoryMonitor implements PlugIn {
    int width = 200;
    int height = 75;
    long fps, startTime, elapsedTime;
    ImageProcessor ip;
    int frames;
    ImageCanvas ic;
    double[] mem;
    int index;
    long value;
    double max = 12*1204*1024; // 12MB
    long maxMemory = IJ.maxMemory();

    public void run(String arg) {
        if (Interpreter.isBatchMode()) return;
        if (IJ.altKeyDown()) {
            // simulate frame grabber
            width = 640;
            height = 480;
        }
        ip = new ByteProcessor(width, height, new byte[width*height], null);
        ip.setColor(Color.white);
        ip.fill();
        ip.setColor(Color.black);
        ip.setFont(new Font("SansSerif",Font.PLAIN,12));
        ip.setAntialiasedText(true);
        ip.snapshot();
        ImagePlus imp = new ImagePlus("Memory", ip);
        ImageWindow.centerNextImage();
        imp.show();
        imp.lock();
        ImageWindow win = imp.getWindow();
        ic = win.getCanvas();
        mem = new double[width+1];
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
        startTime = System.currentTimeMillis();
        win.running = true;
        while (win.running) {
            updatePixels();
            showValue();
            imp.updateAndDraw();
            if (width==640)
                Thread.yield();
            else
                IJ.wait(100);
            frames++;
        }
        imp.unlock();
    }
    
    void showValue() {
        double value2 = (double)value/1048576L;
        String s = IJ.d2s(value2,value2>50?0:2)+"MB";
        if (maxMemory>0L) {
            double percent = value*100/maxMemory;
            s += " ("+(percent<1.0?"<1":IJ.d2s(percent,0)) + "%)";
        }
        if (width==640) {
            elapsedTime = System.currentTimeMillis()-startTime;
            if (elapsedTime>0) {
                double scale = ic.getMagnification();
                fps = (frames*10000)/elapsedTime;
                s += ", " + fps/10 + "." + fps%10 + " fps";
            }
        }
        ip.moveTo(2, 15);
        ip.drawString(s);
    }

    void updatePixels() {
        double used = IJ.currentMemory();
        if (frames%10==0) value = (long)used;
        if (used>0.9*max) max *= 2.0;
        mem[index++] = used;
        if (index==mem.length) index = 0;
        ip.reset();
        int index2 = index+1;
        if (index2==mem.length) index2 = 0;
        double scale = height/max;
        ip.moveTo(0, height-(int)(mem[index2]*scale));
        for (int x=1; x<width; x++) {
            index2++;
            if (index2==mem.length) index2 = 0;
            ip.lineTo(x, height-(int)(mem[index2]*scale));
        }
    }

}