#include "maze.h"

int WALL = 0;
int EMPTY = 1;
int PATH = 2;
int DEAD = 3;

maze::maze() {
    map.resize(8);
    for(int i = 0; i < 8; i++) {
        map[i].resize(8);
        for(int j = 0; j < 8; j++) {
            map[i][j].resize(8);
        }
    }
}

void vector_clear(vector<vector<vector<int>>> & map) {
    for(unsigned int k = 0; k < 8; k++) {
        for(unsigned int j = 0; j < 8; j++) {
            for(unsigned int i = 0; i < 8; i++) {
                map[i][j][k] = 0;
            }
        }
    }
}

void maze::createRandomMaze() {
    vector_clear(map);
    for(int i = 0; i < 8; i++) {
        for(int j = 0; j < 8; j++) {
            for(int k = 0; k < 8; k++) {
                int randnum = rand() % 2;
                map[i][j][k] = randnum;
            }
        }
    }
    map[0][0][0] = 1;
    map[7][7][7] = 1;
}

bool maze::importMaze(string fileName) {
    vector_clear(map);
    ifstream infile(fileName.c_str());
    char c;
    for(unsigned int k = 0; k < 8; k++) {
        for(unsigned int j = 0; j < 8; j++) {
            for(unsigned int i = 0; i < 8; i++) {
                c = infile.get();
                if (c == '0') {
                    map[i][j][k] = 0;
                }
                else if (c == '1') {
                    map[i][j][k] = 1;
                }
                else if (c == 'a') {
                    return false;
                }
                c = infile.get();
            }
            c = infile.get();
            if(c == '\r') {
                c = infile.get();
            }
            if(c != '\n') {
                return false;
            }
        }
        c = infile.get();
        if(c == '\r') {
            c = infile.get();
        }
        if(c != '\n') {
            return false;
        }
    }
    if(map[0][0][0] == 0 || map[7][7][7] == 0) {
        return false;
    }
    return true;
}

bool maze::solve(int x,int y, int z) {
    if(x < 0 || y < 0 || z < 0 || x >= map.size() || y >= map.size() || z >= map.size()) {
        return false;
    }
    else if(map[x][y][z] != EMPTY) {
        return false;
    }
    else if(x == map.size() - 1 && y == map.size() - 1 && z == map.size() - 1) {
        path << "(" << x << ", " << y << ", " << z << ")";
        ordered_pairs.push_back(path.str());
        path.str("");
        map[x][y][z] = PATH;
        return true;
    }
    else {
        map[x][y][z] = PATH;
        if(solve(x - 1, y, z) ||
             solve(x + 1, y, z) ||
             solve(x, y - 1, z) ||
             solve(x, y + 1, z) ||
             solve(x, y, z - 1) ||
             solve(x, y, z + 1)) {
            path << "(" << x << ", " << y << ", " << z << ")\n";
            ordered_pairs.push_back(path.str());
            path.str("");
            return true;
        } 
        else {
            map[x][y][z] = DEAD;
            return false;
        }
    }
}

bool maze::traverseMaze() {
    path.str("");
    ordered_pairs.clear();
    bool b = solve(0,0,0);
    return b;
}

string maze::getMazePath() {
    for(int i = ordered_pairs.size() - 1; i >= 0; i--) {
        path << ordered_pairs[i];
    }
    return path.str();
}

string maze::getMaze() {
    stringstream os;
    os << *this;
    return os.str();
}

ostream & operator<<(ostream & os,  maze & m) {
    for(int k = 0; k < 8; k++) {
        for(int j = 0; j < 8; j++) {
            for(int i = 0; i < 8; i++) {
                os << m.map[i][j][k];
                os << " ";
            }
            os << "\n";
        }
        os << "\n";
    }
    return os;
}
