#ifndef SQUASH_EXPR_REWRITER
#define SQUASH_EXPR_REWRITER
// See License.txt for copyright and terms of use

// Rewrites code at the expression level

#include "oink.gr.gen.h"
#include "oink_global.h"
#include "squash_min_max_line_visitor.h"
#include "squash_patcher.h"
#include <string>
#include <iostream>
#include <map>
#include <list>

class ExprRewriterVisitor;

class ExprRewriter {
public:

  ExprRewriter(std::string const &interfaceClassName,
               std::string const &implementationClassName,
               Patcher &patcher,
               SquashCmd const &cmd);

  void rewrite(S_compound *s);
  void rewriteExpression(Expression *obj);
  void rewriteMemberInit(MemberInit *obj);
  ~ExprRewriter();
public:
  // Marks statements on line for patching
  template<class T> void rewriteSurrounding(T* t);

  std::string const &interfaceClassName;
  std::string const &implementationClassName;
  Patcher &patcher;

  typedef std::list<std::pair<Statement*, MinMaxLineVisitor> > stMmlvList;
  // All of the statements with the associated positions
  stMmlvList stmLines;
  // Statements to rewrite are pushed here
  stMmlvList rewrites;
  SquashCmd const &cmd;
  ExprRewriterVisitor *exprVisitor;
  
};

// Convenient func to print out arbitrary AST nodes
template<class T> static void print(std::ostream &ostream, T *m) {
  OStreamOutStream out0(ostream);
  CodeOutStream codeOut(out0);
  PrintEnv env(typePrinterOink, &codeOut);
  m->print(env);
  codeOut.finish();
}

// Helper to hack around around various lacking of correct position info in the ast
template <class T> static MinMaxLineVisitor
    traverseAndGuess(Patcher &patcher, T obj, 
                     std::string const terminators = "}")
{
  MinMaxLineVisitor mmlv;
  obj->traverse(mmlv);
  //HEURISTIC: }; is usually at least one line after the last member
  while (patcher.getLine(mmlv.maxLine, mmlv.getFile()).find_first_of(terminators)
        == std::string::npos)
  {
    mmlv.maxLine++;
  }
  return mmlv;
}

typedef std::list<AtomicType*> AtomicType_list;
void listAtomicTypes(Type *t, AtomicType_list &ls);
void listAtomicTypes(AtomicType *t, AtomicType_list &ls);

#endif // SQUASH_EXPR_REWRITER
