package common.util;

public abstract class ExtMath {
	private static final float[] SIN_TABLE = new float[65536];
	private static final double ATAN_ADD = Double.longBitsToDouble(4805340802404319232L);
	private static final double[] ATAN_SIN = new double[257];
	private static final double[] ATAN_COS = new double[257];

	static {
		for(int z = 0; z < 65536; z++) {
			SIN_TABLE[z] = (float)Math.sin((double)z * Math.PI * 2.0D / 65536.0D);
		}
		for(int z = 0; z < 257; z++) {
			double a = Math.asin((double)z / 256.0D);
			ATAN_COS[z] = Math.cos(a);
			ATAN_SIN[z] = a;
		}
	}

	public static float sin(float value) {
		return SIN_TABLE[(int)(value * 10430.378F) & 65535];
	}

	public static float cos(float value) {
		return SIN_TABLE[(int)(value * 10430.378F + 16384.0F) & 65535];
	}

	public static float sqrtf(float value) {
		return (float)Math.sqrt((double)value);
	}

	public static float sqrtd(double value) {
		return (float)Math.sqrt(value);
	}

	public static int floorf(float value) {
		int i = (int)value;
		return value < (float)i ? i - 1 : i;
	}

	public static int floord(double value) {
		int i = (int)value;
		return value < (double)i ? i - 1 : i;
	}

	public static float absf(float value) {
		return value >= 0.0F ? value : -value;
	}

	public static int absi(int value) {
		return value >= 0 ? value : -value;
	}

	public static int ceilf(float value) {
		int i = (int)value;
		return value > (float)i ? i + 1 : i;
	}

	public static int ceild(double value) {
		int i = (int)value;
		return value > (double)i ? i + 1 : i;
	}

	public static int clampi(int num, int min, int max) {
		return num < min ? min : (num > max ? max : num);
	}

	public static float clampf(float num, float min, float max) {
		return num < min ? min : (num > max ? max : num);
	}

	public static double clampd(double num, double min, double max) {
		return num < min ? min : (num > max ? max : num);
	}

	public static float wrapf(float value) {
		value = value % 360.0F;

		if(value >= 180.0F) {
			value -= 360.0F;
		}

		if(value < -180.0F) {
			value += 360.0F;
		}

		return value;
	}

	public static double wrapd(double value) {
		value = value % 360.0D;

		if(value >= 180.0D) {
			value -= 360.0D;
		}

		if(value < -180.0D) {
			value += 360.0D;
		}

		return value;
	}

	public static double atan2(double v1, double v2) {
		double d0 = v2 * v2 + v1 * v1;

		if(Double.isNaN(d0)) {
			return Double.NaN;
		}
		else {
			boolean flag = v1 < 0.0D;

			if(flag) {
				v1 = -v1;
			}

			boolean flag1 = v2 < 0.0D;

			if(flag1) {
				v2 = -v2;
			}

			boolean flag2 = v1 > v2;

			if(flag2) {
				double d1 = v2;
				v2 = v1;
				v1 = d1;
			}

			double p1 = 0.5D * d0;
			long li = Double.doubleToRawLongBits(d0);
			li = 6910469410427058090L - (li >> 1);
			d0 = Double.longBitsToDouble(li);
			d0 = d0 * (1.5D - p1 * d0 * d0);
			
			v2 = v2 * d0;
			v1 = v1 * d0;
			double d2 = ATAN_ADD + v1;
			int i = (int)Double.doubleToRawLongBits(d2);
			double d3 = ATAN_SIN[i];
			double d4 = ATAN_COS[i];
			double d5 = d2 - ATAN_ADD;
			double d6 = v1 * d4 - v2 * d5;
			double d7 = (6.0D + d6 * d6) * d6 * 0.16666666666666666D;
			double d8 = d3 + d7;

			if(flag2) {
				d8 = (Math.PI / 2D) - d8;
			}

			if(flag1) {
				d8 = Math.PI - d8;
			}

			if(flag) {
				d8 = -d8;
			}

			return d8;
		}
	}
}
