#ifndef MEM_RECORDS_H
#define MEM_RECORDS_H

#include <vector>
#include <utility>
#include <ostream>
#include <algorithm>
#include <iterator>

#include "MemHeader.hpp"

namespace mem {

  class Record
  {
  public:
    typedef std::vector<unsigned long> vint;
    Record():seq_()
      {
	head_.len_=0;
	head_.type_=UnknownID;
	data_.reserve(300);
      }

    int type() const { return head_.type_; }

    Header head_;
    int seq_;
    vint data_;
  };

  std::ostream& operator<<(std::ostream& ost, const Record& r);

  class AllocRecord
  {
  public:
    explicit AllocRecord(Record& r): r_(r) { }

    const Header& header() const { return r_.head_; }

    const unsigned long* stackBegin() const { return &r_.data_[2]; }
    const unsigned long* stackEnd() const { return &(*r_.data_.end()); }

    unsigned long* stackBegin() { return &r_.data_[2]; }
    unsigned long* stackEnd() { return &(*r_.data_.end()); }

    unsigned long address() const { return r_.data_[0]; }
    int seq() const { return r_.seq_; }
    int size() const { return r_.data_[1]; }
    const char* id() const { return r_.head_.type_==mem::AllocID?"m":r_.head_.type_==mem::CallocID?"c":r_.head_.type_==mem::ReallocID?"r":"?"; }

  private:
    Record& r_;
  };

  class FreeRecord
  {
  public:
    explicit FreeRecord(Record& r): r_(r) { }

    const Header& header() const { return r_.head_; }

    const unsigned long* stackBegin() const { return &r_.data_[1]; }
    const unsigned long* stackEnd() const { return &(*r_.data_.end()); }

    unsigned long* stackBegin() { return &r_.data_[1]; }
    unsigned long* stackEnd() { return &(*r_.data_.end()); }

    unsigned long address() const { return r_.data_[0]; }
    int seq() const { return r_.seq_; }
    int size() const { return 0; }
    const char* id() const { return "f"; }

  private:
    Record& r_;
  };

  inline std::ostream& operator<<(std::ostream& ost,const AllocRecord& a)
  {
    ost << a.id() << " " 
	<< (void*)a.address() << " " 
	<< a.seq() << " "
      	<< a.size() << " ";
    std::copy(a.stackBegin(),a.stackEnd(),
          std::ostream_iterator<unsigned long>(ost," "));
    return ost;
  }

  inline std::ostream& operator<<(std::ostream& ost,const FreeRecord& a)
  {
    ost << a.id() << " " 
	<< (void*)a.address() << " " 
	<< a.seq() << " "
      	<< a.size() << " ";
    std::copy(a.stackBegin(),a.stackEnd(),
          std::ostream_iterator<unsigned long>(ost," "));
    return ost;
  }

  unsigned long getAddress(const Record& r);
  typedef std::pair<unsigned long*,unsigned long*> StackArray;
  typedef std::pair<const unsigned long*,const unsigned long*> ConstStackArray;
  ConstStackArray getStack(const Record& r);
  StackArray getStack(Record& r);

}
#endif
