package ckelling.baukasten;

import java.awt.*;
import java.util.*;


/**
 *	StatInfo.java
 *
 *	Verwaltet statistische Informationen und zeigt diese
 *	in einem Fenster an
 *
 *	@author		Carsten Kelling
 *	@version	0.3.0, 18.12.96
 */
public class StatInfo extends Frame
{
    public final static int	WIDTH	= 320;
    public final static int	HEIGHT	= 250;
    public final static String	DEFAULT_STATUSLINE = new String("");

	private Rechner p;

	private Hashtable	stats;

	private boolean		locked		= false;


    public StatInfo(Rechner par) {

        super("Statistik");

        p = par;
        stats = new Hashtable(100);

        //{{INIT_CONTROLS
        //setLayout(null);
        GridBagLayout gridBag = new GridBagLayout();
		GridBagConstraints c = new GridBagConstraints();

        setLayout(gridBag);
        addNotify();
        //resize(insets().left + insets().right + 322, insets().top + insets().bottom + 286);
        resize(preferredSize().width, preferredSize().height);

        //noTitle titleLabel=new Label("Statistik", Label.CENTER);
        //noTitle titleLabel.setFont(new Font("Helvetica",Font.BOLD,14));
        //noTitle add(titleLabel);
        //noTitle titleLabel.reshape(insets().left + 21,insets().top + 7,273,19);

        outputTotal = new Label("", Label.LEFT);
        c.fill = GridBagConstraints.BOTH;
        //c.insets = new Insets(5, 10, 5, 10);
        c.weightx = 1.0;
        c.gridx = 0;
        c.gridwidth = GridBagConstraints.REMAINDER;
        c.gridheight = 1;
        gridBag.setConstraints(outputTotal, c);
        add(outputTotal);
        //outputTotal.reshape(insets().left + 21,insets().top + 39,273,26);
	        //}}

        outputCommands = new RTFTextArea(p.SMALLFONT, 5,33);
        c.weighty = 1.0;
        c.gridheight = 3;
        gridBag.setConstraints(outputCommands, c);
        add(outputCommands);
        //outputCommands.reshape(insets().left + 21,insets().top + 71,273,85);

        outputCache=new RTFTextArea(p.SMALLFONT, 5,33);
        gridBag.setConstraints(outputCache, c);
        add(outputCache);
        //outputCache.reshape(insets().left + 21,insets().top + 162,273,85);

        statusLine = new Label(DEFAULT_STATUSLINE, Label.LEFT);
        c.weighty = 0.0;
        c.gridheight = 1;
        gridBag.setConstraints(statusLine, c);
        add(statusLine);

        setBackground(p.BACKGROUND);

		update();

        //{{INIT_MENUS
        //}}
    }

	public Insets insets()	//	leave some space around the edges
	{
		Insets r = super.insets();
		return new Insets (r.top + 5, r.left+ 5, r.bottom + 5, r.right + 5);
        //format: top, left, bottom, right
	} /* end Insets */

	public Dimension preferredSize()
	{
		double psX = WIDTH; double psY = HEIGHT;

		double faktor = p.SMALLFONTSIZE / (double) p.NORMALFONTSIZE;
		psX = psX * faktor; psY = psY * faktor;

		return new Dimension((int) psX, (int) psY);
	}

	public Dimension minimumSize()
	{
		return preferredSize();
	}

	/**
	 *  Zeigt den aktuellen Stand der Statistik an.
	 */
    public void update()
    {
    	if (locked)
    		return;
    		
        outputTotal.setText("Takte gesamt: " + getStat(p.CLOCKS_TOTAL));

	    outputCommands.setText("Befehle gesamt: " + getStat(p.COMMANDS_TOTAL) + "\nLade-Befehle: " + getStat(p.LOADS_TOTAL) + "\nSpeicher-Befehle: " + getStat(p.STORES_TOTAL));

	    int readHit = getStat(p.READ_HIT);
	    int readMiss = getStat(p.READ_MISS_CACHED) + getStat(p.READ_MISS_NON_CACHED) + getStat(p.READ_MISS_SYNC);
	    String hitMissRatio = new String("-");
	    if (readMiss > 0)
	    	hitMissRatio = Double.toString((double) readHit / (double) readMiss);
    	outputCache.setText("read hit: " + readHit + "\nread miss: " + readMiss + "\nVerhältnis hit/miss: " + hitMissRatio);
    }

    public void showStatus(String status)
    {
    	if (! locked)
	    	statusLine.setText(status);
    }

    public boolean handleEvent(Event event) {

    	if (event.id == Event.WINDOW_DESTROY) {
    	    return true;
    	}
    	return super.handleEvent(event);
    }

    //{{DECLARE_MENUS
    //}}

    //{{DECLARE_CONTROLS
    //noTitle Label titleLabel;
    Label		outputTotal;
    //}}
    Label		statusLine;
    RTFTextArea	outputCommands;
    RTFTextArea	outputCache;

	public int getStat(int index1)
	{
		Integer index = new Integer(index1);
		if (stats.containsKey(index))
		{
			return ((Integer) stats.get(index)).intValue();
		}
		else
		{
			stats.put(index, new Integer(0));
			return 0;
		}
	}

	private void incStat(int index)
	{
		incStat(index, 1);
	}
	private void incStat(int index1, int increase)
    {
    	Integer index = new Integer(index1);
   		if (stats.containsKey(index))
	   		stats.put(index, new Integer( ((Integer)stats.get(index)).intValue() + increase));
	    else
	    	stats.put(index, new Integer(increase));

		if (! locked)
			update();
	}

	public void setStat(int index)
	{
	 	incStat(index);

	    switch (index)
	    {
	    	case p.LDA_ABSOL:
	    	case p.LDA_MEM:
	    	case p.LDA_MEM_INDIR:
	    		incStat(p.LOADS_TOTAL);
	    		break;
	    	case p.STA_ABSOL:
	    	case p.STA_MEM:
	    		incStat(p.STORES_TOTAL);
	    		break;
	    	default:
	    }
    }

    public void delay(int delay)
    {
    	incStat(p.CLOCKS_TOTAL, delay);
    }


    public void singleStep(int c_state)
    {
    	if ( (c_state == Rechner.FETCH) || (c_state == Rechner.FETCH_DECODE) )
    	{
	    	incStat(p.COMMANDS_TOTAL);
	    	setStat(c_state);
	    }
    }

	/**
	* Alle Werte der Statistik auf 0 zuruecksetzen
	*/
    public void clearStats()
    {
    	stats = new Hashtable(100);
    	statusLine.setText(new String(""));
    	update();
    }

    public Hashtable getStats()
    {
    	Hashtable value = new Hashtable(100);
    	for (Enumeration k = stats.keys(); k.hasMoreElements(); )
    	{
    		Object key = k.nextElement();
    		value.put( key, new Integer( ((Integer) stats.get(key)).intValue() ) );
    	}
    	return value;
    }

    public void setStats(Hashtable newStats)
    {
    	stats = newStats;

    	update();
    }


	/**
	 * Werte werden weiterhin in der Statistik mitprotokolliert, aber noch nicht angezeigt.
	 * @see #unlock
	 */
	public synchronized void lock()
	{
		locked = true;
	}

	/**
	 * Wertänderungen in der Statistik werden wieder sofort angezeigt; ruft update() auf.
	 * @see #lock
	 */
	public synchronized void unlock()
	{
		locked = false;
		update();
	}

}


