import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.security.AccessControlException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.TreeMap;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;

/**
 * java performance test applet
 * (c) tetsuomeister * 
 * http://goashake.de
 * @author tetsuomeister
 * @version 0.43
 * build with java 1.5.0._09
 * 2006.11.30
 */
public class JavaPerformanceTestApplet extends JApplet 
{
	private static final long serialVersionUID = 1;
	private int rndmin = 1;
	private int rndmax = 32;
	private int spalte = 10;
	private int rect_xpos = spalte;
	private int rect_ypos = 20;
	private int rect_weite = 120;
	private int rect_hoehe = 20;
	private int counter, mLast, mBytes, multiplier = 0;
	private double  percent, specmax, specnow, specavg, spectonne,loopmax  = 0.00;
	private String hashcode = "";
	private Calendar calendar = null;
	private Rectangle progressBar = null;
	private LinkedList<DataObjekt> ll1 = null;
	private LinkedList<DataObjekt> ll2 = null;
	private TreeMap<String, DataObjekt> tree = null;
	private HashSet<String> hash = null;
	private myRandom mr = null;
	private VergleichData vg = null;
	private DataObjekt foo, foa, fob = new DataObjekt();
	private JButton stopButton, startButton;  	
	private TextField maxcalc;
	private JLabel lb1;
	private Display canvas;	
	
	public void init() {
		setBackground(Color.BLACK);
		canvas = new Display();
		getContentPane().add(canvas, BorderLayout.CENTER);
		this.setFont(new Font("Tahoma",Font.BOLD, 12));
		JPanel bottom = new JPanel();
		lb1 = new JLabel("FAKTOR");
		lb1.setFont(this.getFont());
		bottom.add(lb1);
		maxcalc = new TextField("4",2);	
		maxcalc.setFont(this.getFont());
		bottom.setBackground(Color.gray);
		bottom.add(maxcalc);		
		startButton = new JButton("Start");
		startButton.setFont(this.getFont());
		startButton.addActionListener(canvas);
		bottom.add(startButton);		
		stopButton = new JButton("Stop");
		stopButton.setFont(this.getFont());
		stopButton.addActionListener(canvas);
		bottom.add(stopButton);
		this.setSize(new Dimension(400,300));
		getContentPane().add(bottom, BorderLayout.SOUTH);
	} 	
	
	public Insets getInsets() {
		return new Insets(2,2,2,2);
	}
	
	public void stop() {
		
		try{Thread.sleep(50);}
		catch (Exception e) {}
		canvas.stopRunning();
	}
	
	private void startZeit()
	{
		SimpleDateFormat fmt = new SimpleDateFormat();
		fmt.applyPattern( "HH:mm:ss:SSS" );
		fmt.format(this.calendar.getTime());
	}
	
	private long endZeit()
	{
		long endzeit = 0;
		try {endzeit = (Calendar.getInstance().getTimeInMillis() - calendar.getTimeInMillis());}
		catch (NullPointerException npe) {endzeit = 1;}
		return endzeit;
	}	
	
	public static String getSHA1Hash(String hashMe) throws NoSuchAlgorithmException{
		MessageDigest md = MessageDigest.getInstance("SHA1");
		md.update(hashMe.getBytes());
		byte[] newHash = md.digest();
		StringBuffer newHashStringBuffer = new StringBuffer();
		for ( int i = 0; i < newHash.length; i++ ) newHashStringBuffer.append(Integer.toHexString(newHash[i]&0xff));
		return newHashStringBuffer.toString();
	} 
	
	class Display extends JPanel implements ActionListener, Runnable 
	{
		private static final long serialVersionUID = 13;
		private Graphics OSG;		
		private Thread runner;    
		private boolean running;  		
		
		public void paintComponent(Graphics g) {
			if (OSG == null || running==false) {
				redraw(g);
			}
			if (OSG!=null && running ==true) 
			{
				g.setColor(Color.LIGHT_GRAY);
				g.fillRect(0,0,getWidth(),getHeight());
				paintIt(g);		
			}
			if (OSG!=null && running ==false)
			{running = false;}
		}
		
		public void redraw(Graphics g)
		{
			g.setColor(Color.black);
			g.fillRect(0,0,getWidth(),getHeight());
		}
		
		public void actionPerformed(ActionEvent evt) {
			String command = evt.getActionCommand();
			if (command.equals("Start"))
				startRunning();
			else if (command.equals("Stop"))
				stopRunning();
		}
		
