package net.soupgames.guimark2;

/**
 * GuiMark2 Text in Java.
 * Version 1.2
 *
 * Written by Jesper Juul, www.jesperjuul.net
 * 
 * This is a quick port from HTML5/JavaScript to Java 1.5.
 * 
 *  Results on my 2007 Thinkpad T60p, running Windows XP, Java 1.6.0_20:
 *  HTML5 Firefox: 18 FPS
 *  Flash: 2 FPS  
 *  Java: 13 FPS
 *
 * V1.0: Runs.
 * V1.1: Made to work on Java 1.5.
 * V1.2: Code cleanup, fixed mistake where the center panel had a more text than specified in the GUImark2 test
 */
import java.applet.Applet;
import java.awt.Button;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Label;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferStrategy;
import java.io.InputStream;
import java.net.URL;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTextArea;

public class text extends Applet implements Runnable, ActionListener {

	private static final String JAPANESE = "せっかく見つけたすばらしい記事がどこにあったか忘れてしまった経験はありますか ならタイトルとアドレスだけでなく、訪問したウェブページのコンテンツからも検索することができます。せっかく見つけたすばらしい記事がどこにあったか忘れてしまった経験はありますか ならタイトルとアドレスだけでなく、訪問したウェブページのコンテンツからも検索することができます。訪問したウェブページのコンテンツからも検索することができます。せっかく見つけたすばらしい記事がどこにあったか忘れてしまった経験はありますか ならタイトルとアドレスだけでなく、訪問\n";

	private static final String RUSSIAN = "Очередь заведено создаете те про, джоэл должен написано вы всю. Получаете отказаться программистов миф мы, не пишете размере количества нее, по две заведено безостановочно? Ещё то этой вреде внешних, люсита автора принадлежите мы опа. Ну эти всегда образование\n";

	private static final String ENGLISH = "Curabitur quis neque quis lacus mollis laoreet vitae eget dolor. Curabitur sodales, diam eget viverra volutpat, nibh ligula tincidunt magna, quis ornare nibh metus vitae dui. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse viverra felis non\n";

	private static final int W = 1200, H = 600, XPOS = 0, YPOS = 40;
	private static final int CW = 200, CH = 300;
	private static final long serialVersionUID = 1882731086792923772L;

	private Thread thread = null;

	Label meterlabel;
	FPSMeter meter = new FPSMeter();
	Button starttestbutton;
	double fps;

	private Label testresult;

	// Start timer at next update
	private Boolean starttest = false;

	private JPanel panel;

	private BufferStrategy bufferstrategy;

	private Canvas drawcanvas;

	long startTime = System.currentTimeMillis();

	private JComponent center;

	private JComponent bottomright;

	private JComponent topright;

	private JComponent bottomleft;

	private JComponent topleft;

	boolean expand = true;
	int expandwidth = 200;

	// test runner
	long testBegin = 0;
	Vector<Long> testData = new Vector<Long>();

	boolean testRunning = false;

	@Override
	public synchronized void start() {

		if (thread == null) {
			thread = new Thread(this);
			thread.setPriority(Thread.MIN_PRIORITY);
			thread.start();
		}
	}

	synchronized void initGraphics() {

		setLayout(null);

		Label title = new Label("GuiMark2 Java Text Test");
		title.setBounds(10, 10, 300, 20);
		Font f = getFont();
		title.setFont(new Font(f.getName(), Font.BOLD, f.getSize()));
		add(title);

		meterlabel = new Label("");
		meterlabel.setBounds(400, 10, 200, 20);
		add(meterlabel);

		testresult = new Label("Loading fonts - please wait.");
		testresult.setBounds(600, 10, 200, 20);
		add(testresult);

		starttestbutton = new Button("Start Test");
		starttestbutton.setBounds(800, 10, 100, 20);
		add(starttestbutton);
		starttestbutton.addActionListener(this);

		panel = new JPanel();
		panel.setSize(W, H);
		panel.setLocation(XPOS, YPOS);
		// add(panel);

		panel.setLayout(null);

		topleft = makeTextComponent(concatStr(ENGLISH, 60));
		topleft.setDoubleBuffered(false);
		topleft.setBounds(0, 0, CW, CH);

		try {
			InputStream is = new URL(getDocumentBase(), "fonts/Champignon.ttf")
					.openStream();
			Font font = Font.createFont(Font.TRUETYPE_FONT, is);
			topleft.setFont(font.deriveFont(Font.PLAIN, 14));
		} catch (Exception e) {
			e.printStackTrace();
		}
		panel.add(topleft);

		bottomleft = makeTextComponent(concatStr(ENGLISH, 60));
		bottomleft.setBounds(0, CH, CW, CH);

		try {
			InputStream is = new URL(getDocumentBase(), "fonts/StarJedi.ttf")
					.openStream();
			Font font = Font.createFont(Font.TRUETYPE_FONT, is);
			bottomleft.setFont(font.deriveFont(Font.PLAIN, 14));
		} catch (Exception e) {
			e.printStackTrace();
		}
		panel.add(bottomleft);
		bottomleft.setBorder(BorderFactory.createMatteBorder(2, 0, 0, 0,
				Color.black));

		topright = makeTextComponent(concatStr(RUSSIAN, 60));
		topright.setBounds(W - CW, 0, CW, CH);
		panel.add(topright);

		bottomright = makeTextComponent(concatStr(JAPANESE, 60));
		bottomright.setBounds(W - CW, CH, CW, CH);
		panel.add(bottomright);
		bottomright.setBorder(BorderFactory.createMatteBorder(2, 0, 0, 0,
				Color.black));

		// Using the mttare font
		// http://maktak.hp.infoseek.co.jp/
		try {
			InputStream is = new URL(getDocumentBase(), "fonts/MT_TARE.ttf")
					.openStream();
			Font font = Font.createFont(Font.TRUETYPE_FONT, is);
			bottomright.setFont(font.deriveFont(Font.PLAIN, 14));
		} catch (Exception e) {
			e.printStackTrace();
		}

		center = makeTextComponent(concatStr(ENGLISH, 60));
		center.setBorder(BorderFactory.createMatteBorder(0, 2, 0, 2,
				Color.black));
		center.setBounds(CW, 0, W - CW * 2, H);
		panel.add(center);

		drawcanvas = new Canvas();
		drawcanvas.setSize(W, H);
		drawcanvas.setLocation(XPOS, YPOS);
		add(drawcanvas);
		drawcanvas.createBufferStrategy(2);
		bufferstrategy = drawcanvas.getBufferStrategy();

		testresult.setText("");

	}

