// Aspell check functions
// Copyright 1998 by Kevin Atkinson under the terms of the LGPL

#ifndef as_check__
#define as_check__

#define tl template <class Itr, class ItrEnd>
#define tld template <class Itr, class ItrEnd = Itr>
#define tt Itr,ItrEnd

tld class region_skipper_iterator {
public:
  typedef iterator_traits<Itr>::value_type       value_type;
  typedef iterator_traits<Itr>::difference_type  difference_type;
  typedef iterator_traits<Itr>::pointer          pointer;
  typedef iterator_traits<Itr>::reference        reference;
protected:
  Itr    real_cur_;
  Itr    cur_;
  ItrEnd end_;
  bool blank_out_;
  void skip_ahead() {
    scan_ahead();
    if (blank_out_) real_cur_ = cur_;
    ++cur_;
  }
  virtual void scan_ahead() = 0;
  void reset(Itr c, ItrEnd e) 
    {real_cur_ = c; cur_ = c; end_ = e; blank_out_ = false;}
public:
  region_skipper_iterator() {}
  virtual ~region_skipper_iterator() {}
  
  virtual region_skipper_iterator & operator= (const region_skipper_iterator &other) {
    real_cur_  = other.real_cur_;
    cur_       = other.cur_;
    end_       = other.end_;
    blank_out_ = other.blank_out_;
    return *this;
  }

  virtual const char * name() const = 0;
  virtual region_skipper_iterator * clone() const = 0;
  virtual region_skipper_iterator * create() const = 0;
  virtual void save_state() {};
  virtual void rescan(Itr b, Itr c, ItrEnd e) {restart(c,e);}
  virtual void scan_ahead(Itr b) {restart(b,end_);}
  virtual void restart(Itr c, ItrEnd e) = 0;

  reference operator*()
    {return *real_cur_;}
  const reference operator*() const 
    {return *real_cur_;}
  region_skipper_iterator& operator++() 
    {++real_cur_; if (real_cur_ == cur_) skip_ahead(); return *this;}
  Itr real_itr() const {return real_cur_;}
  ItrEnd end() const {return end_;}
  bool is_end() const {return real_cur_ == end_;}
};

tl inline bool operator== (const region_skipper_iterator<tt> & rhs, 
			   const region_skipper_iterator<tt> & lhs) 
{
  return rhs.real_itr() == lhs.real_itr();
}

template <class ItrEnd>
class region_skipper_iterator_end {
  ItrEnd end_;
public:
  ItrEnd end() const {return end_;}
};

tl inline bool operator==(region_skipper_iterator<Itr, ItrEnd> rhs,
			  region_skipper_iterator_end<ItrEnd> lhs) {
  return rhs.real_itr() == lhs.end();  
};

tl inline bool operator==(region_skipper_iterator_end<ItrEnd> rhs,
			  region_skipper_iterator<Itr, ItrEnd> lhs) {
  return rhs.end() == lhs.real_itr();  
};

tld class url_skip_iterator : public region_skipper_iterator<tt> {
protected:
  void scan_ahead();
public:
  url_skip_iterator() {}
  const char * name() const {return "url";}
  url_skip_iterator * clone() const {return new url_skip_iterator(*this);}
  url_skip_iterator * create() const {return new url_skip_iterator;}
  void restart(Itr i, ItrEnd e) 
    {reset(i,e); skip_ahead();}
};

tld class no_skip_iterator : public region_skipper_iterator<tt> {
protected:
  void scan_ahead() {}
public:
  no_skip_iterator() {}
  const char * name() const {return "none";}
  no_skip_iterator * clone() const {return new no_skip_iterator(*this);}
  no_skip_iterator * create() const {return new no_skip_iterator;}
  void restart(Itr i, ItrEnd e)
    {reset(i,e);}
};

#undef tl
#undef tt
#undef tld

template <class Itr, class ItrEnd = Itr>
class aspell_check_state {
public:
  typedef region_skipper_iterator<Itr, ItrEnd> skip_iterator;
  typedef Itr                                  iterator;
  typedef ItrEnd                               end_iterator;
public: // this stuff is really private but friend templates
        // are a mess
  skip_iterator * word_begin_;
  skip_iterator * word_end_;
  void copy(const skip_iterator &i)
    {word_begin_ = i.clone(); word_end_ = i.create();}
  void copy(const aspell_check_state &other) {
    word_begin_ = other.word_begin_ ? other.word_begin_->clone() : 0;
    word_begin_ = other.word_end_   ? other.word_end_->clone()   : 0;
  }
  void destroy() {
    delete word_begin_;
    delete word_end_;
  }
  void save_state() {
    word_begin_->save_state();
    word_end_->save_state();
  };
public:
  aspell_check_state() : word_begin_(0), word_end_(0) {}
  aspell_check_state(const skip_iterator &i) {copy(i);}
  aspell_check_state(const aspell_check_state &other) {copy(other);}
  aspell_check_state& operator= (const skip_iterator &i)
    {destroy(); copy(i); return *this;}
  aspell_check_state& operator= (const aspell_check_state &other)
    {if (&other != this) {destroy(); copy(other);} return *this;}
  ~aspell_check_state() {destroy();}
  const skip_iterator & itr() const {return *word_begin_;}
  void advance() {*word_begin_ = *word_end_;}
  Itr     word_begin() const {return word_begin_->real_itr();}
  Itr     word_end()   const {return word_end_->real_itr();}
  ItrEnd end()        const {return word_begin_->end();}
  bool   at_end() const {return word_begin_->is_end();}
  void reset() 
    {skip_iterator * temp = word_begin_->create(); destroy(); 
    word_begin_ = temp; word_end_ = temp->create();}
  void restart(Itr c, ItrEnd e) {word_begin_->restart(c,e);}
  void rescan(Itr b, Itr c, ItrEnd e) {word_begin_->rescan(b, c, e);}
  void scan_ahead(Itr c) {word_begin_->scan_ahead(c);}
};

struct AS_DoNothing {
  void operator () () const {}
};

template <class ForwardIterator, class EndIterator, class StatusFunc>
bool check (const aspell & sc, 
	    aspell_check_state<ForwardIterator, EndIterator> & state,
	    const StatusFunc & print_status);

template <class ForwardIterator, class EndIterator>
inline bool check (const aspell & sc, 
		   aspell_check_state<ForwardIterator, EndIterator> & state) 
{
  return check(sc, state, AS_DoNothing());
}

#endif
