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

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

main(lidia_size_t argc, char **argv)
{
    cout << "This program computes the factorization of a polynomial over\n";
    cout << "a finite prime field using an algorithm of Shoup and v.z.Gathen.\n";
    cout << "Options :\n";
    cout << " -v   print additional information (such as timinigs)\n";
    cout << " -cn  set poly_arg_bound to n\n";
    cout << "      poly_arg_bound controls space allocation for tables that\n";
    cout << "      are used in various routines.\n";
    cout << "      If n > 0, space is only allocated for about n numbers mod p.\n";
    cout << "      If n <= 0, space is allocated as to maximize speed.\n";
    cout << " -bm  set DDF_GCD_BLOCKING_FACTOR to m\n";
    cout << "      In the DDF routine, gcds are computed in blocks of this size.\n\n";

    lidia_size_t verbose = 0;

    argc--;
    argv++;
    single_factor < Fp_polynomial >::set_verbose_mode(0);

    while (argc > 0)
    {
	if (strcmp(argv[0], "-v") == 0)
	{
	    verbose = 1;
	    single_factor < Fp_polynomial >::set_verbose_mode(1);
	}
	else if (argv[0][0] == '-' && argv[0][1] == 'c')
		poly_argument::set_poly_arg_bound(atoi(argv[0] + 2));
		//see Fp_polynomial_util.h, class poly_argument
	else if (argv[0][0] == '-' && argv[0][1] == 'b')
		DDF_GCD_BLOCKING_FACTOR = atoi(argv[0]+2);
		//see DDF.c
	else
	{
	    cerr << "unknown option: " << argv[0] << "\n";
	    return 1;
	}

	argc--;
	argv++;
    }

    cout << "Please enter a monic polynomial (example: x^54 - 3*x^2 + 1 mod 5) :\n";
    Fp_polynomial f;
    cin >> f;
    const bigint & p = f.modulus();

    if (verbose)
    {
	cerr << "can_zass:  degree of polynomial = " << f.degree()
	     << ", bitlength of modulus = " << p.bit_length()
	     <<",\n poly_arg_bound = " << poly_argument::get_poly_arg_bound()
	     << ", gcd blocking = " << DDF_GCD_BLOCKING_FACTOR
	     << "\n";
    }

    factorization < Fp_polynomial > factors;

    my_timer t;
    t.start("total time: ");

    can_zass(factors, f);

    if (verbose) t.stop();

    cout << "factorization :\n";
    cout << factors << "\n";

    Fp_polynomial ff;

    ff = factors.value();
    if (f != ff)
    {
	cerr << "Incorrect factorization!!\n";
	cout << "Product of factors :";
	cout << ff << endl;
	cout << "should be :" << endl;
	cout << f << endl;
    }
}