		void startRunning() {
			if (running == true) {return;}
			runner = new Thread(this);
			running = true;
			runner.start();
		}
		
		void stopRunning() {
			running = false;
			startButton.setEnabled(true);
			stopButton.setEnabled(false);
		}
		
		public void run() 
		{			
			System.out.println(maxcalc.getText());
			foo = new DataObjekt();
			ll1 = new LinkedList<DataObjekt>();
			ll2 = new LinkedList<DataObjekt>();
			tree = new TreeMap<String, DataObjekt>();
			hash = new HashSet<String>();
			mr = new myRandom();
			vg = new VergleichData();
			specavg = 0;
			counter =0;
			spectonne = 0;
			specnow = 0;
			mBytes = 0;
			percent =0;
			mLast =0;
			progressBar = new Rectangle(rect_xpos, rect_ypos, rect_weite, rect_hoehe);
			multiplier = Integer.valueOf(maxcalc.getText()).intValue();
			loopmax = (int)(multiplier*2e6*Math.PI*Math.E);
			calendar = Calendar.getInstance();
			startZeit();
			startButton.setEnabled(false);
			stopButton.setEnabled(true);			
			OSG = getGraphics();
			OSG.setColor(Color.black);
			for (int i = 0; i < (loopmax)&& running; i++)
			{
				counter = i;
				updateBar(i,loopmax);
			}				
			running = false;
			stopButton.setEnabled(false);
			startButton.setEnabled(true);
		} 		
	} 
	public void paintIt(Graphics g)
	{
		int starty = 90;
		int step = 11;
		g.setFont(new Font("Tahoma",Font.BOLD, step));				
		this.paintMatrix(g, step);
		this.paintBar(g);
		this.paintTaskInfo(starty,step,g);
		this.paintSysInfo(starty,step,g);				
	}
	
	private void updateBar(int posx, double maxx)
	{	
		if (posx >= 1)
		{
			percent = (posx/maxx);
			int dd = (int)Math.round(percent*100);
			if (mLast <= dd && counter != 0)
			{					
				if ((posx+1) >= maxx){percent = 1.0;}			
				percent = (double)dd/100;
				try {specnow = Math.round(counter/endZeit());}
				catch (ArithmeticException ae) {specnow =0;}
				if (specnow > specmax) {specmax = specnow;}
				spectonne += specnow;
				specavg = Math.round(spectonne/(dd));	
				for (int i=0; i<mr.nextInt(rndmin*multiplier,rndmax*multiplier);i++){ll1.add(foo.machObjekt());}
				ll1 = vg.entferneDoppelteCounter(ll1);
				for (int i=0; i<ll1.size();i++){tree.put(String.valueOf(i),ll1.get(i));}
				ll1.clear();
				for (int i=0; i<tree.size();i++){ll2.add(tree.get(String.valueOf(i)));}
				tree.clear();
				ll2 = vg.entferneDoppelteClown(ll2);
				try{hash.add(getSHA1Hash(String.valueOf(ll2.toString())));}
				catch(NoSuchAlgorithmException nsae){hash.add(ll2.toString());}
				try{hashcode = (getSHA1Hash(String.valueOf(hash.toString())));}
				catch(NoSuchAlgorithmException nsae){hashcode=String.valueOf(counter);}
				mLast = dd+1;
				this.repaint();
			}
		}
	}		
	
	private void paintSysInfo(int starty,int step,Graphics g)
	{
		g.setColor(Color.GRAY);
		try{
			g.drawString("JavaVM : "+System.getProperty("java.version"), spalte ,starty+(step*9));
			g.drawString("Country : "+System.getProperty("user.country"), spalte ,starty+(step*10));
			g.drawString("VGA : "+System.getProperty("java.awt.graphicsenv"), spalte ,starty+(step*11));		
			g.drawString("OS.Ver.: "+System.getProperty("os.version"), spalte ,starty+(step*12));
			g.drawString("CPUtype : "+System.getProperty("os.arch"), spalte ,starty+(step*13));
			g.drawString("ProxyPort : " +System.getProperty("http.proxyPort"), spalte ,starty+(step*14));
			g.drawString("Browser : "+System.getProperty("browser.version"), spalte ,starty+(step*15));}
		catch (AccessControlException ace){}
	}
	
