
#ifndef __repl_t_hh__
#define __repl_t_hh__

#include "repl.hh"
#include "clone_ptr-t.hh"

namespace afilter {

  //
  // repl_itr
  //

  template <typename CR, int I, int O>
  ReplItr<CR,I,O>::ReplItr() 
    : buffer(repl.max_out()) {}

  template <typename CR, int I, int O>
  ReplItr<CR,I,O>::ReplItr(ConfigData * opts, const ReplOpts * lopts) 
    : repl(opts,lopts), buffer(repl.max_out()) {}

  template <typename CR, int I, int O>
  ReplItr<CR,I,O>::ReplItr(const CharReplBase & cr) 
    : repl(static_cast<const CR &>(cr)), buffer(repl.max_out()) {}

  template <typename CR, int I, int O>
  ReplItr<CR,I,O> * ReplItr<CR,I,O>::clone() const {
    return new ReplItr(*this);
  }

  template <typename CR, int I, int O>
  void ReplItr<CR,I,O>::assign(const FilterItrPart * other) {
    *this = *static_cast<const ReplItr *>(other);
  }
  
  template <typename CR, int I, int O>
  string ReplItr<CR,I,O>::name() const {
    return repl.name();
  }

  template <typename CR, int I, int O>
  double ReplItr<CR,I,O>::order_num() const {
    return repl.order_num();
  }

  template <typename CR, int I, int O>
  char ReplItr<CR,I,O>::first() {
    char c = itr->first();
    if (!c) return c;
    last = itr;
    buffer.clear();
    if (repl.fill(c, last, &buffer)) {
      buffer.reset();
      c = *buffer;
      ++buffer;
      return c;
    } else {
      return '?';
    }
  }

  template <typename CR, int I, int O>
  char ReplItr<CR,I,O>::next() {
    if (buffer.at_end()) {
      char c = last->next();
      if (!c) return c;
      itr = last;
      buffer.clear();
      if (!repl.fill(c, last, &buffer))
	return '?';
      buffer.reset();
    }
    char c = *buffer;
    ++buffer;
    return c;
  }

  //
  // DualRepl
  //


  template <typename From, typename To>
  DualRepl<From,To>::DualRepl() : repl_from(new From()), repl_to(new To()) {}

  template <typename From, typename To>
  string DualRepl<From,To>::name() const {
    return repl_from->name() + "/" + repl_to->name();
  }

  template <typename From, typename To>
  double DualRepl<From,To>::order_num() const {
    return (repl_from->order_num() + repl_to->order_num())/2;
  }

  template <typename From, typename To>
  int DualRepl<From,To>::max_in() const {
    return repl_from->max_in();
  }

  template <typename From, typename To>
  int DualRepl<From,To>::max_out() const {
    return repl_to->max_out();
  }

  template <typename From, typename To>
  int DualRepl<From,To>::scan_needed() const {
    return repl_from->scan_needed();
  }

  template <typename From, typename To>
  void DualRepl<From,To>::reset() {
    repl_from->reset();
  }

  template <typename From, typename To>
  void DualRepl<From,To>::scan(Itr & begin, const ItrRoot & stop) {
    repl_from->scan(begin, stop);
  }

  template <typename From, typename To>
  bool DualRepl<From,To>::fill(InValue c, Itr * i, Buffer * b) {
    if (!repl_from->fill(c, i, &dummy_buf)) {
      TryHard::String t = try_hard.tryu(c);
      if (t.empty()) return false;
      else return false; // FIXME do the right thing, don't return false
    } else {
      return repl_to->fill(*dummy_buf, 0, b);
    }
  }
}
#endif
