#ifndef _VISMAN_H
#define _VISMAN_H
#include <iostream.h>
#include "log.h"
#include "logtext.h"

//returns a copy of the string, made with operator new [] 
char *newStr (const char *copythis);

class Vis {
public:
  const Vis *_parent;
  char _type [40];
  int _depth; //how many parents we have
  
  Vis (const Vis *parent, const LogEntry *someevent);

  virtual void Display (const LogEntry *upto) const = 0; //should draw your state through upto

  virtual char * StatusLine (const LogEntry *ours) const = 0; //what's going to show up in the log status window for this event? The returned string has to be newed b/c we delete it when we're done.

  virtual const LogEntry *GetStartEntry (void) const = 0;
  //recursive calls have to be smart about these - maybe use some obj *
  //as an id.
  virtual int IsOurs (const LogEntry *en) const = 0; //returns true if the event is one of ours
  virtual int IsEndEvent (const LogEntry *en) const = 0; //returns true if the event is our end event
  virtual int IsStartEvent (const LogEntry *en) const = 0; //returns true if the event is our end event
};


class VisManager {
protected:
  const Vis *_cur_vis;

  const LogEntry *_cur_entry;
  int _cur_entry_num;
  
  LogText _text;
  
  void LeaveCurEvent (void);
  
  void AddToStatus (const Vis *curvis, const LogEntry *entry);
  void DisplayUpTo (const Vis *curvis, const LogEntry *start, const LogEntry *end);
  void DisplayCurrent (const LogEntry *start);

  void CollectStatusLines (Vis *cur);

  Vis * ConstructVis (const Vis *parent, const LogEntry *en); //the big switch.
     //vis is responsible for finding its start event

  void CleanStack (void);

public:
  VisManager (void);

  void Step (void); //go forward one log entry
  void StepOver (void); //if we could step down, don't.
  void StepUp (void); //get back to our parent
  void GetPast (void); //get to right past our end event

  void RewindUp (void); //get back to our parent
  void RewindOver (void); //get to previous event at this level; if none, go to the parent.
  void Rewind (void); //go back one log event
  void RewindToStart (void); //go to our start event

  void JumpUp (void);

  void JumpToEnd();
  void JumpToStart();

  void ClearLog (void) {rclog.Clear(); delete _cur_vis; _cur_entry = rclog.First(); _cur_vis = ConstructVis (NULL, _cur_entry);}
  void GotoEvent (const LogEntry *en);

  int Display (void); //returns nonzero if we're displaying a new entry
  void CollectStatusLines (void);

  static const LogEntry *FindVisStart (const Vis *vis, const LogEntry *starthere);
  static const LogEntry *FindVisEnd (const Vis *vis, const LogEntry *starthere);

//first entry is 1
  int Loc(void) const {return _cur_entry_num + 1;} //what log entry we're on.
  const LogEntry *Entry (void) const {return _cur_entry;}
};

class DefaultVis : public Vis {
protected:
  const LogEntry *_ourevent;
public:
  DefaultVis (const Vis *parent, const LogEntry *someevent) : Vis (parent, someevent), _ourevent (someevent) {strcpy (_type, "defaultVis");}

   void Display (const LogEntry *current) const {cerr << "[need display for " << current->_name << "]" << endl;}

  char *StatusLine (const LogEntry *ours) const  {char *newline = new char [strlen (ours->_name) + 1]; strcpy (newline, ours->_name); return newline;}

  const LogEntry *GetStartEntry (void) const {return _ourevent;}

  int IsOurs (const LogEntry *en) const {return (en == _ourevent);}
  int IsStartEvent (const LogEntry *en) const {return (en == _ourevent);}
  int IsEndEvent (const LogEntry *en) const {return (en == _ourevent);}
};

//these all return NULL if the query failed.
class LogQueryEngine {
public:
  static const LogEntry *FindNextNewFrame (const LogEntry *starthere);
  static const LogEntry *FindPrevNewFrame (const LogEntry *starthere);
  static const LogEntry *FindFrameNum (int framenum);
  static const LogEntry *FindNextRay (int x, int y);
  
  static const LogEntry *FindNextObjMiss (const LogEntry *starthere);
  static const LogEntry *FindPrevObjMiss (const LogEntry *starthere);
};

#endif
