// Solve the congruence x^2 = n (mod p).
void tonelli_shanks(uint32_t n, uint32_t p, uint32_t *result) {
	if(p == 2) {
		result[0] = n;
		result[1] = n;
		return;
	}

	uint64_t S = 0;
	uint64_t Q = p - 1;

	while(Q % 2 == 0) {
		Q /= 2;
		++S;
	}

	uint64_t z = 2;

	while(legendre_symbol(z, p) != -1)
		++z;

	uint64_t c = pow_mod(z, Q, p);
	uint64_t R = pow_mod(n, (Q + 1) / 2, p);
	uint64_t t = pow_mod(n, Q, p);
	uint64_t M = S;

	while(t % p != 1) {
		int32_t i = 1;
		while(pow_mod(t, pow(2, i), p) != 1)
			++i;
	
		uint64_t b = pow_mod(c,  pow(2, M - i - 1), p);
		R = R * b % p;
		t = t * b * b % p;
		c = b * b % p;
		M = i;
	}

	result[0] = R;
	result[1] = p - R;
}
int main(int argc, char *argv[])
{
	const int stage=atoi(argv[1]);  
	long down=(long)(stage-1)*1000000; long up=(long)stage*1000000; // blocksize = 1000000 (1 million)
	printf("Primes %ld-%ld\n",down,up);
	
	clock_t begin,end;
	double times;
	begin=clock();

	// This is the list of discriminants we want to find counterexamples for
	long D_list[10]={1073741783,4294967291,8589934583,17179869143,34359738319,68719476731,137438953447,274877906899,549755813723,1099511627563};
	int h_list[10]={22991,34805,107849,136023,86757,98601,162855,114227,220527,176451};
	
	// The upper bound of these discriminants is D_max
	long D_max=pow(2,40), D, p;
	// The upper bound of class numbers for these discriminants is h_max
	int h_max = h_upper_bound(-D_max);

	int temp=1, h, order; 
	int *factors_of_h=NULL; factors_of_h = (int *) realloc(factors_of_h, 17* sizeof(int));
	char aac_file[100]; 

	// Use prime sieve to find all primes less than D_root, D_root>sqrt(up)
	int* primes; 
	long D_root=10000000;
	primes = (int *) malloc(((int) (1.25506 * D_root / log(D_root))) * sizeof(int));
	prime_sieve(D_root, primes);
	primes = (int *) realloc(primes, (2 + primes[0]) * sizeof(int));
	
	for(int count=0;count<10;count++)
	{  
		D=D_list[count];
		h=h_list[count];
		// Save the counterexamples in the file ./AAC/D/D_stage
		sprintf(aac_file,"./AAC/%ld/%ld_%d",D,D,stage);
		FILE* wf=fopen(aac_file,"w");

		for(p=down+1;;p++)
		{
			if(p>up)
				break;
			if(isprime(p,primes)==1)
			{	
				if(legendre_symbol(-D,p)==1)
				{  
					if(h==1)
						order=1;
					else
					{ 	
						temp=h;int count=1; factors_of_h[0]=0;  
						for(int s=1;primes[s]<=h_max;s++)
						{    
							if(temp%primes[s]==0)
							{ 
								factors_of_h[count]=primes[s]; count++;  
								factors_of_h[0]=factors_of_h[0]+1;
								while(temp%primes[s]==0)
									temp=temp/primes[s]; 
							}
							if(temp<=1)
								break;
						}
						order=order_mpz(D,p,h,factors_of_h);
					}		
					aac(D,p,order,wf);
				}
			}
		} // run out the primes
		fclose(wf); 
	} // count loop ends
	free(factors_of_h);

	free(primes);

	end=clock();
	times=(double)(end-begin)/CLOCKS_PER_SEC;
	printf("stage %d:%lf seconds\n",stage,times); 

	return 0;
}