// definition file for template'd Set class

#include <iostream>
#include <cctype>

#include "srchsort.h"
#include "input.h"

// can't do using since this will be #include'd elsewhere...

template <typename ElemType>
long Set<ElemType>::find(const ElemType & item) const
{
   return bin_search(the_set, 0, cur_elem-1, item);
}

template <typename ElemType>
void Set<ElemType>::arrange(void)
{
   sort(the_set, 0, cur_elem-1);
   return;
}

template <typename ElemType>
bool Set<ElemType>::operator!(void) const
{
    return !worked;
}

template <typename ElemType>
Set<ElemType> & Set<ElemType>::operator+=(const ElemType & item)
{
   worked = false;
   if (cur_elem < MAX_SET)
   {
      worked = true;
      the_set[cur_elem++] = item;
      if (cur_elem > 1)
      {
         arrange();
      }
   }
   return *this;
}

template <typename ElemType>
void Set<ElemType>::rem_elem(const ElemType & item, const long from_where)
{
   long i;
   for (i = from_where; i < (cur_elem-1); i++)
   {
      the_set[i] = the_set[i+1];
   }
   cur_elem--;
   return;
}


template <typename ElemType>
Set<ElemType>::Set(void)
{
   cur_elem = 0;
   worked = true;
}


template <typename ElemType>
bool operator^(const ElemType & item, const Set<ElemType> & set)
{
   return (set.find(item) >= 0);
}

template <typename ElemType>
bool Set<ElemType>::operator^(const ElemType & item) const
{
   return (find(item) >= 0);
}


template <typename ElemType>
Set<ElemType> Set<ElemType>::operator+(const Set<ElemType> & set) const
{
   Set<ElemType> new_set(*this);
   long i;
   for (i = 0; i < set.cur_elem; i++)
   {
      new_set += set.the_set[i];
   }
   return new_set;
}

template <typename ElemType>
Set<ElemType> Set<ElemType>::operator*(const Set<ElemType> & set) const
{
   Set<ElemType> new_set(*this);
   long i;
   for (i = 0; i < set.cur_elem; i++)
   {
      new_set -= set.the_set[i];
   }
   return new_set;
}

template <typename ElemType>
Set<ElemType> & Set<ElemType>::operator-=(const ElemType & item)
{
   long at;
   if ((at = find(item)) >= 0)
   {
      rem_elem(item, at);
   }
   worked = (at >= 0);
   return *this;
}


template <typename ElemType>
std::ostream & operator<<(std::ostream & out, const Set<ElemType> & set)
{
   long i;
   out << " { ";
   for (i = 0; i < set.cur_elem; i++)
   {
      out << set.the_set[i] << "  ";
      if (((i+1)%7) == 0)
      {
         out << std::endl << "   ";
      }
   }
   out << "}";
   if ((i%7) == 0)
   {
      out << std::endl;
   }
   return out;
}

template <typename ElemType>
std::istream & operator>>(std::istream & in, Set<ElemType> & set)
{
   char brace;
   long i;
   in >> brace;
   i = 0;
   while ((i < MAX_SET) && !in.eof() && (peek(in) != '}'))
   {
      in >> set.the_set[i++];
   }
   in >> brace;
   set.cur_elem = i;
   set.arrange();
   set.rem_dupl();
   return in;
}

template <typename ElemType>
void Set<ElemType>::rem_dupl(void)
{
   long i = 0;
   while (i < (cur_elem-1))
   {
      if (the_set[i] == the_set[i+1])
      {
         rem_elem(the_set[i], i);
      }
      else
      {
         i++;
      }
   }
   return;
}

template <typename ElemType>
bool Set<ElemType>::full(void) const
{
    return (cur_elem == MAX_SET);
}
