#if defined(HAVE_MAC_DIRS) || defined(__MWERKS__)
#include <LiDIA:rational_factorization.h>
#else
#include <LiDIA/rational_factorization.h>
#endif


void rational_factorization::
trialdiv(lidia_size_t index, unsigned int lower_bound, unsigned int upper_bound, ecm_primes &prim)
{
  bigint N(factors[index].single_base);
  int lexp = factors[index].single_exponent;
 
  rf_single_factor fact;
  
  lidia_size_t n = no_of_comp();
  long p, q;
  int count = 0;
  
  bigint TMP;
  
  if (info)  
  { 
    cout << "index " << index << ":   trialdivision up to " << upper_bound << "\n";
    cout.flush();
  }
  
  prim.resetprimes(lower_bound);
  
  if ( lower_bound < 2 )
  {
    while ( N.is_even() )
    {
      count++;
      N.divide_by_2();
    }
    
    if ( count )
    {
      fact.single_base = bigint(2);
      fact.single_exponent = count * lexp;
      fact.factor_state = prime;
      factors[n++] = fact;
      
      if (info) 
	if ( count > 1 ) cout << "factor: 2 ^ " << count << "\n";
	else             cout << "factor: 2 \n";
      
      count = 0;
    }
  }
  
  while ( ((p = prim.getprimes()) < upper_bound) && !N.is_one() && p != 1 )
  {
    div_rem(TMP, q, N, p);
    
    while ( !q )
    {
      N.assign(TMP);
      count++;
      div_rem(TMP, q, N, p);
    }
      
    if ( count )
    {   
      fact.single_base.assign(p);
      fact.single_exponent = count * lexp;
      fact.factor_state = prime;

      factors[n++] = fact;

      if (info) 
	if ( count > 1 ) cout << "factor: " << p << " ^ " << count << "\n";
	else             cout << "factor: " << p << " \n";
      
      count = 0;
    } 
  }
   
  if ( N.is_one() )
  {
    n--;
    factors[index] = factors[n];
    factors.remove_from(n);
  }
  else
  {
    fact.single_base.assign(N);
    fact.single_exponent = lexp;
    fact.factor_state = dont_know;
    
    factors[index] = fact;
  }  
}


void  rational_factorization::
trialdiv_comp(lidia_size_t index, unsigned int upper_bound, unsigned int lower_bound)
{ 
  if ( (index < 0) || (index >= no_of_comp()) )
    lidia_error_handler("rational_factorization", "trialdiv_comp::index out of range");

  if ( state(factors[index].factor_state) == prime )
  {
    if (info) 
      cout << "prime number " << factors[index].single_base << "\n";
    return;
  }
  
  if (lower_bound > upper_bound)
  { 
    lidia_warning_handler("rational_factorization", "trialdiv_comp::lower_bound > upper_bound");
    return;
  }
  
  ecm_primes prim(lower_bound, upper_bound+200, 200000);  
  
  trialdiv(index, lower_bound, upper_bound, prim);
  
  compose();
}


void  rational_factorization::
trialdiv(unsigned int upper_bound, unsigned int lower_bound)
{
  if (lower_bound > upper_bound)
  {
    lidia_warning_handler("rational_factorization", "trialdiv::lower_bound > upper_bound");
    return;
  }
  
  ecm_primes prim(lower_bound, upper_bound+200, 200000);
   
  lidia_size_t index, len = no_of_comp();
   
  for (index = 0; index < len; index++)
  {    
    if ( state(factors[index].factor_state) == prime )
    {
      if (info) 
	cout << "index " << index << " prime number " << factors[index].single_base << "\n";
    }
    else
      trialdiv(index, lower_bound, upper_bound, prim);
  }
  
  compose();
}


rational_factorization trialdiv(const bigint &N, unsigned int upper_bound, unsigned int lower_bound)
{
  rational_factorization f(N);
  
  f.trialdiv(upper_bound, lower_bound);

  return f;
}





