#include "stdafx.h"
#include "TraversableAVMGame.h"
#include <iostream>
using std::endl;
#include <string>
using std::string;
#include <list>
using std::list;
#include <fstream>
using std::ofstream;
using std::ifstream;
#include <exception>
using std::exception;

void TraversableAVMGame::initialize() {
    subcategories.clear();
    subcategories.push_back(Category(
        "Animal","Is it an animal?",1));
    subcategories.push_back(Category(
        "Vegetable","Is it a vegetable?",2));
    subcategories.push_back(Category(
        "Mineral","Is it a mineral?",3));
    place.category = this;
    place.nextSubcategory = subcategories.begin();
}

ostream & operator << (ostream &out, list<int> coordinates) {
    bool first = true;
    while (coordinates.size() > 0) {
        if (!first) out << '.';
        first = false;
        out << coordinates.front();
        coordinates.pop_front();
    }
    return out;
}

void Category::writeTo(ostream &out, list<int> prefix) {
    if (!prefix.empty()) out << prefix << '.';
    out << childNumber << " \"" << name << "\" \"" 
        << yesOrNoQuestion << "\"" << endl;
    prefix.push_back(childNumber);
    for (list<Category>::iterator i = subcategories.begin(); 
            i != subcategories.end(); ++i)
        i->writeTo(out,prefix);
}

void TraversableAVMGame::writeTo(ostream &out) {
    list<int> prefix;
    for (list<Category>::iterator i = subcategories.begin(); 
            i != subcategories.end(); ++i)
        i->writeTo(out,prefix);
}

ostream & operator << (ostream &out, 
                        TraversableAVMGame & game) {
    game.writeTo(out);
    return out;
}

void getQuotedString(istream &in, string &s) {
    s = "";
    char discard = ' ';
    while (discard != '"' && in >> discard);
    char c = ' ';
    while (c != '"' && !in.fail()) {
        in.get(c);
        if (c != '"') s += c;
    }
}

istream & operator >> (istream &in, list<int> &L) {
    int number;
    L.clear();
    in >> number;
    L.push_back(number);
    while (in.peek() == '.') {
        in.get();
        in >> number;
        L.push_back(number);
    }
    return in;
}

bool Category::install(list<int> coordinates, 
                        Category category) {
    if (coordinates.empty()) {
        if (category.childNumber != subcategories.size()+1) 
            return false;
        subcategories.push_back(category);
    }
    else {
        list<Category>::iterator i = subcategories.begin();
        while (i->childNumber != coordinates.front()) ++i;
        coordinates.pop_front();
        i->install(coordinates, category);
    }
    return true;
}

void TraversableAVMGame::readFrom(istream & in) {
    subcategories.clear();
    list<int> coordinates;
    while (in >> coordinates) {
        string name, question;
        getQuotedString(in, name);
        getQuotedString(in, question);
        int childNumber = coordinates.back();
        coordinates.pop_back();
        Category subCategory(name,question,childNumber);
        if (!install(coordinates,subCategory))
            throw exception("Invalid coordinates");
    }
}

istream & operator >> (istream &in, 
                        TraversableAVMGame & game) {
    game.readFrom(in);
    game.reset();
    return in;
}