	private JComponent makeTextComponent(String string) {
		// Experiment: Is JTextPane faster than JTextArea?
		// Answer: Slightly on Java 1.6 on Windows, much slower on Mac - both 1.5 and 1.6  
//		String version = System.getProperty("java.version");
//		char major = version.charAt(0);
//		char minor = version.charAt(2);
//		if ((major < '2') && (minor < '6')) {
			JTextArea jt = new JTextArea();
			jt.setText(string);
			jt.setLineWrap(true);
			jt.setWrapStyleWord(true);
			return jt;
//		} else {
//			JTextPane jt = new JTextPane();
//			jt.setText(string);
//			jt.setEditable(false);
//			return jt;
//		}
	}

	/**
	 * 
	 */
	synchronized void processFrame() {
		if (expand) {
			expandwidth++;
			if (expandwidth == 400) {
				expand = false;
			}
		} else {
			expandwidth--;
			if (expandwidth == 200) {
				expand = true;
			}
		}

		topleft.setBounds(0, 0, expandwidth, CH);
		bottomleft.setBounds(0, CH, expandwidth, CH);
		topright.setBounds(W - expandwidth, 0, expandwidth, CH);
		bottomright.setBounds(W - expandwidth, CH, expandwidth, CH);
		center.setBounds(expandwidth, 0, W - expandwidth * 2, H);

		try {
			Graphics2D draw = (Graphics2D) bufferstrategy.getDrawGraphics();
			draw.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
					RenderingHints.VALUE_ANTIALIAS_ON);

			// Not sure how to make Swing paint immediately without flickering,
			// so
			// rather making it draw into a buffer.
			//
			topleft.paint(draw);
			draw.translate(0, CH);
			bottomleft.paint(draw);
			draw.translate(W - expandwidth, -CH);
			topright.paint(draw);
			draw.translate(0, CH);
			bottomright.paint(draw);
			draw.translate(-(W - expandwidth * 2), -CH);
			center.paint(draw);
			draw.dispose();

			bufferstrategy.show();
		} catch (Exception e) {
			// e.printStackTrace();
		}

		updatePerformance();
	}

	void updatePerformance() {
		meter.increment();
		if (testRunning) {
			continueTest();
		}
		meterlabel.setText("Current: " + meter.getFramerate() + " fps");
	}

	String concatStr(String str, int num) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < num; i++)
			sb.append(str);
		return sb.toString();

	}

	synchronized void startTest() {
		testBegin = System.currentTimeMillis();
		testRunning = true;
		testData.removeAllElements();
		testresult.setText("Running...");
	}

	synchronized void continueTest() {
		long time = System.currentTimeMillis();
		testData.add(time);
		if (time - testBegin > 10000) {
			testRunning = false;
			double output = ((double) testData.size() / (double) (time - testBegin)) * 1000;
			testresult.setText("Test Average: " + meter.formatNumber(output)
					+ " fps");
		}
	}

	class FPSMeter {
		String sampleFPS = "0";
		long lastSampledTime = 0;
		int sampleFrames = 0;

		int sampleDuration = 500;

		void increment() {
			sampleFrames++;
		}

		String getFramerate() {
			double diff = System.currentTimeMillis() - lastSampledTime;
			if (diff >= sampleDuration) {
				double rawFPS = sampleFrames / (diff / 1000);
				sampleFPS = formatNumber(rawFPS);
				sampleFrames = 0;
				lastSampledTime = System.currentTimeMillis();
			}
			return sampleFPS;
		}

		String formatNumber(double rawFPS) {
			// format as XX.XX
			return "" + Math.floor(rawFPS * 100) / 100;
		}
	}

	synchronized long getTimer() {
		return System.currentTimeMillis() - startTime;
	}

	public void run() {

		initGraphics();
		while (true) {
			processFrame();

			synchronized (starttest) {
				if (starttest) {
					starttest = false;
					startTest();
				}
			}
		}
	}

	// When a button is pushed
	public void actionPerformed(ActionEvent evt) {
		if (evt.getSource() == starttestbutton) {
			synchronized (starttest) {
				starttest = true;
			}
		}

	}

}

