import java.applet.Applet;
import java.applet.AppletStub;
import java.awt.Dimension;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;

import javax.swing.JFrame;

/**
 * An {@link Applet} used for loading the rs2-client.
 * 
 * @author Thomas Le Godais <thomaslegodais@live.com>
 */
public class RS2Loader extends Applet implements AppletStub {

	/**
	 * An generated serial UID.
	 */
	private static final long serialVersionUID = 1670498001014004354L;

	/**
	 * This client instance.
	 */
	private static RS2Loader rsLoader;

	/**
	 * The parameters of the client.
	 */
	private Properties parameters = new Properties();

	/**
	 * The current frame of the client application.
	 */
	public JFrame clientFrame = null;

	/**
	 * The print stream instance.
	 */
	// private PrintStream printStream;

	/**
	 * The main entry point of the current application.
	 * 
	 * @param args
	 *            The command line arguments.
	 */
	public static void main(String... args) {
		rsLoader = new RS2Loader();
		rsLoader.doFrame();
	}

	/**
	 * Performs the operations needed to show the client.
	 */
	private void doFrame() {
		readParameters();
		openFrame();
		startClient();
		clientFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	/**
	 * Starts the actual client.
	 */
	private void startClient() {
		try {

			Class<?> client_class = Class.forName("client");

			Object v_client = client_class.getConstructor().newInstance();
			client_class.getSuperclass().getMethod("supplyApplet", Applet.class).invoke(v_client, this);
			client_class.getMethod("init").invoke(v_client);
			client_class.getMethod("start").invoke(v_client);
			/*
			 * File[] files = new File("./dumps/").listFiles(); int totalNumber
			 * = 0; for (int index = 0; index < files.length; index++) { File
			 * file = files[index]; if (file == null) { continue; } String
			 * fileName = file.getName(); if (fileName.startsWith("dump-")) {
			 * totalNumber++; } } printStream = new PrintStream(new
			 * FileOutputStream("./dumps/dump-"+totalNumber+".txt"));
			 */
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Opens the actual frame application.
	 */
	private void openFrame() {
		clientFrame = new JFrame("Jagex");
		clientFrame.add(this);
		clientFrame.setVisible(true);
		clientFrame.setSize(800, 600);
	}

	/**
	 * Reads the parameters text file, and stores the parameters.
	 */
	@SuppressWarnings("resource")
	private void readParameters() {
		try {
			BufferedReader reader = new BufferedReader(new FileReader("./params.txt"));

			String line;
			while ((line = reader.readLine()) != null) {
				if (line.contains("document.write('<param name=")) {
					String[] regex = line.split(" value=");

					String parameterName = regex[0];
					String[] parameterRegex = parameterName.split("name=");
					String finalParameter = parameterRegex[1].replaceAll("\"", "");

					String parameterValue = regex[1];
					String finalValue = parameterValue.replaceAll("\"", "").replace(">');", "");

					parameters.put(finalParameter, finalValue);
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.applet.AppletStub#appletResize(int, int)
	 */
	@Override
	public void appletResize(int dimensionX, int dimensionY) {
		super.resize(new Dimension(dimensionX, dimensionY));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.applet.Applet#getParameter(java.lang.String)
	 */
	@Override
	public String getParameter(String paramName) {
		return (String) parameters.get(paramName);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.applet.Applet#getDocumentBase()
	 */
	@Override
	public URL getDocumentBase() {
		try {
			return new URL("http://world8.runescape.com");
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.applet.Applet#getCodeBase()
	 */
	@Override
	public URL getCodeBase() {
		try {
			return new URL("http://world8.runescape.com");
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * If we should print out interfaces.
	 */
	public static final boolean PRINTING_INTERFACES = true;

	/**
	 * Prints out the current interface sent to the client.
	 * 
	 * @param interfaceId
	 *            The ID of the interface.
	 * @param interfacePosition
	 *            The position of the interface on the screen.
	 * @param walkable
	 *            If the interface can be walked around when opened.
	 */
	public void onInterface(int interfaceId, int interfacePosition, int walkable) {
		if (!PRINTING_INTERFACES) {
			return;
		}
		int windowID = interfacePosition >> 16;
		int slotID = interfacePosition & 0xFFFF;
		boolean isWalkable = (walkable == 1);
		// printStream.println("sendInterface(" + interfaceId + ", " + windowID
		// + ", " + slotID + ", " + isWalkable + ");");
		System.out.println("sendInterface(" + interfaceId + ", " + windowID + ", " + slotID + ", " + isWalkable + ");");
	}

	/**
	 * If we should print out interface configs.
	 */
	public static final boolean PRINTING_INTERFACE_CONFIGS = true;

	/**
	 * Prints out the interface config sent to the client.
	 * 
	 * @param position
	 *            The position of the config.
	 * @param start
	 *            The start value of the config.
	 * @param end
	 *            The end value of the config.
	 * @param hash
	 *            The config hash.
	 */
	public void onInterfaceConfig(int position, int start, int end, int hash) {
		if (!PRINTING_INTERFACE_CONFIGS) {
			return;
		}
		int windowID = position >> 16;
		int slotID = position & 0xFFFF;
		// printStream.println("interfaceConfig(" + windowID + ", " + slotID +
		// ", " + start + ", " + end + ", " + hash + ");");
		System.out.println("interfaceConfig(" + windowID + ", " + slotID + ", " + start + ", " + end + ", " + hash + ");");
	}

	/**
	 * If we should print out configs or not.
	 */
	public static final boolean PRINTING_CONFIGS = true;

	/**
	 * Prints out a config sent to the client.
	 * 
	 * @param configID
	 *            The ID of the config.
	 * @param configValue
	 *            The value of the config.
	 */
	public void onConfig(int configID, int configValue) {
		if (!PRINTING_CONFIGS) {
			return;
		}
		// printStream.println("Config(" + configID + ", " + configValue +
		// ");");
		System.out.println("Config(" + configID + ", " + configValue + ");");
	}

	/**
	 * If we're printing out client scripts.
	 */
	public static final boolean PRINTING_CLIENT_SCRIPTS = true;

	/**
	 * Prints out a client script sent to the client.
	 * 
	 * @param objects
	 *            The client script objects.
	 */
	public void onClientScript(Object[] objects) {
		if (!PRINTING_CLIENT_SCRIPTS) {
			return;
		}
		StringBuilder builder = new StringBuilder("ClientScript(");
		for (int index = 0; index < objects.length; index++) {
			builder.append(objects[index]);
			if (index != (objects.length - 1)) {
				builder.append(", ");
			}
		}
		builder.append(");");
		// printStream.println(builder.toString());
		System.out.println(builder.toString());
	}

	/**
	 * If we're printing out CS2 Configs.
	 */
	public static final boolean PRINTING_CS2_CONFIGS = true;

	/**
	 * Prints out a cs2 config sent to the client.
	 * 
	 * @param configID
	 *            The ID of the config.
	 * @param configValue
	 *            The value of the config.
	 */
	public void onCS2Config(int configID, int configValue) {
		if (!PRINTING_CS2_CONFIGS) {
			return;
		}
		// printStream.println("CS2Config(" + configID + ", " + configValue +
		// ");");
		System.out.println("CS2Config(" + configID + ", " + configValue + ");");
	}

	/**
	 * Gets the instance of the client.
	 * 
	 * @return The instance.
	 */
	public static RS2Loader getInstance() {
		return rsLoader;
	}
}