
//
// LiDIA - a library for computational number theory
//   Copyright (c) 1995 by the LiDIA Group
//
// File        : residue_class_list.h
// Author      : Oliver Morsch, Thomas Papanikolaou
// Last change : Aug 21 1995 (initial version)
//               Dec 07 1995, OM (bug fixing)
//		 Dec 07 1995, MM (bug fixing too)
//

#ifndef RESIDUE_CLASS_LIST_H
#define RESIDUE_CLASS_LIST_H  


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


template <class T> class residue_class
{
  private:
    
    T mod;                    // a bigmods residue_class
    unsigned int rfc;         // reference counter (how often is this class in use?)
    residue_class <T> * next; // pointer to the successor

  public:

    // *** constructors ***

    residue_class() { rfc = 1; };
    residue_class(const T & data) { mod = data; rfc = 1; };
    residue_class(const T & data, residue_class <T> * n) { mod = data; next = n; rfc = 1; };
    ~residue_class(){}

    // *** rfc handling ***

    unsigned int get_ref() const
    { return rfc; }

    unsigned int inc_ref()
    { rfc++; return rfc; }

    unsigned int dec_ref()
    { rfc--; return rfc; }

    // *** basic functions ***

    const T & get_mod() const
    {return mod;}

    T & get_mod()
    {return mod;}
    
    void set_mod(const T & e)
    {mod = e;}

    void set_succ(residue_class <T> *e)
    {next = e;}

    residue_class <T> *succ()
    {return next;}    
};


template <class T> class residue_class_list
{
  protected:
    
    residue_class <T> * head;

  public:

    //
    // *** constructor ***
    //

    residue_class_list() 
     {head = NULL;}

    
    //
    // *** destructor ***
    //

    ~residue_class_list() 
      {
	residue_class <T> *next;

        while (head != NULL)
	 {
	    next = head->succ();
	    delete head;
            head = next;
	 }
      }
	  

    //
    // *** basic functions ***
    //

    const residue_class <T> *first() const
      {return head;}

    residue_class <T> *first()
      {return head;}


    bool print(ostream & out = cout) const
    {
      // return value: false:  list is empty -> nothing to print
      //               true :  all list elements have been printed 

      if (head == NULL)
         return false;
      else
       {
	 residue_class<T> *e = head;

	 while (e != NULL)
	  {
	    out << "<" << e->get_mod() << ", " << e->get_ref() << ">";
	    e = e->succ();
	  }
	 out << "\n";
	 return true;
       }
    }


    residue_class <T> *insert(const T & data)
    {
      //
      // searches for an existing residue_class with mod = data
      //

      residue_class <T> *e = head;

      while (e != NULL)
      {
	// found ?
	if (e->get_mod() == data)
	 {
	   e->inc_ref();
	   return e;
	 }
	else
	   e = e->succ();
      }

      //
      // residue_class does not exist yet => create it
      //

      e = new residue_class<T>(data, head);
      head = e;
      return e;
    }


    residue_class <T> *set_to(residue_class <T> * a)
     {
       // WARNING: For efficiency reasons, the user has to take
       // the responsibility, that the pointer a really points to
       // an element of the list *this.

       a->inc_ref();
       return a;
     }


    int clear(residue_class <T> * elmnt)
     {

       // return value: 0  the residue_class to be deleted doesnt exist
       //               1  the rfc of the residue_class to be deleted is decreased
       //		2  the residue_class is deleted

       // WARNING: To avoid side effects, elmnt must point
       // to an element of the list *this or should be NULL, because,
       // if the rfc of elmnt is greater than one, the
       // rfc is decreased. In this case, it is not verified,
       // whether elmnt points to an elemnt of the list.

       int rc;

       if (head == NULL || elmnt == NULL)
          rc = 0;
       else
        {
          //
          // just decrease the ref. counter
          //

          if (elmnt->get_ref() > 1)
           {
             elmnt->dec_ref();
             rc = 1;
           }

          //
          // otherwise, remove the element from the list
          //

          else
           {
              residue_class < T > *e, *pred;
              rc = 2;

              //	
              // elmnt is the head of the list
              //

              if (elmnt == head)
               {
                 e = head->succ();
                 delete head;
                 head = e;
               }

              //
              // search for the predecessor of elmnt in the list
              //

              else
               {
                 pred = head;
                 e    = head->succ();

                 while (e != elmnt && e != NULL)
                  {
                    pred = e;
                    e = e->succ();
                  }

                  // found ?

                  if (e == elmnt)
                   {
                     pred->set_succ(e->succ());
                     delete e;
                   }
                  else
                     rc = 0;
               }
            }
         }

      return (rc);
    }
};

#endif  
