//
// LiDIA - a library for computational number theory
//   Copyright (c) 1996 by the LiDIA Group
//
// File        : order_mod.c
// Author      : Thomas Pfahler
// Last change : TPf, July 4 1996, initial version
//


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



bigint
order_mod(const bigint &aa, const bigint &p, int verbose=0)
//returns multiplicative order of a in Z/pZ, p must be prime and positive
{ 
    bigint a(aa);
    if (a.is_negative() || a >= p)
	remainder(a, a, p);

    if (a.is_zero()) return (bigint)0;
    if (a.is_one())  return (bigint)1;
	
    bigint m(p);
    dec(m);		//m = p-1
    
    rational_factorization f(m);
    timer t;
    
    if (verbose)  { t.start_timer(); }
    f.factor();
    if (verbose)
    { t.stop_timer(); cerr<<"order, factoring : "; t.print(); cerr<<endl; }
    
    if (!f.is_prime_factorization())
    {
	lidia_error_handler("...","order_mod(bigint&, bigint&)::could not factor p-1");
    }

    bigint p_i, pow;
    lidia_size_t i, e_i, end = f.no_of_comp();
    for (i = 0; i < end; i++)
    { 
	p_i = f.base(i);
	e_i = f.exponent(i);
	power_mod(pow, a, (m/p_i), p);
	while ( (e_i > 0) && (pow.is_one()) ) 
	{ 
	    m=m/p_i;
	    e_i--;
	    power_mod(pow, a, (m/p_i), p);
	}
    }
    return m;
}