	private void paintTaskInfo(int starty,int step,Graphics g)
	{
		g.setColor(Color.GRAY);
		g.drawString("J.P.T.A v0.43", spalte , starty-(step*3));
		g.drawString("percent : " + nurDreiStellen(), spalte , starty-(step*2));
		g.drawString("100 % : " + Math.round(loopmax), spalte , starty-(step*1));
		g.drawString("SHA1 : " + (hashcode), spalte , starty);
		g.drawString("objekte : " + (ll2.size()), spalte , starty+(step*1));
		g.drawString("rendert : " + (mBytes) + " byte", spalte , starty+(step*2));
		g.drawString("time : " + (endZeit()) + " ms", spalte , starty+(step*3));
		try{g.drawString("i/o  : " + Math.round((mBytes*8)/(endZeit()/1000)) + " bit/sec", spalte , starty+(step*4));}
		catch (ArithmeticException ae){g.drawString("i/o  : calculating bit/sec", spalte , starty+(step*4));}
		g.drawString("max\t: " + specmax + " Ops/sec.", spalte , starty+(step*6));
		g.drawString("now\t: " + specnow + " Ops/sec.", spalte , starty+(step*7));
		g.drawString("avg\t: " + specavg + " Ops/sec.", spalte , starty+(step*8));
	}
	
	private void paintBar(Graphics g)
	{
		g.clearRect(rect_xpos, rect_ypos, rect_weite, rect_hoehe);
		g.setColor(Color.DARK_GRAY);
		g.fillRect(progressBar.x, progressBar.y,(int)(progressBar.width*percent), progressBar.height);
		g.setColor(Color.BLACK);
		g.drawRect(progressBar.x, progressBar.y, progressBar.width,progressBar.height);		
		g.setColor(Color.GREEN);
		g.drawString(nurDreiStellen(), rect_xpos+((rect_weite/2)-12),rect_ypos+((rect_hoehe/2)+4));
	}
	
	private void checkPerformance(Graphics g)
	{
		if (specnow < 1000){g.setColor(Color.RED);}
		if (1000 < specnow && specnow < 2000){g.setColor(Color.YELLOW);}
		if (2000 < specnow && specnow < 3000){g.setColor(Color.ORANGE);}
		if (3000 < specnow && specnow < 4000){g.setColor(Color.GREEN);}
		if (4000 < specnow && specnow < 5000){g.setColor(Color.CYAN);}
		if (specnow > 6000){g.setColor(Color.WHITE);}		
	}
	
	private void paintMatrix(Graphics g, int step)
	{
		foo = ll2.get(mr.nextInt(0,ll2.size()-1));
		String matrix = (foo.getMCounter().toString() + foo.getMData() + foo.getMData() + foo.getMTrouble());
		String temp = "SHA1=";
		try{temp += getSHA1Hash(matrix) + "..." + getSHA1Hash(matrix).length();}
		catch(NoSuchAlgorithmException nsae){temp+=matrix;}
		this.checkPerformance(g);
		int columbreak = 21;
		int painty = (columbreak);
		int iii = 0;			
		step -= 3;
		int paintx = spalte+rect_weite+step+step;
		for (int x = 0; x<temp.length(); x++ )
		{
			iii += 1;
			painty = (columbreak);
			painty += (step*iii);
			try{g.drawString(String.valueOf(temp.charAt(x)),paintx,painty);}
			catch (StringIndexOutOfBoundsException sioobe) {}
			if (x%columbreak == 1)
			{
				paintx +=step;
				painty = (columbreak);
				iii=0;
			}
		}
	}
	
	private String nurDreiStellen(){return String.valueOf(Math.round(percent*100))+ " %" ;}		
	
	class myRandom extends SecureRandom
	{
		private static final long serialVersionUID = 3;
		private Thread random = null;
		public myRandom(){super();random = new Thread(random);random.start();}		
		public int nextInt(int min, int max)
		{try{return this.nextInt(max - min + 1) + min;}
		catch (IllegalArgumentException iae){return this.nextInt();}}
		public int nextBigChar(){return this.nextInt(48,90);}
		public int nextSmallChar(){return this.nextInt(97,122);}
	}
	
	class VergleichData 
	{
		private static final long serialVersionUID = 4;
		private Thread datavergleich = null;
		public VergleichData(){datavergleich = new Thread(datavergleich);datavergleich.start();}
		
