//
// LiDIA - a library for computational number theory
//   Copyright (c) 1994, 1995 by the LiDIA Group
//
// File        : fpc.c 
// Author      : Damian Weber (DW)
// Last change : TP, Aug 8 1995, initial version
//

#include <LiDIA/dlp.h>

void help()
{

  cout << "\n" << "usage: fpc <prime>" << "\n" << "\n";
  cout << "\n" << "Functions in Fp" << "\n" << "\n";
  cout << "a+b" << "\n";
  cout << "a-b" << "\n";
  cout << "a*b" << "\n";
  cout << "a/b" << "\n";
  cout << "a^b" << "\n";
  cout << "\n";
}

int  main(int argc,char **argv)
{
  const int LENGTH=5000;
  bigint p,a,b,y;
  bigint inv_b;
  char   *op,opc,string[LENGTH];
  char   *prompt="fpc>";

  int    check1,check2,count;

  if (argc>1)
    string_to_bigint(argv[1],p);
  else
    {
      help();
      return (0);
    }

  if (!is_prime(p, 6)) 
    {
      cerr << "fpc: " << p << " is not a prime number " << "\n";
      return(1);
    }

  cout << "Computing in F" << p << " ..." << "\n" << "\n";

  count=0;
  y=0;

  while(1)
    {
      cout << prompt;
      cin.getline(string,LENGTH);

      if (string[0]=='q')
	break;

      if (string[0]=='h')
	{
	  help();
	  continue;
	}

      op=strpbrk(string,"+-*/^");

      if (op==0)
	{
	  cerr << "no operand found (op='+-*/^')" << "\n";
	  continue;
	}
     
      opc=*op;

      *op=0;

      check1=1;
      if (string[0]=='&') a=y;
      else 
	check1=string_to_bigint(string,a);

      check2=1;
      if (op[1]=='&') b=y;
      else
	check2=string_to_bigint(op+1,b);

      if (check1==0) 
	{
	  cerr << "operand 1 not numeric" << "\n";
	  continue;
	}

      if (check2==0) 
	{
	  cerr << "operand 2 not numeric" << "\n";
	  continue;
	}
     
      if (a.is_lt_zero())
	{
	  a%=p;
	  a+=p;
        }

      if (b.is_lt_zero())
	{
	  if (opc=='^')
	    {
	      b%=(p-bigint(1));
	      b+=(p-bigint(1));
	    }
	  else
	    {
	      b%=p;
	      b+=p;
	    }
	}

      switch (opc)
	{
	case '^': power_mod(y,a,b,p);
	  break;
	case '+': y=(a+b) % p;
	  break;
	case '-': y=(a-b) % p;
	  break;
	case '*': y=(a*b) % p;
	  break;
	case '/': power_mod(inv_b,b,p-bigint(2),p); 
	  y=(a*inv_b) % p;
	}

      cout << "out(" << ++count << ") = " << y << "\n";
    }

}

