package geiger;

public class Simulation {
	public static int count = 0;

	public static int accumulator = 0;
	public static int accumulator2Ticks = 0;
	public static int ticks = 0;

	public static boolean run = true;

	public static void run() throws InterruptedException {
		while (run) {
			Thread.sleep(250);

			ticks++;

			accumulator += count;
			accumulator2Ticks += count;
			// Resets 4040
			count = 0;

			// Note: 'accumulator' will never, ever be > 8192 with the following algorithm

			// How to test 'accumulator2Ticks > ticks' on the real hardware:
			// from most significant bit, if 'accumulator2Ticks'[x] > 'ticks'[x], then 'accumulator2Ticks > ticks'
			if (accumulator2Ticks > ticks && ticks % 2 == 0 && ticks != 40) {
				// ticks == 2  -> accumulator*(4*40)/2  = accumulator*80
				// ticks == 4  -> accumulator*(4*40)/4  = accumulator*40
				// ticks == 6  -> accumulator*(4*40)/6  = accumulator*80/3
				// ticks == 8  -> accumulator*(4*40)/8  = accumulator*20
				// ticks == 10 -> accumulator*(4*40)/10 = accumulator*80/5
				// ticks == 12 -> accumulator*(4*40)/12 = accumulator*80/6
				// ticks == 14 -> accumulator*(4*40)/14 = accumulator*80/7
				// ticks == 16 -> accumulator*(4*40)/16 = accumulator*10
				// ticks == 18 -> accumulator*(4*40)/18 = accumulator*80/9
				// ticks == 20 -> accumulator*(4*40)/20 = accumulator*8
				// ticks == 22 -> accumulator*(4*40)/22 = accumulator*80/11
				// ticks == 24 -> accumulator*(4*40)/24 = accumulator*20/3
				// ticks == 26 -> accumulator*(4*40)/26 = accumulator*80/13
				// ticks == 28 -> accumulator*(4*40)/28 = accumulator*40/7
				// ticks == 30 -> accumulator*(4*40)/30 = accumulator*16/3
				// ticks == 32 -> accumulator*(4*40)/32 = accumulator*5
				// ticks == 34 -> accumulator*(4*40)/34 = accumulator*80/17
				// ticks == 36 -> accumulator*(4*40)/36 = accumulator*40/9
				// ticks == 38 -> accumulator*(4*40)/38 = accumulator*80/19

				// accumulator < 8192 -> (8192*4/2)*40=655360 -> 6.55mSv/h, but the tube does not support it!
				float temp = ((float) accumulator * 4.0f) / ((float) ticks); // Counts per Second (acc/(ticks/4))
				float uSv = temp * 40;
				System.out.println("I " + (uSv / 100.0f) + "µSv/h");

				// Test for bit 12
				if (accumulator > 4096) {
					ticks = 0;
					accumulator = 0;
				}
			} else if (ticks == 40) {
				float uSv = (((float) accumulator) * 4.0f); // 10s*4 = 40s; /100 for µSv
				System.out.println("@10s " + (uSv / 100.0f) + "µSv/h");

				ticks = 0;
				accumulator = 0;
			}

			if (ticks % 4 == 0) {
				accumulator2Ticks = 0;
			}
		}
	}