		public LinkedList<DataObjekt> entferneDoppelteCounter(LinkedList<DataObjekt> tempList)
		{
			int objectunique = tempList.size();
			while (tempList.size() > 1 && objectunique+1 > tempList.size())
			{
				Collections.sort(tempList, new VergleichCounter());
				for (int i = 1; i < tempList.size(); i++)
				{	
					do
					{
						foa = tempList.get(i);
						fob = tempList.get(i-1);
						if (foa.getMCounter().equals(fob.getMCounter()))
						{tempList.remove(i-1);}
					}while (i<tempList.size() && (foa.getMCounter().equals(fob.getMCounter())));
					objectunique = Collections.binarySearch(tempList,foa,new VergleichCounter());
				}			
			}
			return tempList;
		}
		
		public LinkedList<DataObjekt> entferneDoppelteClown(LinkedList<DataObjekt> tempList)
		{
			int objectunique = tempList.size();
			while (tempList.size() > 1 && objectunique+1 > tempList.size())
			{
				Collections.sort(tempList, new VergleichClown());
				for (int i = 1; i < tempList.size(); i++)
				{	
					do
					{
						foa = tempList.get(i);
						fob = tempList.get(i-1);
						if (foa.getMClown().equals(fob.getMClown()))
						{tempList.remove(i-1);}
					}while (i<tempList.size() && (foa.getMClown().equals(fob.getMClown())));
					objectunique = Collections.binarySearch(tempList,foa,new VergleichClown());
				}			
			}
			return tempList;
		}
	}
	
	class VergleichCounter implements Comparator
	{
		private static final long serialVersionUID = 5;
		public VergleichCounter() {}
		
		public int compare(Object a, Object b)
		{
			foa = (JavaPerformanceTestApplet.DataObjekt)a;
			fob = (JavaPerformanceTestApplet.DataObjekt)b;
			int ergebnis = 1;		
			if (foa.getMData().equals(fob.getMCounter()))
			{ergebnis = foa.getMCounter().compareTo(fob.getMCounter());}
			else
			{ergebnis = foa.getMCounter().compareTo(fob.getMCounter());}							
			return ergebnis;		
		}
	}
	
	class VergleichClown<K extends Comparable<? super K>>  implements Comparator
	{
		private static final long serialVersionUID = 6;
		public VergleichClown() {}
		
		public int compare(Object a, Object b)
		{
			foa = (DataObjekt)a;
			fob = (DataObjekt)b;
			int ergebnis = 1;		
			if (foa.getMClown().equals(fob.getMClown()))
			{ergebnis = foa.getMClown().compareTo(fob.getMClown());}
			else
			{ergebnis = foa.getMClown().compareTo(fob.getMClown());}							
			return ergebnis;		
		}
	}
	
	public class DataObjekt 
	{
		private static final long serialVersionUID = 6;
		private Thread da = null;
		private String mCounter = "Counter";
		private String mData = "Data";
		private String mClown = "Clown";
		private String mTrouble = "Trouble";
		private int mTotal = 0;
		public DataObjekt() {da=new Thread(da);da.start();}
		public String getMCounter() {return mCounter;}
		public void setMCounter(String counter) {mCounter = counter;}
		public String getMData(){return mData;}
		public void setMData(String data){mData = data;}
		public String getMClown(){return mClown;}
		public void setMClown(String clown){mClown = clown;}
		public String getMTrouble(){return mTrouble;}
		public void setMTrouble(String trouble){mTrouble = trouble;}
		public int getMTotal(){return mTotal;}
		public void setMTotal(int total) {mTotal = total;}
		
		private DataObjekt machObjekt()
		{
			DataObjekt doo = new DataObjekt();
			doo.setMCounter(String.valueOf(mr.nextInt(0,9)));
			doo.setMData(machString(mr.nextInt(rndmin,(multiplier*rndmax))));
			doo.setMClown(machString(mr.nextInt(rndmin,(multiplier*rndmax*(int)Math.PI))));
			doo.setMTrouble(machString(mr.nextInt(rndmin,(multiplier*rndmax*(int)Math.E))));
			doo.setMTotal(doo.getMCounter().length()+doo.getMData().length()+doo.getMClown().length()+doo.getMTrouble().length());
			mBytes += doo.getMTotal();
			return doo;
		}
		
		private String machString(int l)
		{
			String newString = "";
			for(int i = 0; i < l; i++) 
			{newString += ((char)(mr.nextBigChar())) +""+ ((int)(mr.nextInt(i,l))) +""+ ((char)(mr.nextSmallChar()));}
			return newString;
		}
	}
}
