//
// LiDIA - a library for computational number theory
//   Copyright (c) 1994, 1995 by the LiDIA Group
//
// File        : is_prime.c 
// Author      : Andreas M"uller (AM)
// Last change : AM, Feb 7 1995, initial version
//               TP, Feb 7 1995, change b = 10 to b = 9
//               VM, Apr 20 1995, check whether a1 is even
//

#include <LiDIA/bigint.h>

bool is_prime(const bigint &a1, const int b1)
{
   static long a[10] = {3, 5, 7, 11, 13, 17, 19, 23, 29, 31};
   long b, j, ok, i, k = 0, sx;

   if (!a1.longify(sx))   // can not be converted to long
     {
     if (sx <= 0)
       return 0;
     
     if (sx == 2)
       return 1;

     if (sx <= 31)
       {
	 for (i=0; i<10; i++)
	   if (sx == a[i])
	     return 1;
	 
	 return 0;
       }
   }
   
   if ( a1.is_le_zero() || a1.is_even() )
     return 0;

   if ( b1 <= 0 )
     lidia_error_handler("is_prime", "#tests <= 0");
   
   if ( b1 > 9 )
     b = 9;
   else 
     b = b1;
   
   bigint erg;
   bigint H(37), Q(a1);
   dec(Q);

   bigint N_minus1(Q);

   while ( Q.is_even() )
   {
      Q.divide_by_2();
      k++;
   }

   for (i = 0; i <= b; i++)         
   {
      power_mod(erg, bigint(a[i]), Q, a1);
      
      if ( !erg.is_one() && erg.compare(N_minus1) )
      {
	 j = k;
	 ok = 0;
	 
	 while( (j > 0) && !ok )
         {
	    square(erg, erg);
	    remainder(erg, erg, a1);
	    
	    if ( !erg.compare(N_minus1) ) ok = 1;

	    j--;
	 }

	 if ( !ok ) 
         {
	    return (0);
         } 
      }
   }
   
   for (; i <= b1; i++)         
   {
      if ( !a1.compare(H) )
	return 1;

      power_mod(erg, H, Q, a1);
      
      if ( !erg.is_one() && erg.compare(N_minus1) )
      {
	 j = k;
	 ok = 0;
	 
	 while( (j > 0) && !ok )
         {
	    square(erg, erg);
	    remainder(erg, erg, a1);
	    
	    if ( !erg.compare(N_minus1) ) ok = 1;

	    j--;
	 }

	 if ( !ok ) 
         {
	    return (0);
         } 
      }
      
      H = next_prime(H);
   }
   
   return(1);
}
