package com.didi.codeProfiler;



import java.awt.*;

import java.util.*;



// A remix of Brad Paley's CodeProfiler,

// this applet shows simultaneous threads of execution.

// as superimposed layers of code. Lines of code are

// sized according to their proportion of execution

// during a given thread, and the layers are colored

// and ordered by thread priority.



// The applet connects three people: Brad, me, and the author of the

// program being profiled.



// Created by Martin Wattenberg, Aug 31, 2002.

// Coded in "remix style": concise & site-specific rather

//                         than general & optimized.



public class CodeLayers extends CodeProfiler {

    class ThreadData { Thread thread; double timing, usage; 

                        LineData[] profile=new LineData[256];}

    class LineData {double usage, currentSize;}

    Hashtable threadTable=new Hashtable();

    Vector threads=new Vector(); // list of threads in order of priority.

    Font[] lineFont=new Font[300];

	

    public CodeLayers() {

        for (int i=1; i<lineFont.length; i++)

            lineFont[i]=new Font("Helvetica", Font.BOLD, i);

        setBackground(Color.white);

    }

		

    // Record profile data for each execution thread.

    public synchronized int line(int i) {		

        Thread thread=Thread.currentThread();

        ThreadData data=(ThreadData)threadTable.get(thread);

        if (data==null) {

            data=new ThreadData(); data.thread=thread;

            threadTable.put(thread, data);

            int j; 

            for (j=0; j<threads.size() && data(j).thread.getPriority()<thread.getPriority(); j++);

            threads.insertElementAt(data,j);

        }

        if (data.profile[i]==null) data.profile[i]=new LineData();

        data.profile[i].usage++; data.usage++; data.timing=2;

        return i;

    }	

    ThreadData data(int i) { return (ThreadData)threads.elementAt(i);}

		

    void drawCodeLayers(Graphics g, int w, int h) {

        g.setColor(getBackground());

        g.fillRect(0,0,w,h);

        if (programLines==null) return;

        int i,j,n=threads.size();		

        for (i=0; i<n; i++) {

            ThreadData data=data(i);

            if (data.usage<=0 || data.timing<=0) continue;

            LineData[] profile=data.profile;			

            for (j=0; j<profile.length; j++) {

                if (profile[j]==null) continue;

                profile[j].currentSize=.95*profile[j].currentSize+

                                        .05*profile[j].usage/data.usage;

                profile[j].usage*=.95;

            }

            nt c=Math.max(0, Math.min(255, 1230-200*data.thread.getPriority()));

            g.setColor(new Color((int)(c*.5),64+(int)(c*.5),(int)(100+c*.5)));

            double position=Math.min(data.timing,1)-1; // slide new, old threads in and out of view.			

            for (j=0; j<programLines.length; j++) {

                Line line=programLines[j];

                if (!line.hasLineCall || profile[line.lineAsWrittenIndex]==null)

                     continue;

                double u=profile[line.lineAsWrittenIndex].currentSize;

                if (u==0) continue;

                int lineH=(int)(u*h), lineY=(int)(5+position*(h-10));

                g.setFont(lineFont[Math.max(1,Math.min(lineH, lineFont.length-1))]);

                int q=line.s.indexOf("line(");

                if (q>-1) line.s=line.s.substring(0,q);

                line.s=line.s.trim();

                if (line.s.length()==0) // means real code is on previous line.

                    line.s=programLines[j-1].s.trim();

                g.drawString(line.s,5,lineY+(3*lineH)/4);				

                position+=u;

            }

            data.usage*=.95; data.timing-=.04; // "decay" thread data for smooth animation.					

        }

    }

	

    // Hook into superclass's animation engine, following Brad's code.

    public synchronized void drawAll(Graphics g) {      

        int w=size().width/2, h=size().height;

        if (w<21 || h<21) return;  

        if (offscreenImage==null ||   

            w!=offscreenImage.getWidth(this) ||   

            h!=offscreenImage.getHeight(this)) {  

            offscreenImage=createImage(w, h);  

            offscreenGraphics=offscreenImage.getGraphics();  

        }   

        if (offscreenGraphics==null) return;         

            drawCodeLayers(offscreenGraphics, w,h);

        g.drawImage(offscreenImage, 0, 0, this);  

    }   

}