
#ifndef __bskip__
#define __bskip__

#include "filter.hh"

namespace afilter {

  template <typename T>
  class BlockSkipBase {
  public:
    typedef typename T::Base      Base;
    typedef typename T::Itr       Itr;
    typedef typename T::ItrRoot   ItrRoot;

    virtual BlockSkipBase * clone() const = 0;

    virtual string name() const = 0;
    virtual double order_num() const = 0;

    virtual ~BlockSkipBase() {}

    virtual void reset() {}

    virtual void scan(char c, Itr *, bool & blank_out) = 0;
  };

  struct BlockSkipFilterTypes {
    typedef FilterItrPart                        Itr;
    typedef FilterItrRoot                        ItrRoot;
    typedef BlockSkipBase<BlockSkipFilterTypes>  Base;
  };

  template <typename BlockSkip>
  class BlockSkipItr : public FilterItrPart {
  public:
    string name() const {return skip.name();}
    double order_num() const {return skip.order_num();}

    BlockSkipItr() : blank_char(' ') {}

    BlockSkipItr(const BlockSkipItr & other) 
      : FilterItrPart(other), blank_out(other.blank_out), skip(other.skip),
	root(itr ? itr->root() : 0), 
	block_end(other.block_end), 
	end_root(block_end ? block_end->root() : 0) {}
  
    BlockSkipItr & operator= (const FilterItrPart & o) {
      FilterItrPart::operator=(o);
      const BlockSkipItr & other = static_cast<const BlockSkipItr &>(o);
      blank_out = other.blank_out;
      skip = other.skip;
      root = itr ? itr->root() : 0;
      block_end = other.block_end;
      end_root = block_end ? block_end->root() : 0;
      return *this;
    }

    BlockSkipItr * clone() const {return new BlockSkipItr(*this);}
    void assign(const FilterItrPart * o) {*this = *(const BlockSkipItr *)(o);}

    void reset() {
      blank_out = false; 
      skip.reset();
    }
  
    void scan (const FilterItrRoot * stop) {
      while (*root != *stop && next()); 
    }

    char first() {
      char c = itr->first();
      block_end = itr;
      root = itr->root();
      end_root = block_end->root();
      if (c=='\0') return '\0';
      skip.scan(c, block_end, blank_out);
      if (blank_out) {
	if (blank_char == '\0')
	  return BlockSkipItr::next();
	else
	  return blank_char;
      }
      return c;
    }

    char next() {
    begin:
      bool at_end = *root == *end_root;
      char c = itr->next();
      if (c=='\0') return '\0';
      if (at_end) {
	block_end = itr; //???Needed
	skip.scan(c, block_end, blank_out);
      }
      if (blank_out) {
	if (blank_char == '\0')
	  goto begin;
	else
	  return blank_char;
      } 
      return c;
    }
  
  private:
    bool            blank_out;
    char            blank_char;
    BlockSkip       skip;
    FilterItrRoot * root;

    ClonePtr<FilterItrPart> block_end;
    FilterItrRoot *          end_root;
  };
}

#endif

  