	/**
	 * This algorithm is perfect (= gives valid values for each input it's been designed for: 0->2^20-1).
	 */
	public static long[] decode20(long value) {
		long[] result = new long[6];

		value = value & 0x000FFFFF;

		long n4 = (value & 0x000F0000) >> 16;
		long n3 = (value & 0x0000F000) >> 12;
		long n2 = (value & 0x00000F00) >> 8;
		long n1 = (value & 0x000000F0) >> 4;
		long n0 = (value & 0x0000000F);

		/*
		n4 n3 n2 n1 n0
		n = 65536*n4 + 4096*n3 + 256*n2 + 16*n1 + 1*n0
		n = n4*(6*10000 + 5*1000 + 5*100 + 3*10 + 6)
		   +n3*(          4*1000         + 9*10 + 6)
		   +n2*(                   2*100 + 5*10 + 6)
		   +n1*(                           1*10 + 6)
		   +n0*(                                  1)
		n = 10000*(6*n4)
		   +1000 *(5*n4 + 4*n3)
		   +100  *(5*n4 + 2*n2)
		   +10   *(3*n4 + 9*n3 + 5*n2 + 1*n1)
		   +1    *(6*n4 + 6*n3 + 6*n2 + 6*n1 + 1*n0)
		n = 100000*d5 + 10000*d4 + 1000*d3 + 100*d2 + 10*d1 + 1*d0
		==>
		a4 = 6*n4
		a3 = 5*n4 + 4*n3
		a2 = 5*n4 + 2*n2
		a1 = 3*n4 + 9*n3 + 5*n2 + 1*n1
		a0 = 6*n4 + 6*n3 + 6*n2 + 6*n1 + 1*n0
		==>
		c1 = a0/10
		d0 = a0%10
		c2 = (a1+c1)/10
		d1 = (a1+c1)%10
		c3 = (a2+c2)/10
		d2 = (a2+c2)%10
		c4 = (a3+c3)/10
		d3 = (a3+c3)%10
		c5 = (a4+c4)/10
		d4 = (a4+c4)%10
		c6 = (a5+c5)/10
		d5 = (a5+c5)%10
		*/

		// a4 <= 6*15=90
		long a4 = 6 * n4;
		// a3 <= 135
		long a3 = 5 * n4 + 4 * n3;
		// a2 <= 105
		long a2 = 5 * n4 + 2 * n2;
		// a1 <= 288
		long a1 = 3 * n4 + 9 * n3 + 5 * n2 + 1 * n1;
		// a0 <= 375
		long a0 = 6 * n4 + 6 * n3 + 6 * n2 + 6 * n1 + 1 * n0;

		// c1 <= 37 (375/10)
		long c1 = a0 / 10;
		long d0 = a0 % 10;
		long c2 = (a1 + c1) / 10;
		long d1 = (a1 + c1) % 10;
		long c3 = (a2 + c2) / 10;
		long d2 = (a2 + c2) % 10;
		long c4 = (a3 + c3) / 10;
		long d3 = (a3 + c3) % 10;
		long c5 = (a4 + c4) / 10;
		long d4 = (a4 + c4) % 10;
		long d5 = c5;

		// Least significant
		result[0] = d0;
		result[1] = d1;
		result[2] = d2;
		result[3] = d3;
		result[4] = d4;
		// Most significant
		result[5] = d5;

		return result;
	}

