//
// LiDIA - a library for computational number theory
//   Copyright (c) 1994, 1995 by the LiDIA Group
//
// File        : 
// Author      : Victor Shoup, Thomas Pfahler (TPf)
// Last change : TPf, Feb 29, 1996, initial version
//



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


void factor(factorization< gf_polynomial > &F, const gf_polynomial &f)
{
    const bigint &q = f.base().field().number_of_elements();
    const lidia_size_t k = f.base().field().degree();
    lidia_size_t n = f.degree(), i, j;
    if (n < 0)
	lidia_error_handler("gf_polynomial", "factor(...)::input is zero polynomial");
    
    if (k == 1)
    {
	Fp_polynomial ff;
	ff.set_modulus(q);
	for (i = n ; i >=0; i--)
	    ff[i].assign(f[i].polynomial_rep()[0]);
	
	gf_polynomial tmp(f.base());
	factorization< Fp_polynomial > Fact = factor(ff);
	F.kill();
	tmp.set_degree(0);
	tmp[0].set_polynomial(Fact.unit());
	F.append(tmp);
	
	for (j = 0; j < Fact.no_of_prime_components(); j++)
	{
	    tmp.set_degree(Fact.prime_base(j).base().degree());
	    for (i = Fact.prime_base(j).base().degree(); i >= 0; i--)
	    {
		ff.assign(Fact.prime_base(j).base()[i]);
		tmp[i].set_polynomial(ff);
	    }
	    F.append(tmp, Fact.prime_exponent(j));
	}
	return;
    }
    if (q.bit_length() * n > 100000 || q < 50)
	can_zass(F, f);
    else
	berlekamp(F, f);
}

factorization< gf_polynomial >
single_factor< gf_polynomial >::factor() const
{
    return ::factor(rep);
}
