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

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



 
// ---------------------- PRIVATE ----------------------------

mcp::item* mcp::head = 0;
bigint mcp::ZERO = 0;

void mcp::delete_from_list(item* p)
{
//assumption: p != 0  &&  p->reference_counter == 0 
	debug_handler_c( "mcp", "delete_from_list( item* )", 1, cout<<"deleted "<<p->M<<endl; );

  	if (head == 0)
	  	lidia_error_handler( "mcp", "delete_from_list::list is empty" );
  	if (p == head)
	  	head = head->next;
	else
	{
	  	item* tmp = head;	//head!=0
	
  		while (tmp->next != p && tmp->next != 0)
	  		tmp = tmp->next;
		if (tmp->next == 0)
		  	lidia_error_handler( "mcp", "delete_from_list::item not found" );
		//now, tmp->next == p
		tmp->next = p->next;	//=temp->next->next;
	}
	delete p;
}

mcp::item* mcp::insert_into_list(const bigint& B)
{
//B should not be in the list yet
	debug_handler_c( "mcp", "insert_into_list( bigint& )", 1, cout<<"inserted "<<B<<endl; ); 
	item* tmp = new item;
	tmp->M.assign(B);
	tmp->next = head;
	tmp->reference_counter = 1;
	head = tmp;		//insert at the beginning
	return tmp;
}


void mcp::del(item* p)
{
  	if (p!=0)
	{
  		p->reference_counter--;
		if (p->reference_counter == 0)
				delete_from_list(p);
	}
}

void mcp::assign(const mcp& a)
{
#if 0
	if (a.ptr == 0)
	  	lidia_error_handler( "mcp", "assign( mcp& )::argument is zero" );
#endif
  	if (ptr != a.ptr)
	{
		del(ptr);
  		ptr = a.ptr;
		ptr->reference_counter++;
	}

}



// ---------------------- PUBLIC ----------------------------

mcp::mcp()
{
  	ptr = 0;
}
	
mcp::mcp(const mcp& a)
{
  	ptr = a.ptr;
	ptr->reference_counter++;
}


mcp::~mcp()
{
  	del(ptr);
}

void mcp::set(const bigint& B)
{
  	if (ptr != 0  ?  ptr->M == B  :  0)
	  	return;
  	del(ptr);
	item* tmp = head;
	while (tmp != 0  ?  tmp->M != B  :  0)
		tmp = tmp->next;
	if (tmp == 0)
  		ptr = insert_into_list(B);
	else
	{
	  	ptr = tmp;
		ptr->reference_counter++;
	}
}


void swap(mcp& x, mcp& y)
{
	mcp::item* tmp = x.ptr;
	x.ptr = y.ptr;
	y.ptr = tmp;
}

const bigint& mcp::mod() const
{
  	if (ptr != 0)
	  	return ptr->M;

	//lidia_error_handler( "mcp", "mod( void )::has no value yet" );
	return ZERO;
}

void mcp::statistics()
{
  	mcp::item* tmp = head;
	cout<<"mcp - INFO ...........................................\n";
	while (tmp != 0)
	{
	  	cout<<"  "<<tmp->reference_counter<<" references to ( "<<tmp->M<<" )\n";
		tmp = tmp->next;
	}
	cout<<endl;
}

