//
// LiDIA - a library for computational number theory
//   Copyright (c) 1995 by the LiDIA Group
//
// File        : sort_vector.h 
// Author      : Frank Lehmann (FL), Markus Maurer (MM) 
//               Thomas Papanikolaou (TP), Patrick Theobald (PT)
// Last change : FL/MM, Feb 15 1995, initial version
//               FL/MM, May 10 1995, clean-up
//		 FL/MM, May 15 1995, changed type of size variables to base_vector<T>::size_type
//		 FL/MM, May 27 1995, moved protected members "sort_dir", "el_cmp"
//				     from sort_vector to base_vector; changed member
//				     operator=; removed friend swap()
//		 FL/MM, Jul  6 1995, replaced base_vector<T>::size_type by lidia_size_t
//               FL/MM, Jul 24 1995, added 'const' to T* parameters of constructors
//		 FL/MM, Aug 30 1995, changed "error_handler" to "lidia_error_handler"
//               PT     Oct 28 1995, new template concept
//


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// *
// *    File        :  sort_vector.h
// *
// *    Description :  -) definition of template class 'sort_vector'
// *                      to allow use of sortable vectors
// *
// *                   -) virtual base class is 'base_vector'
// *
// *                   -) uses template class 'comparator'
// *
// *    Notes       :  *) any class MUST support the operators
// *                                  <, <=, and  == 
// *                      to allow its use in the template
// *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

#ifndef LIDIA_SORT_VECTOR_H
#define LIDIA_SORT_VECTOR_H

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

const char SORT_VECTOR_DEF  =  0;
const char SORT_VECTOR_UP   =  1;
const char SORT_VECTOR_DOWN =  2;
const char SORT_VECTOR_CMP  =  3;

template <class T> 
class sort_vector : public virtual base_vector < T >
{
  
  /**
   ** constructors 
   **/
 
 public:
 
  inline sort_vector() : base_vector < T > (0, FIXED) 
    {sort_dir = SORT_VECTOR_UP; el_cmp = nil;}
  inline sort_vector(lidia_size_t all, char md) : base_vector < T > (all, md)
    {sort_dir = SORT_VECTOR_UP; el_cmp = nil;}
  inline sort_vector(lidia_size_t all, lidia_size_t len) : base_vector < T > (all, len, FIXED)
    {sort_dir = SORT_VECTOR_UP; el_cmp = nil;}
  inline sort_vector(lidia_size_t all, lidia_size_t len, char md) : base_vector < T > (all, len, md)
    {sort_dir = SORT_VECTOR_UP; el_cmp = nil;}
  inline sort_vector(const sort_vector < T > & v) : base_vector < T > (v, FIXED)
    {sort_dir = v.sort_dir; el_cmp = v.el_cmp;}
  inline sort_vector(const base_vector < T > & v, char md) : base_vector < T > (v, md)
    {sort_dir = SORT_VECTOR_UP; el_cmp = nil;}
  inline sort_vector(const T *v, lidia_size_t len) : base_vector < T > (v, len, FIXED)
    {sort_dir = SORT_VECTOR_UP; el_cmp = nil;}
  inline sort_vector(const T *v, lidia_size_t len, char md) : base_vector < T > (v, len, md)
    {sort_dir = SORT_VECTOR_UP; el_cmp = nil;}
  
  /**
   ** destructor 
   **/

 public:  

  inline ~sort_vector() {}
  
  /**
   ** assignment 
   **/

 public:

  sort_vector < T > & operator = (const sort_vector < T > &);

  /**
   ** reading & modifying sort-directions  
   **/

 public:

  inline char sort_direction() const
    {return  sort_dir;}
  inline char get_sort_direction() const
    {return  sort_dir;}

  void set_sort_direction(char); 
  void set_sort_direction(int (*cmp) (const T &, const T &));

  /**
   ** sort-functions using Quick-Sort routines  
   **/

 public:

  void sort(int (*cmp)(const T &, const T &), lidia_size_t l = 0, lidia_size_t r = -1);
  void sort(char sort_direction = SORT_VECTOR_DEF, lidia_size_t l = 0, lidia_size_t r = -1);
  inline void sort(lidia_size_t l, lidia_size_t r)
    {sort(SORT_VECTOR_DEF, l, r);}

 protected:

  void sort_up(lidia_size_t, lidia_size_t);
  void sort_down(lidia_size_t, lidia_size_t);

  /**
   ** functions for linear search in vectors  
   **/

 public:
  
  bool linear_search(const T &, lidia_size_t &) const;

  /**
   ** functions for binary search in sorted vectors  
   **/
 
 public:
 
  bool bin_search(const T &, lidia_size_t &, int (*cmp)(const T &, const T &), lidia_size_t l = 0, lidia_size_t r = -1) const; 
  bool bin_search(const T &, lidia_size_t &, char sort_direction = SORT_VECTOR_DEF, lidia_size_t l = 0, lidia_size_t r = -1) const;
  inline bool bin_search(const T & x, lidia_size_t & pos, lidia_size_t l, lidia_size_t r) const
    {return (bool) bin_search(x, pos, SORT_VECTOR_DEF, l, r);}

 protected:

  bool bin_search_up(const  T &, lidia_size_t &, lidia_size_t, lidia_size_t) const;
  bool bin_search_down(const  T &, lidia_size_t &, lidia_size_t, lidia_size_t) const;

  /**
   ** functions to insert new elts. into a vector  
   **/
 
 public:
 
  void insert(const T &, int (*cmp)(const T &, const T &), lidia_size_t l = 0, lidia_size_t r = -1);
  void insert(const T &, char sort_direction = SORT_VECTOR_DEF, lidia_size_t l = 0, lidia_size_t r = -1);
  inline void insert(const T & x, lidia_size_t l, lidia_size_t r) 
    {insert(x, SORT_VECTOR_DEF, l, r);}

  /**
   ** functions to remove elts. from within a vector  
   **/

 public:

  bool remove(const T &, int (*cmp)(const T &, const T &), lidia_size_t l = 0, lidia_size_t r = -1);
  bool remove(const T &, char sort_direction = SORT_VECTOR_DEF, lidia_size_t l = 0, lidia_size_t r = -1);
  inline bool remove(const T & x, lidia_size_t l, lidia_size_t r)
    {return (bool) remove(x, SORT_VECTOR_DEF, l, r);}

  int lex_compare(sort_vector < T > &) const;
 
  /**
   ** miscellaneous 
   **/

 public:
 
  void delete_copies();
};

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

#endif

