//
// LiDIA - a library for computational number theory
//   Copyright (c) 1994, 1995 by the LiDIA Group
//


#ifndef LIDIA_SINGLE_FACTOR__H
#define LIDIA_SINGLE_FACTOR__H


template< class T > class single_factor;

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


template< class T > class base_factor;
template< class T > class factorization;



/****************************************************************
                   class single_factor<T>
****************************************************************/



template< class T >
class single_factor : public base_factor< T >
{
/****************************************************************************

  This is the default implementation for the class single_factor.
  This code is used if there is no special instantiation for type T.
  
  There exist special instantiations for type T = {bigint, Fp_polynomial, ideal}
  	single_factor< bigint >
	single_factor< Fp_polynomial >
	single_factor< ideal >

  If you want to add another special instantiation (not the default one),
  compare example below (Fp_polynomial, gf_polynomial, bigint)

****************************************************************************/


    friend class factorization< T >;

 private:
//additional information should be defined here



 public:
	/**
	** constructors, destructor
	**/
    single_factor();
		//default value must be '1' (the neutral element of multiplication)
    single_factor(const single_factor< T > &);
		//copy constructor
    single_factor(const T&);
		//conversion for type T
    ~single_factor();



	/**
	** swap
	**/
	
 private :
    void swap(single_factor< T > &b);
 public :
    inline 
    friend void swap(single_factor< T > & a, single_factor< T > & b)
    { a.swap(b); }
   

	/**
	** assignment
	**/
    single_factor< T > & operator= ( const single_factor< T > & x);
    const T & operator= ( const T & x);
#ifndef HEADBANGER
    void assign(const single_factor< T > & x);
    void assign(const T & x);
#endif		//HEADBANGER

	/**
	** queries
	**/
	
    bool is_one() const;
    
    inline 
    bool is_prime_factor() const
    { return (prime_flag() == decomposable_object::prime); }

    bool is_prime_factor(int test);
	//test==0 -> no explicit primality test (only a flag is checked)
	//test!=0 -> explicit prime-test if prime_state()==unknown
	//see manual

    T extract_unit();
    friend lidia_size_t ord_divide(const single_factor< T > &a,
	    single_factor< T > &b);


	/**
	** factorization algorithms
	**/

    factorization< T > factor() const;	
   		// standard factorization algorithm, used in function 
   		// "factorization< T >::factor_all_components"
		
    friend factorization< T > factor(const single_factor< T > & f);
   		// "do not implement function body in .h-file"
		// "otherwise, it will confuse the CC-compiler"


};







#if defined(HAVE_MAC_DIRS) || defined(__MWERKS__)

#include <LiDIA:sf_Fp_polynomial.h>
#include <LiDIA:sf_gf_polynomial.h>
//#include <LiDIA:sf_bigint.h>

#ifndef __GNUG__
#include <LiDIA:sort_vector.h>
#include <LiDIA:ppair.h>
//typedef sort_vector< ppair< single_factor< bigint >,lidia_size_t > > dummy1;
typedef sort_vector< ppair< single_factor< Fp_polynomial >,lidia_size_t > > dummy2;
typedef sort_vector< ppair< single_factor< gf_polynomial >,lidia_size_t > > dummy3;
#endif


#else


#include <LiDIA/sf_Fp_polynomial.h>
#include <LiDIA/sf_gf_polynomial.h>
//#include <LiDIA/sf_bigint.h>

#ifndef __GNUG__
#include <LiDIA/sort_vector.h>
#include <LiDIA/ppair.h>
//typedef sort_vector< ppair< single_factor< bigint >,lidia_size_t > > dummy1;
typedef sort_vector< ppair< single_factor< Fp_polynomial >,lidia_size_t > > dummy2;
typedef sort_vector< ppair< single_factor< gf_polynomial >,lidia_size_t > > dummy3;
#endif


#endif

#ifdef LIDIA_INCLUDE_C
#include <LiDIA/single_factor.c>
#endif

#endif