	/**
	 * Perfect too. No approximation! Attention: Java can put values >255 into chars!!!
	 */
	public static long[] decode20approx(long value) {
		long[] result = new long[6];

		value = value & 0x000FFFFF;

		char n4 = (char) (((value & 0x000F0000) >> 16) & 0x0F);
		char n3 = (char) (((value & 0x0000F000) >> 12) & 0x0F);
		char n2 = (char) (((value & 0x00000F00) >> 8) & 0x0F);
		char n1 = (char) (((value & 0x000000F0) >> 4) & 0x0F);
		char n0 = (char) (value & 0x0000000F);

		boolean a1_carry = false;
		boolean a0_carry = false;
		char rest = (char) (0);
		char temp = (char) (0);

		// a4 <= 6*15=90
		char a4 = (char) (((char) (n4 + n4 + n4 + n4 + n4 + n4)) & 0xFF);
		// a3 <= 135
		char a3 = (char) (((char) (n4 + n4 + n4 + n4 + n4 + n3 + n3 + n3 + n3)) & 0xFF);
		// a2 <= 105
		char a2 = (char) (((char) (n4 + n4 + n4 + n4 + n4 + n2 + n2)) & 0xFF);
		// a1 <= 288
		char a1 = (char) (((char) (n3 + n3 + n3 + n3 + n3 + n3 + n3 + n3 + n3 + n2 + n2 + n2 + n2 + n2 + n1)) & 0xFF); // Max: 15*15 = 225 = 255 - 30
		rest = (char) (((char) (255 - a1)) & 0xFF);
		temp = (char) (((char) (n4 + n4 + n4)) & 0xFF);
		if (temp > rest) {
			a1_carry = true;
		}
		a1 = (char) (((char) (n4 + n4 + n4) + ((char) a1)) & 0xFF);
		// a0 <= 375
		char a0 = (char) (n4 + n4 + n4 + n4 + n4 + n4 + n3 + n3 + n3 + n3 + n3 + n3 + n0); // Max: 13*15 = 195 = 255 - 60
		rest = (char) (((char) (255 - a0)) & 0xFF);
		temp = (char) (((char) (n2 + n2 + n2 + n2 + n2 + n2)) & 0xFF);
		if (temp > rest) {
			a0_carry = true;
		}
		a0 = (char) (((char) (n2 + n2 + n2 + n2 + n2 + n2) + ((char) a0)) & 0xFF);
		rest = (char) (((char) (255 - a0)) & 0xFF);
		temp = (char) (((char) (n1 + n1 + n1 + n1 + n1 + n1)) & 0xFF);
		if (temp > rest) {
			a0_carry = true;
		}
		a0 = (char) (((char) (n1 + n1 + n1 + n1 + n1 + n1) + ((char) a0)) & 0xFF);

		char c1, c2, c3, c4, c5;
		char d0, d1, d2, d3, d4, d5;
		char[] c1d0 = div10AndMod10(a0, a0_carry, (char) 0);
		c1 = c1d0[0]; // q
		d0 = c1d0[1]; // r
		char[] c2d1 = div10AndMod10(a1, a1_carry, (char) c1);
		c2 = c2d1[0];
		d1 = c2d1[1];
		char[] c3d2 = div10AndMod10(a2, false, (char) c2); // a2+c2 <= 105+37 <= 255 (37 is the maximum for cY)
		c3 = c3d2[0];
		d2 = c3d2[1];
		char[] c4d3 = div10AndMod10(a3, false, (char) c3); // a3+c3 <= 135+37 <= 255 (37 is the maximum for cY)
		c4 = c4d3[0];
		d3 = c4d3[1];
		char[] c5d4 = div10AndMod10(a4, false, (char) c4); // a4+c4 <= 90+37 <= 255 (37 is the maximum for cY)
		c5 = c5d4[0];
		d4 = c5d4[1];
		d5 = c5;

		// Least significant
		result[0] = d0;
		result[1] = d1;
		result[2] = d2;
		result[3] = d3;
		result[4] = d4;
		// Most significant
		result[5] = d5;

		return result;
	}

	public static int div3(int A) {
		/* approximate A/3 */
		int Q = ((A >> 2) + A) >> 2; /* Q = A*0.0101 */
		Q = ((Q) + A) >> 2; /* Q = A*0.010101 */
		Q = ((Q) + A) >> 2; /* Q = A*0.01010101 */
		Q = ((Q) + A) >> 2; /* Q = A*0.0101010101 */
		Q = ((Q) + A) >> 1; /* Q = A*0.10101010101 */
		Q = ((Q >> 12) + Q); /* Q = A*0.10101010101010101010101 */
		Q = ((Q >> 24) + Q) >> 1; /* Q = A*0.010101010101001010101010101 ... */
		/* either Q = A/3 or Q+1 = A/3 for all 32-bit unsigned A */

		int R = (Q << 1) + Q;
		R = A - R;
		int T = R - 3;
		if (T >= 0)
			Q = Q + 1;
		if (T >= 0)
			R = T;
		return Q;
	}

	public static int div5(int A) {
		/* approximate A/5 */
		int Q = ((A >> 1) + A) >> 1; /* Q = A*0.11 */
		Q = ((Q >> 4) + Q); /* Q = A*0.110011 */
		Q = ((Q >> 8) + Q); /* Q = A*0.11001100110011 */
		Q = ((Q >> 16) + Q) >> 2; /* Q = A*0.001100110011001100110011001... */
		/* either Q = A/5 or Q+1 = A/5 for all 32-bit unsigned A */

		int R = (Q << 2) + Q;
		R = A - R;
		int T = R - 5;
		if (T >= 0)
			Q = Q + 1;
		if (T >= 0)
			R = T;
		return Q;
	}

