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

import javax.swing.JFrame;

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

	public static final BigInteger JS5_PUBLIC_KEY = new BigInteger("65537");
	public static final BigInteger JS5_MODULUS = new BigInteger("94666348539958968834808460611852149211785356996377796698379618753799159545647881011484461408556075779272322957335990663560201447187011818120054586219288795904417679307872458425003354947779149675488956246296991286683045531197716929411226131948190685619562593508263921455324012129739743813729218800184508603103");

	public static final BigInteger LOGIN_PUBLIC_KEY = new BigInteger("65537");
	public static final BigInteger LOGIN_MODULUS = new BigInteger("110063664812358969356231542802081947430528122676297579730619346412273936349316977898593694252445030315541775603083844994256827557662800678113875799813210037390451780955652066595663249072526970095850959080070233374137191355324004067236273088126264135372668465043785730938661534728528236258802847613346000117499");

	public static String[] IN_PACKET_NAMES = new String[512];
	public static boolean[] IGNORED_PACKETS = new boolean[512];

	static {
	}

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

	public static Loader ctx;

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

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

	public boolean RSPS = true;
	public String host, lobbyHost;

	public boolean debug = true;

	/**
	 * The main entry point of the current application.
	 * 
	 * @param args The command line arguments.
	 */
	public static void main(String... args) throws IOException {
		Loader rsLoader = ctx = new Loader();
		rsLoader.RSPS = true;
		rsLoader.host = "127.0.0.1";
		rsLoader.lobbyHost = rsLoader.host;
		rsLoader.doFrame();
	}

	private PrintStream logStream;
	private PrintStream printStream;

	/**
	 * 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);

		} 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("./data/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(">');", "");

					if (RSPS && finalValue.startsWith("lobby")) {
						finalValue = lobbyHost;
					}
					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://" + host + "");
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		return null;
	}

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

	public void debug(String message) {
		if (debug) {
			logStream.println(message);
			printStream.println(message);
		}
	}

	public void onIncommingPacket(int id, int size) {
		if (!IGNORED_PACKETS[id]) {
			if (IN_PACKET_NAMES[id] == null) {
				// debug("Incomming packet [id=" + id + ", size=" + size + "]");
			} else {
				debug("Incomming : " + IN_PACKET_NAMES[id]);
			}
		}
	}

	public void onLobbyPacket1(int val1, int val2, int val3) {
		debug("LobbyPacket1(" + val1 + ", " + val2 + ", " + val3 + ")");
	}

	public void onConfig(int id, int val) {
//		debug("Config(" + id + ", " + val + ")");
	}

	public void onInterface(int id, int position, boolean walkable) {
		int window = position >> 16;
		int slot = position & 0xffff;
		debug("Interface(" + id + ", " + window + ", " + slot + ", " + walkable + ")");
	}

	public void onInterfaceConfig(int position, int start, int end, int hash) {
		int window = position >> 16;
		int slot = position & 0xffff;
		debug("InterfaceConfig(" + window + ", " + slot + ", " + start + ", " + end + ", " + hash + ")");
	}

	public void onCSConfig(int id, int val) {
		debug("CSConfig(" + id + ", " + val + ")");
	}

	public void onCS(Object[] args) {
		StringBuilder sb = new StringBuilder("ClientScript(");
		for (int i = 0; i < args.length; i++) {
			sb.append(args[i]);
			if (i != (args.length - 1)) {
				sb.append(", ");
			}
		}
		sb.append(")");
		debug(sb.toString());
	}

	public void onSpecialInterface(int position, int id, boolean walkable, int position2, int id2) {
		int window = position >> 16;
		int slot = position & 0xffff;
		int window2 = position2 >> 16;
		int slot2 = position2 & 0xffff;
		debug("SInterface(" + id + ", " + window + ", " + slot + ", " + walkable + ", " + id2 + ", " + window2 + ", " + slot2 + ")");
	}
}