// ============================================================================
// File:               $File$
//
// Project:
//
// Purpose:
//
// Author:             Rammi
//
// Copyright Notice:   (c) 1999-2006  Rammi (rammi@caff.de)
//                     This code is in the public domain.
//                     Use at own risk.
//                     No guarantees given.
//
// Latest change:      $Date: 2006-02-01 13:48:49 +0100 (Mi, 01 Feb 2006) $
//
// History:	       $Log$
//=============================================================================

package de.caff.util.debug;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 *  A panel displaying automatically updated info about memory usage of the JVM.
 *
 *  @author Rammi
 */
public class MemoryUsagePanel
        extends JPanel
{
  private static final int MEMORY_UPDATE_TIME = 2*1000;
  private JLabel         _usedMemLabel;
  private JLabel         _freeMemLabel;
  private JLabel         _totalMemLabel;
  private JLabel         _maxUsedMemLabel;
  private long           _maxUsedMem;

  public MemoryUsagePanel() {
    this(MEMORY_UPDATE_TIME);
  }

  public MemoryUsagePanel(int updateTime) {
    super(new BorderLayout());
    JPanel sub      = new JPanel(new GridLayout(0, 2, 1, 1));
    sub.add(new JLabel("used:  ", JLabel.RIGHT));
    sub.add(_usedMemLabel = new JLabel());
    
    sub.add(new JLabel("free:  ", JLabel.RIGHT));
    sub.add(_freeMemLabel = new JLabel());
    
    sub.add(new JLabel("TOTAL:  ", JLabel.RIGHT));
    sub.add(_totalMemLabel = new JLabel());
    
    sub.add(new JLabel("max. used:  ", JLabel.RIGHT));
    sub.add(_maxUsedMemLabel = new JLabel());
    
    add("North", sub);
      
    JButton col = new JButton("Collect!");
    col.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
	System.gc();
	_maxUsedMem = 0;
	updateMemoryDisplay();
      }
    });
    col.setToolTipText("Invokes the garbage collector and resets max.used");
    add("South", col);
    
    if (updateTime > 0) {
      new Timer(MEMORY_UPDATE_TIME, new ActionListener() {
        public void actionPerformed(ActionEvent e) {
	  updateMemoryDisplay();
	}
      }).start();
    }
    
  }

  /**
   *  Get a string from a memory size value.
   *  @param  size  size value
   *  @return string representation
   */
  private static String getString(long size) {
    if (size > 1000) {
      String prefix    = getString(size/1000);
      long   remainder = size%1000;
      if (remainder > 100) {
	return prefix+","+remainder;
      }
      else if (remainder > 10) {
	return prefix+",0"+remainder;
      }
      else {
	return prefix+",00"+remainder;
      }
    }
    else {
      return Long.toString(size);
    }
  }

  /**
   *  Update the memory display.
   */
  private void updateMemoryDisplay() {
    Runtime rt = Runtime.getRuntime();
    long freeMem  = rt.freeMemory();
    long totalMem = rt.totalMemory();
    long usedMem  = totalMem - freeMem;

    _usedMemLabel.setText(getString(usedMem));
    _freeMemLabel.setText(getString(freeMem));
    _totalMemLabel.setText(getString(totalMem));
    if (usedMem > _maxUsedMem) {
      _maxUsedMem = usedMem;
      _maxUsedMemLabel.setText(getString(_maxUsedMem));
    }
  }
}