	public static int div7(int A) {
		/* approximate A/7 */
		int Q = ((A >> 3) + A) >> 1; /* Q = A*0.1001 */
		Q = ((Q >> 6) + Q); /* Q = A*0.1001001001 */
		Q = ((Q >> 12) + Q); /* Q = A*0.1001001001001001001001 */
		Q = ((Q >> 24) + Q) >> 2; /* Q = A*0.001001001001001001001001001... */
		/* either Q = A/7 or Q+1 = A/7 for all 32-bit unsigned A */

		int R = (Q << 3) - Q;
		R = A - R;
		int T = R - 7;
		if (T >= 0)
			Q = Q + 1;
		if (T >= 0)
			R = T;
		return Q;
	}

	public static int div11(int A) {
		/* approximate A/11 */
		int Q = ((A >> 2) + A) >> 1; /* Q = A*0.101 */
		Q = ((Q) + A) >> 1; /* Q = A*0.1101 */
		Q = ((Q) + A) >> 2; /* Q = A*0.011101 */
		Q = ((Q) + A) >> 1; /* Q = A*0.1011101 */
		Q = ((Q >> 10) + Q); /* Q = A*0.10111010001011101 */
		Q = ((Q >> 20) + Q) >> 3; /* Q = A*0.000101110100010111010001011... */
		/* either Q = A/11 or Q+1 = A/11 for all 32-bit unsigned A */

		int R = (((Q << 2) + Q) << 1) + Q;
		R = A - R;
		int T = R - 11;
		if (T >= 0)
			Q = Q + 1;
		if (T >= 0)
			R = T;
		return Q;
	}

	/**
	 * Proved (exhaustive test) to be valid for 0 <= toAdd <= 245. Beginning from toAdd = 246, it'll fail. Never fails with all i (0->255), all hasCarry (representing value 256).
	 */
	public static char[] div10AndMod10(char i, boolean hasCarry, char toAdd) {
		char[] result = new char[2];

		char q = 0xFF;
		char r = i;
		int rr = r; // Not to be used on the real hardware
		do {
			// On the real hardware, use a call
			q = (char) (((char) (q + 1)) & 0xFF);
			rr = rr - 10;
			r = (char) (((char) (r - 10)) & 0xFF);
		} while (rr >= 0);
		r = (char) (((char) (r + 10)) & 0xFF);
		// On the real hardware, wait...

		// 'r' can contain values 0-9
		// 'q' can contain values 0-25 (255/10)

		if (hasCarry) {
			q = (char) (((char) (q + 25)) & 0xFF);
			r = (char) (((char) (r + 6)) & 0xFF); // 6 = 256%10 -> r <= 255
			if (r > 10) {
				q = (char) (((char) (q + 1)) & 0xFF);
				r = (char) (((char) (r - 10)) & 0xFF);
			}
			// On the real hardware, wait...
		} else {
			// On the real hardware, wait...
		}

		// If q==0, then q==255 after the following
		q = (char) (((char) (q - 1)) & 0xFF);
		r = (char) (((char) (r + toAdd)) & 0xFF); // Attention: 'toAdd' is not supposed to be >cY (=37)
		rr = r;
		do {
			q = (char) (((char) (q + 1)) & 0xFF);
			rr = rr - 10;
			r = (char) (((char) (r - 10)) & 0xFF);
		} while (rr >= 0);
		r = (char) (((char) (r + 10)) & 0xFF);
		// On the real hardware, wait...

		result[0] = q;
		result[1] = r;

		return result;
	}

	/*public static void div10(long i) {
		char q, r;
		
	    // approximate the quotient as q = i*0.00011001101 (binary)
	    q = ((i>>2) + i) >> 1; // times 0.101
	    q = ((q   ) + i) >> 1; // times 0.1101
	    q = ((q>>2) + i) >> 1; // times 0.1001101
	    q = ((q   ) + i) >> 4; // times 0.00011001101

	    // compute the reimainder as r = i - 10*q
	    r = ((q<<2) + q) << 1; // times 1010.
	    r = i - r;
	}*/

	/**
	 * @param countsPerSecond Counts per second
	 * @throws InterruptedException
	 */
	public static void impulseGenerator(float cPM) throws InterruptedException {
		float meanTime = (60.0f / cPM) * 1000.0f;
		System.out.println("Mean time: " + meanTime);
		while (run) {
			Thread.sleep((int) (meanTime + meanTime * (Math.random() - 0.5) * 0.9));

			//System.err.println("Emit");
			// Don't mind the synchronization
			count++;
		}
	}
}
