#if defined(HAVE_MAC_DIRS) || defined(__MWERKS__)
#include <LiDIA:bigint.h>
#include <LiDIA:arith.inl>
#include <LiDIA:lidia_vector.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#else
#include <LiDIA/bigint.h>
#include <LiDIA/arith.inl>
#include <LiDIA/lidia_vector.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#endif

// Compile with option -DEXP_MODE to  create
// example application for expanding vectors


#ifdef  EXP_MODE
#define MODE EXPAND

#else
#define MODE FIXED

#endif


/** 
 ** Building lidia_vectors of type 'elem_type'
 **/


int 
less_than(const elem_type & a, const elem_type & b) 
{
  if ( a <  b ) return -1 ;
  if ( a == b ) return  0 ;
  if ( a >  b ) return  1 ;
}

int 
greater_than ( const elem_type & a , const elem_type & b ) 
{
  if ( a >  b ) return -1 ;
  if ( a == b ) return  0 ;
  if ( a <  b ) return  1 ;
}


main ()
{
  int i   ;
  
  int test, rc, pos ;

  char *fname ;
  FILE *fp    ;
      
  elem_type el, tmp ;

  lidia_vector <elem_type> a( 0, MODE ) ;

  test = 0 ;



  // ***** input, output, and operator[] *****

    cout << "\n Please enter (" << MODE << ") vector with non-zero entries : " ;
  cin  >>  a ;
  

  lidia_vector <elem_type> b( 0, EXPAND ) ;

  cout << "\n\n Enter entries of another vector with non-zero entries : \n" ;

  for ( i = 0 ; i < a.size() ; i++ )
       {
	 cout << " " << i << " : " ;
	  cin  >> b[i]  ;
       }
  
  
  elem_type *x = new elem_type [ b.size() + 1 ] ;
  
  for ( i = 0 ; i < b.size() ; i++ )
    {
      x[i] = b[i] ; 
    }
  
  
  cout << "\n if this is your second input vector : [ " ;

  for ( i = 0 ; i < b.size() ; i++ )
    {
      cout << x[i] << " " ;
    }
  
  cout << "],\n then operator[] is ok.\n\n" << flush ;
  
      
  
  lidia_vector <elem_type> c( a , MODE ) ;
  lidia_vector <elem_type> d( x , b.size() , MODE ) ;
  
  cout << "\n This is your first input  : " << a ;
  cout << "\n and a copy of it          : " << c ;
  cout << "\n This is your second input : " << b ;
  cout << "\n and a copy of it          : " << d ;
  
  cout << "\n\n ------------------------- \n\n" ;
  
  
  

      // ***** changing size and capacity *****

      cout << " Changing the size of a vector : \n\n" ;
      cout << " original       : " << " size = " << a.size() << " : cap. = " << a.capacity() << " : " << a << "\n" ;
      
      a.set_size ( a.size() / 2 ) ;

      cout << " halfsized      : " << " size = " << a.size() << " : cap. = " << a.capacity() << " : " << a <<  "\n" ;

      a.set_capacity ( a.capacity() * 2 ) ;

      cout << " double space   : " << " size = " << a.size() << " : cap. = " << a.capacity() << " : " << a <<  "\n" ;

      a.set_size ( a.size() * 2 ) ;

      cout << " size reset     : " << " size = " << a.size() << " : cap. = " << a.capacity() << " : " << a <<  "\n" ;

      a.kill ( ) ;

      cout << " delete vector  : " << " size = " << a.size() << " : cap. = " << a.capacity() << " : " << a <<  "\n" ;

      a = c ;

      cout << " and recover it : " << " size = " << a.size() << " : cap. = " << a.capacity() << " : " << a <<  "\n" ;

      cout << " \n Please check all the results.\n" ;

      cout << "\n ------------------------- \n\n" ;


 

      // ***** == and != *****

      cout << " operator== and operator!= ... \n\n" << flush ;

      if ( !(a == c) )
       {
         cout << " ERROR : operator== failed  <----- \n" << flush ;
	 test++ ;
       }


      a[0] = b[0] + (elem_type) 1 ;

      if ( !(a != b) )
       {
         cout << " ERROR : operator!= failed   <------ \n" << flush ;
	 test++ ;
       }


 

      cout << " arithmetical operations ... \n\n" ;

      lidia_vector<elem_type> z1 ( 0, MODE ) ;
      lidia_vector<elem_type> z2 ( 0, MODE ) ;
      lidia_vector<elem_type> z3 ( 0, MODE ) ;

  
      // *****  ADDITION AND SUBTRACTION  *****

      a = c ;

      z1 = a  +  b ;
      z2 = z1 -  a ;

      if ( z2 != b ) 
       {
	 cout << " ERROR : operator+  or operator- failed     <----- \n" << flush ;
	 test ++ ;
       }


      z1 = a  +  (elem_type) 10 ;
      z2 = z1 -  (elem_type) 10 ;

      if ( z2 != a ) 
       {
	 cout << " ERROR : operator+  or operator- failed  (scalar)   <----- \n" << flush ;
	 test ++ ;
       }


      z1 = -a ;
      z2 = b - a  ;
      z3 = b + z1 ;

      if ( !(z2 == z3) )
       {
         cout << " ERROR :  operator- (unary) failed   <----- \n" << flush ;
	 test++ ;
       }


      add      ( z1 , a  , b ) ;
      subtract ( z2 , z1 , a ) ;

      if ( z2 != b ) 
       {
	 cout << " ERROR : addition or subtraction failed     <----- \n" << flush ;
	 test ++ ;
       }



      add      ( z1 , a  , (elem_type) 10 ) ;
      subtract ( z2 , z1 , (elem_type) 10 ) ;

      if ( z2 != a ) 
       {
	 cout << " ERROR : addition or subtraction failed  (scalar)   <----- \n" << flush ;
	 test ++ ;
       }


      negate   ( z1 , a ) ;
      subtract ( z2 , b , a ) ;
      add      ( z3 , b , z1 ) ;

      if ( !(z2 == z3) )
       {
         cout << " ERROR :  negate failed   <----- \n" << flush ;	 
	 test++ ;
       }



      // *****  MULTIPLICATION AND DIVISION  *****


      compwise_multiply(z1,a,b) ;
      compwise_divide(z2,z1,a);

      if ( z2 != b ) 
       {
	 cout << " ERROR : operator*  or operator/ failed     <----- \n" << flush ;
	 test ++ ;
       }


      z1 = a  *  (elem_type) 10 ;
      z2 = z1 /  (elem_type) 10 ;

      if ( z2 != a ) 
       {
	 cout << " ERROR : operator*  or operator/ failed  (scalar)   <----- \n" << flush ;
	 test ++ ;
       }



      compwise_multiply ( z1 , a  , b ) ;
      compwise_divide   ( z2 , z1 , a ) ;

      if ( z2 != b ) 
       {
	 cout << " ERROR : multiplication or division failed     <----- \n" << flush ;
	 test ++ ;
       }


      multiply ( z1 , a  , (elem_type) 10 ) ;
      divide   ( z2 , z1 , (elem_type) 10 ) ;

      if ( z2 != a ) 
       {
	 cout << " ERROR : multiplication or division failed (scalar)    <----- \n" << flush ;
	 test ++ ;
       }

      

      // *****  SUM OF SQUARES / INNER PRODUCT  *****

      i = 20 ;

      z3.set_capacity ( i ) ;
      z3[0] = (elem_type) 1 ;

      for ( i = 1 ; i < z3.capacity() ; i++ )
      
         z3[i] = z3[i-1] + (elem_type) 1 ;  // z3[i] == i+1 


      tmp = ( i * ( i + i + 1 ) * ( i + 1 ) ) / 6 ;

      z2 = -z3 ;


      if ( tmp != sum_of_squares(z3) )
       {
	 cout << " ERROR : sum_of_squares failed   <----- \n" << flush ;
	 test++ ;
       }

      tmp = -tmp ;


      if ( tmp != z2 * z3 )
       {
         cout << " ERROR : operator* failed   <----- \n" << flush ;
         test++ ;
       }



      // *****  SORTING AND SEARCHING  *****


      cout << " sorting and searching ... \n\n" ;

      z1 = a ;
      z2 = b ;

      z1.sort ( SORT_VECTOR_UP ) ;
      z2.sort ( SORT_VECTOR_DOWN , 0 , z2.size() / 2 ) ;

      z3 = z2 ;
      z3.set_size ( ( z2.size() / 2 ) + 1 ) ;

      cout << " First input in ascending order                 : " << z1 << endl ;
      cout << " First part of second input in descending order : " << z3 << endl ;

      cout << "\n Please check whether the vectors are sorted correctly.\n\n" ;



      z2.sort ( 0 , z2.size()-1 ) ;

      cout << " linear search ... " << endl ;

      tmp = sum_of_squares (z1) ;
      el  = z1[ z1.size()-1 ] ;
      rc  = z1.linear_search ( el , pos ) ;

      if ( ! rc )
       {
	 cout << " ERROR : linear search failed (" << el << " not found) <----- \n" << endl ;
         test++ ;
       }


      el = tmp + (elem_type) 1 ;      
      rc = z1.linear_search ( el , pos ) ;

      if ( rc )
       {
	 cout << " ERROR : linear search failed (non existing element " << el << " found) <----- \n"  << endl ;
         test++ ;
       }



      cout << " binary search ... \n" << endl ;

      el = z1[ z1.size()-1 ] ;
      rc = z1.bin_search ( el , pos ) ;

      if ( ! rc )
       {
	 cout << " ERROR : binary (up) search failed (" << el << " not found) <----- \n"  << endl ;
         test++ ;
       }


      el = tmp + (elem_type) 1 ;      
      rc = z1.bin_search ( el , pos ) ;

      if ( rc  )
       {
	 cout << " ERROR : binary (up) search failed (non existing element " ;
	 cout << el << " found) <----- \n"  << endl ;
         test++ ;
       }


      z1.sort ( SORT_VECTOR_DOWN ) ;

      el = z1[ z1.size()-1 ] ;
      rc = z1.bin_search ( el , pos,  SORT_VECTOR_DOWN ) ;

      if ( ! rc  )
       {
	 cout << " ERROR : binary (down) search failed (" << el << " not found) <----- \n" << endl ;
         test++ ;
       }


      el = tmp + (elem_type) 1 ;
      rc = z1.bin_search ( el , pos ) ;

      if ( rc )
       {
	 cout << " ERROR : binary (down) search failed (non existing element " ; 
	 cout << el << " found) <----- \n" << endl ;
         test++ ;
       }




      //  *****  SORTING/SEARCHING WITH COMPARE-FUNCTIONS  *****

      z1 = a ;
      z2 = b ;

      z1.sort ( greater_than ) ;
      z2.sort ( less_than    ) ;

      cout << " using compare functions ...\n" << endl ;

      cout << " " << a << " in descending  order : " << z1 << "\n" << endl ;
      cout << " " << b << " in ascending   order : " << z2 << endl ;


      cout << "\n binary search ... \n" << endl ;

      el = z1[ z1.size()-1 ] ;
      rc = z1.bin_search ( el , pos , greater_than) ;

      if ( ! rc )
       {
	 cout << " ERROR : binary (gt) search failed (" << el << " not found) <----- \n" << endl ;
         test++ ;
       }


      el = tmp + (elem_type) 1 ;
      rc = z1.bin_search ( el , pos , greater_than ) ;

      if ( rc )
       {
	 cout << " ERROR : binary (gt) search failed (non existing element " ;
         cout << el << " found) <----- \n" << endl ;
         test++ ;
       }

      z1.sort ( less_than  ) ;

      el = z1[ z1.size()-1 ] ;
      rc = z1.bin_search ( el , pos , less_than ) ;
      

      if ( ! rc )
       {
	 cout << " ERROR : binary (lt) search failed (" ;
	 cout << el << " not found) <----- \n" << endl ;
         test++ ;
       }


      el = tmp + (elem_type) 1 ;
      rc = z1.bin_search ( el , pos , less_than ) ;

      if ( rc )
       {
	 cout << " ERROR : binary (lt) search failed (non existing element " ;
	 cout << el << " found) <----- \n" << endl ;
         test++ ;

	 cout << z1 << "\n" << el << "\n" << pos << endl ;
	 exit(1) ;
       }



   // ***** READING FROM AND WRITING TO FILE *****

   cout << " reading from and writing to file ... \n" << endl ;

   fname = tempnam ( ".", "LVECT" ) ;


   // write a to file fname twice, read the to copies of a in z1 and z2, and
   // compare these vectors with a  ( ASCII - format )
 
   if ( ( fp = (FILE*) fopen ( fname, "w" ) ) != nil )
    {
      a.print_to_file ( fp ) ;
      a.print_to_file ( fp ) ;

      fclose ( fp ) ;

      if ( ( fp = (FILE*) fopen ( fname, "r" ) ) != nil )
       {
	 z1.scan_from_file ( fp ) ;
	 z2.scan_from_file ( fp ) ;

	 if ( a != z1 || a != z2 )
	  {
	    cout << "a.print_to_file (FILE*) or a.scan_from_file (FILE*) failed !\n" << endl ;
	    test++ ;
	  }

	 fclose ( fp ) ;
       }
      else
       {	
	 cout << "sorry, can't open " << fname << " for reading in ASCII - format ! \n" ;
	 cout << "test was stopped. \n\n" << endl ;
	 exit ( 1 ) ;
       }
    }
   else
    {
      cout << "sorry, can't open " << fname << " for writing in ASCII - format ! \n" ;
      cout << "test was stopped. \n\n" << endl ;
      exit ( 1 ) ;
    }


   // the same test for binary - format

   if ( ( fp = (FILE*) fopen ( fname, "wb" ) ) != nil )
    {
      a.write_to_file ( fp ) ;
      a.write_to_file ( fp ) ;

      fclose ( fp ) ;

      if ( ( fp = (FILE*) fopen ( fname, "rb" ) ) != nil )
       {
	 z1.read_from_file ( fp ) ;
	 z2.read_from_file ( fp ) ;

	 if ( a != z1 || a != z2 )
	  {
	    cout << "a.write_to_file (FILE*) or a.read_from_file (FILE*) failed !\n" << endl ;
	    test++ ;
	  }

	 fclose ( fp ) ;
       }
      else
       {	
	 cout << "sorry, can't open " << fname << " for reading in binary - format ! \n" ;
	 cout << "test was stopped. \n\n" << endl ;
	 exit ( 1 ) ;
       }
    }
   else
    {
      cout << "sorry, can't open " << fname << " for writing in binary - format ! \n" ;
      cout << "test was stopped. \n\n" << endl ;
      exit ( 1 ) ;
    }


   unlink ( fname ) ;


   if ( test == 0 )
    {
      cout << "\n No errors detected. \n\n" << endl ;
    }
   else
    {
      cout << "\n " << test << " error(s) detected. \n\n" << endl ;
    }
 }
