import java.awt.AWTEvent;
import java.awt.Dimension;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import net.mw3.etewt3.utils.Filter;
import net.mw3.etewt3.utils.Vector;
import com.sun.jna.Memory;

import net.mw3.etewt3.WIN.User32;
import net.mw3.etewt3.handlers.GameInput;
import net.mw3.etewt3.handlers.MWPlayer;
import net.mw3.etewt3.handlers.MemoryHack;
import net.mw3.etewt3.handlers.WindowHandler;
import net.mw3.etewt3.script.ScriptEngine;
import net.mw3.etewt3.utils.Constants;

public class Aimbot extends ScriptEngine {

	public static Aimbot instance = null;
	private double distance;

	public Aimbot() {
		instance = this;
	}

	@Override
	public int loop() throws Exception {
		if (WindowHandler.user32.GetAsyncKeyState(User32.Keys.H) << 16 != 0) {
			MemoryHack.writeMemory(Constants.VIEWANGLEBUFFER, new float[] { 100, 100 }, 8);
		}
		if (WindowHandler.user32.GetAsyncKeyState(User32.Keys.F) << 16 != 0) {

			Robot robot = new Robot();
			MWPlayer our = getLocalPlayer();
			MWPlayer targetPlayer = getClosest();
			if (targetPlayer != null) {
				distance = (1 / targetPlayer.getDistance());
				float dist = 4;
				if (!our.isZoomed()) {
					robot.mousePress(InputEvent.BUTTON3_MASK);
					sleep(200);
				}
				for (int i = 0; i < 75; i++) {
					if (targetPlayer != null)
						if (targetPlayer.isValid()) {
							dist = getDist(targetPlayer, our);
							aimAt(targetPlayer, (distance * dist));
							GameInput.setEvent(GameInput.InputType.Mouse, InputEvent.BUTTON1_MASK);
							sleep(20);
							targetPlayer = getClosest();
						}

				}
				robot.mouseRelease(InputEvent.BUTTON3_MASK);
			}
		}
		return 50;
	}

	private MWPlayer getClosest() {
		MWPlayer[] players = getAll(new Filter<MWPlayer>() {

			@Override
			public boolean accept(MWPlayer player) {
				if (!allForOne() && player.getTeam() != getLocalPlayer().getTeam() && player.isValid() || allForOne() && player.isValid() && player.index != localIndex()) {
					return true;
				}
				return false;
			}

		});
		MWPlayer targetPlayer = null;
		for (MWPlayer player : players) {
			if (player.index == getLocalPlayer().index || !player.isValid())
				continue;
			float[] angles = getAnglesTo(player);
			double dist = Math.sqrt((angles[0] * angles[0]) + (angles[1] * angles[1]));

			if (dist < 20) {
				if (targetPlayer == null) {
					if (player.getDistance() < 100)
						targetPlayer = player;
				}
				if (player.getDistance() < targetPlayer.getDistance())
					targetPlayer = player;
			}
		}
		return targetPlayer;
	}

	private int getDist(MWPlayer targetPlayer, MWPlayer our) {
		if (targetPlayer.getViewAngles()[0] >= 62 && !targetPlayer.isProne() && !targetPlayer.isCrouched()) {
			return (int) (targetPlayer.getViewAngles()[0] - our.getViewAngles()[0]) - 62;
		} else if (targetPlayer.getViewAngles()[0] >= 28 && targetPlayer.getViewAngles()[0] < 62 && !targetPlayer.isProne() && !targetPlayer.isCrouched()) {
			return (int) (targetPlayer.getViewAngles()[0] - our.getViewAngles()[0]) - 28;
		} else {
			if (our.isCrouched() && targetPlayer.isCrouched() || our.isProne() && targetPlayer.isProne())
				return 6;
			if (our.isStanding() && targetPlayer.isCrouched())
				return 23;
			if (our.isStanding() && targetPlayer.isProne())
				return 65;
			if (our.isCrouched() && targetPlayer.isStanding())
				return -15;
			if (our.isCrouched() && targetPlayer.isProne())
				return 23;
			if (our.isProne() && targetPlayer.isStanding())
				return -56;
			if (our.isProne() && targetPlayer.isCrouched())
				return -29;
			return 6;
		}
	}

	@Override
	public boolean onStart() {
		return true;
	}

	public float[] getAnglesTo(MWPlayer target) {
		Memory viewAxisBuffer = MemoryHack.readMemory(Constants.REFDEF + 0x24, 36);
		float[][] viewAxis = new float[3][3];
		int index = 0;
		for (int i = 0; i < 3; i++) {
			viewAxis[i][0] = viewAxisBuffer.getFloat(index++ * 4);
			viewAxis[i][1] = viewAxisBuffer.getFloat(index++ * 4);
			viewAxis[i][2] = viewAxisBuffer.getFloat(index++ * 4);
		}

		float[] vector = Vector.vectorSubtract(target.getRawLocation(), getLocalPlayer().getRawLocation());

		vector = Vector.normalize(vector);

		return new float[] { (float) Vector.toDegree((float) Math.asin(Vector.dotProduct(viewAxis[1], vector))), (float) Vector.toDegree((float) -Math.asin(Vector.dotProduct(viewAxis[2], vector))) };
	}

	public boolean aimAt(MWPlayer target, double verticalOffset) {
		MWPlayer local = getLocalPlayer();
		if (target == null || local == null)
			return false;

		Memory angleBuffer = MemoryHack.readMemory(Constants.VIEWANGLEBUFFER, 8);

		float[] angles = getAnglesTo(target);

		angles[0] += angleBuffer.getFloat(4);
		angles[1] += angleBuffer.getFloat(0) + verticalOffset;

		MemoryHack.writeMemory(Constants.VIEWANGLEBUFFER, new float[] { angles[1], angles[0] }, 8);
		return true;
	}
}