//
// LiDIA - a library for computational number theory
//   Copyright (c) 1996 by the LiDIA Group
//
// File        : gf_element.h
// Author      : Detlef Anton (DA), Thomas Pfahler (TPf)
// Last change : DA, Jan 17 1996, initial version
//               TPf, Jul 1 1996, some min. changes 
//

#ifndef LIDIA_GF_ELEMENT__H
#define LIDIA_GF_ELEMENT__H

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

class gf_p_element;

template <class T > class gf_element
{
  /**
  ** the C++ type we use to represent functions 
  ** of an Element of a Galois field
  **/

#ifndef __GNUG__
public:
#endif

  gf_element(){};

#ifdef __GNUG__
  friend class gf_p_element;
#endif

  friend void add      (gf_p_element & c, const gf_p_element & a, const gf_p_element & b);
  friend void add      (gf_p_element & c, const multi_bigmod & a, const gf_p_element & b);
  friend void add      (gf_p_element & c, const gf_p_element & a, const multi_bigmod & b);
  friend void subtract (gf_p_element & c, const gf_p_element & a, const gf_p_element & b);
  friend void subtract (gf_p_element & c, const multi_bigmod & a, const gf_p_element & b);
  friend void subtract (gf_p_element & c, const gf_p_element & a, const multi_bigmod & b);
  friend void multiply (gf_p_element & c, const gf_p_element & a, const gf_p_element & b);
  friend void multiply (gf_p_element & c, const multi_bigmod & a, const gf_p_element & b);
  friend void multiply (gf_p_element & c, const gf_p_element & a, const multi_bigmod & b);
  friend void divide   (gf_p_element & c, const gf_p_element & a, const multi_bigmod & b);
  friend bool operator == (const gf_p_element & a, const gf_p_element & b);
  friend void swap     (gf_p_element & a, gf_p_element & b);


  friend class gf_n_element;

  friend void add      (gf_n_element & c, const gf_n_element & a, const gf_n_element & b);
  friend void add      (gf_n_element & c, const multi_bigmod & a, const gf_n_element & b);
  friend void add      (gf_n_element & c, const gf_n_element & a, const multi_bigmod & b);
  friend void subtract (gf_n_element & c, const gf_n_element & a, const gf_n_element & b);
  friend void subtract (gf_n_element & c, const multi_bigmod & a, const gf_n_element & b);
  friend void subtract (gf_n_element & c, const gf_n_element & a, const multi_bigmod & b);
  friend void multiply (gf_n_element & c, const gf_n_element & a, const gf_n_element & b);
  friend void multiply (gf_n_element & c, const multi_bigmod & a, const gf_n_element & b);
  friend void multiply (gf_n_element & c, const gf_n_element & a, const multi_bigmod & b);
  friend void divide   (gf_n_element & c, const gf_n_element & a, const multi_bigmod & b);
  friend void pth_power(gf_n_element & c, const gf_n_element & a, lidia_size_t e);
  friend bool operator == (const gf_n_element & a, const gf_n_element & b);
  friend void swap     (gf_n_element & a, gf_n_element & b);
  friend void transform_n_to_p(gf_p_element & a, const gf_n_element & b);
  friend void transform_p_to_n(gf_n_element & a, const gf_p_element & b);

  public:

    /**
    ** base functions
    **/


    /**
    ** high level functions
    **/
   const bigint element_order(const T & elem)                const;
   const T      element_norm(const T & elem)                 const;
         bool   element_is_primitive_element(const T & elem) const;
         bool   element_is_free_element(const T & elem)      const;
  friend void   element_power(T & c, const T & a, const bigint & e);

    /**
    ** input / output - functions
    **/
};

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

#endif
