#ifndef __TRAVERSABLEAVMGAME_H
#define __TRAVERSABLEAVMGAME_H

#include "stdafx.h"

#include <string>
using std::string;
#include <list>
using std::list;
#include <iostream>
using std::ostream;
using std::istream;
#include<stack>
using std::stack;

struct Category {
    Category(string name="", string yesOrNoQuestion="", 
        int childNumber = 0): name(name),
        yesOrNoQuestion(yesOrNoQuestion),
        childNumber(childNumber){
    }
    string name;
    string yesOrNoQuestion;
    int childNumber;
    list<Category> subcategories;
    void writeTo(ostream &out, list<int> prefix);
    bool install(list<int> coordinates, Category category);
};

class TraversableAVMGame: protected Category {
    struct PlaceMarker {
        Category * category;
        list<Category>::iterator nextSubcategory;
    };
    PlaceMarker place;
    stack<PlaceMarker> history;
public:
    void initialize();
    TraversableAVMGame() { initialize(); }
    bool atSubtreeEnd() {
        return place.nextSubcategory == 
                place.category->subcategories.end();
    }
    bool atEnd() {
        return atSubtreeEnd() && place.category == this;
    }
    string getName() {
        return place.category->name;
    }
    string getQuestion() {
        return place.category->yesOrNoQuestion;
    }
    string getNextName() {
        return place.nextSubcategory->name;
    }
    string getNextQuestion() {
        return place.nextSubcategory->yesOrNoQuestion;
    }
    void accept() {
        if (!atSubtreeEnd()) {
            history.push(place);
            place.category = &*place.nextSubcategory;
            place.nextSubcategory = 
                place.category->subcategories.begin();
        }
    }
    void reject() {
        if (!atSubtreeEnd()) place.nextSubcategory++;
        else {
            while (atSubtreeEnd() && !history.empty() 
                    && !atEnd()) {
                place = history.top();
                history.pop();
            }
        }
    }
    virtual void reset() {
        // Must have a virtual function in order to do a 
        // dynamic cast.
        place.category = this;
        place.nextSubcategory = subcategories.begin();
        while (!history.empty()) history.pop();
    }
    void readFrom(istream &in);
    void writeTo(ostream &out);
    void addSubcategory(string subcategoryName, string question) {
        int childNumber = place.category->subcategories.size()+1;
        place.category->subcategories.push_back(
            Category(subcategoryName,question,childNumber)
        );
    }
};

istream & operator >> (
    istream &in, TraversableAVMGame & game);
ostream & operator << (
    ostream &out, TraversableAVMGame & game);

#endif
