#ifndef ASTERIOSB_STEST_HPP
#define ASTERIOSB_STEST_HPP

#include <iostream>
#include <cmath>
#include <string>
#include <sstream>
#include <windows.h>
#include <iomanip>
#include <conio.h>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#include <cstring>
#define RandMinMax(min,max) ((min) + (rand() % ((max)-(min)))
#define RandMax(max) RandMinMax(0,max)
#define GRID_HEIGHT 8
#define GRID_WIDTH 8
#define GRID_LENGTH 8
#define SHIP_NUM 15

using namespace std;

namespace Panda_BATTLESHIP_N{
    int a = 5;
    int b = 5;

    struct B_Position {
        int x_axis;
        int y_axis;
        int player;
    };

   struct P_Won {
        bool isWon;
        bool isTie;
    };

    struct S_STATUS {
        int w_player;
        int SHIP_STATUS; // Ship Status, whether it's hit, sunk, or not there.
    };

    struct P_STATUS {
        int x_axis;
        int y_axis;
        S_STATUS Human_P;
        S_STATUS AI_P;
    };

    const int P_1 = 1;
    const int P_2 = 2;
    const int AMT_SHIPS = 15;
    const int conv = 65;
    //const int GRID_HEIGHT = 8;
    //const int GRID_WIDTH = 8;
          int C_COUNTER = 0;
          int P_COUNTER = 0;
}

using namespace Panda_BATTLESHIP_N;

class BattleShip {
    private:
        P_STATUS L_Grid[64];
        int W_SGrid[8][8]; // Grid for player's ships.
        int W_OGrid[8][8]; // Grid for player's bombs.
        int W_AIGrid[8][8]; // Grid for AI's ships.
        int W_AIOGrid[8][8]; // Grid for AI's bombs.
        int x;
        int y;
        int x_axis;
        int y_axis;
        int CT_Ships; // Counter of the amount of player ships hit.
        int CTAI_Ships; // Counter of the amount of computer ships hit.
        int pos;
        bool isFree;
        bool isWon;


    struct B_Position {
        int x_axis;
        int y_axis;
        int player;
        int isFree;
    };
    B_Position Position[64];

    public: //Function Prototypes.
        ~BattleShip();
        //int SetBoard();
        int PrintGrid();
        int PrintAIGrid(); // for Testing purposes, prints out Computer's grid.
        int Won();
        int ShipPlace(int);
        int MakeMove(int, string, int);
        int Convert(int, int);
        int _Set();
        int ShipsLeft(int);
        int isVictorious();
        int Final_BP();
        string StrSet(int);
        string CharToString(int);
        string MakeMove_AI();


};

int BattleShip::_Set() {
    pos = 0;

    for (int y = 0; y < 8; y++) {
        for (int x = 0; x < 8; x++) {
            W_SGrid[y][x] = 0;
            W_OGrid[y][x] = 0;
            W_AIGrid[y][x] = 0;
            W_AIOGrid[y][x] = 0;
            //Note to self: if it errors take these out.
            L_Grid[pos].x_axis = x;
            L_Grid[pos].y_axis = y;
            L_Grid[pos].Human_P.SHIP_STATUS = 0;
            L_Grid[pos].Human_P.w_player = P_1;
            L_Grid[pos].AI_P.SHIP_STATUS = 0;
            L_Grid[pos].AI_P.w_player = P_2;
            pos++;
        }
    }
}

int BattleShip::PrintGrid() {

    cout << "Player Grids\n\n";
    //Fix these two lines to add width specifications.
    cout << "   \t   Your Bombs:\t\t\t   Your Armada:\n\n";
    for(int y = 0; y < 8; y++){
                cout << "  " << y + 1 << "\t";
                for(int x = 0; x < 8; x++){
                    cout << StrSet(W_OGrid[y][x]) << " ";
                }
                cout << "\t" << y + 1 << "\t";
                for(int x = 0; x < 8; x++){
                    cout << StrSet(W_SGrid[y][x]) << " ";
                }
                cout << endl;
                }

            cout << endl << "   \t";
            for(int j = 65; j< 73; j++){
                cout << char(j) << " ";
            }
            cout << "\t\t";
            for(int k = 65; k < 73; k++){
                cout << char(k) << " ";
                }
                cout << endl;
                cout << endl << "\tAI Ships Left: " << BattleShip::ShipsLeft(P_2);
                cout << "\t\tHuman Ships Left: " << BattleShip::ShipsLeft(P_1);
                return 0;
}

int BattleShip::PrintAIGrid() { // Prints AI board for testing purposes.
    cout << " Computer Grids\n\n";
    cout << "   \t   Your Bombs:\t\t\t   Your Armada:\n\n";
    for(int y = 0; y < 8; y++){
                cout << "  " << y + 1 << "\t";
                for(int x = 0; x < 8; x++){
                    cout << StrSet(W_AIOGrid[y][x]) << " ";
                }
                cout << "\t" << y + 1 << "\t";
                for(int x = 0; x < 8; x++){
                    cout << StrSet(W_AIGrid[y][x]) << " ";
                }
                cout << endl;
                }

            cout << endl << "   \t";
            for(int j = 65; j< 73; j++){
                cout << char(j) << " ";
            }
            cout << "\t\t";
            for(int k = 65; k < 73; k++){
                cout << char(k) << " ";
                }
                return 0;
}


string BattleShip::StrSet(int value) {
    string hold;

    hold = "";

    switch (value) {
        case 0:
            hold += (char) 247;
            return hold;
            break;
        case 1:
            // Hit. Not really needed in this one. If I edit I'll use it.
            return "^";
            break;
        case 2:
            return "Y"; // Miss.
            break;
        case 3:
            return "X"; // Hit
            break;
        case 4:
            return "M"; //Ship.
            break;
        case 5:
            return "Z";
            break;
        case 6:
            return "#";
        default:
            hold += (char) 247;
            return hold;
            break;
        }
        hold +=(char) 247;
            return hold;
    }


int BattleShip::ShipPlace(int player) {
    int a;
    int b;
    int pos = 0;

    if (player == P_1) {
        for (int x = 0; x < AMT_SHIPS; x++) {
        do{
            a = rand() % GRID_HEIGHT; //GRID_HEIGHT = 8. Defined by #define.
            b = rand() % GRID_WIDTH; // Grid_WIDTH = 8. Defined by #define.
        }while (W_SGrid[a][b] != 0);
            // Idea for Structs came from Anthony. Tried other methods,
            // this one worked.
            L_Grid[pos].Human_P.SHIP_STATUS = 1;
            W_SGrid[a][b] = 1;
            pos++;
        }
        }

        if (player == P_2) {
        for (int x = 0; x < AMT_SHIPS; x++) {
        do{
            a = rand() % GRID_HEIGHT;
            b = rand() % GRID_WIDTH;
        }while (W_AIGrid[a][b] != 0);
            L_Grid[pos].AI_P.SHIP_STATUS = 1;
            W_AIGrid[a][b] = 1;
            pos++;
        }
    }

    return 0;

}

//Also used some things Anthony showed me when setting ships.
int BattleShip::Convert(int y, int x) {
    for (int j = 0; j < 64; j++) {
        if ((L_Grid[j].x_axis == x)&&(L_Grid[j].y_axis == y)) {
            return j;
        }
    }
    return -1;
}



int BattleShip::MakeMove(int player, string x, int y) {
    int hold;
    int Xvalue;

        if((int(x[0]) >= 97) && (int(x[0]) <= 105)){
            x[0] = toupper(x[0]);
        }

        Xvalue = int(x[0]) - conv;

    if (player == P_1) {
        if (W_AIGrid[y][Xvalue] == 0) {
            W_OGrid[y][Xvalue] = 4;
            W_AIGrid[y][Xvalue] = 4;
            hold = Convert(y, Xvalue);
        if(hold >= 0){
            L_Grid[hold].AI_P.SHIP_STATUS = 4;
            }
        return 0;
        }


        if (W_AIGrid[y][Xvalue] == 1) {
            W_OGrid[y][Xvalue] = 6;
            W_AIGrid[y][Xvalue] = 6;
            hold = Convert(y, Xvalue);
            if(hold >= 0){
            L_Grid[hold].AI_P.SHIP_STATUS = 6;
            }
            return 2;
        }
    }


    if (player == P_2) {
        if (W_SGrid[y][Xvalue] == 0) {
        W_AIOGrid[y][Xvalue] = 4;
        W_SGrid[y][Xvalue] = 4;
        hold = Convert(y, Xvalue);
        if(hold >= 0){
            L_Grid[hold].Human_P.SHIP_STATUS = 4;
                }
            return 0;
            }
        if (W_SGrid[y][Xvalue] == 1) {
            W_AIOGrid[y][Xvalue] = 3;
            W_SGrid[y][Xvalue] = 3;
            hold = Convert(y, Xvalue);
            if (hold >= 0) {
               L_Grid[hold].Human_P.SHIP_STATUS = 3;
            }
            return 2;
        }
    }
    return 3;
}

string BattleShip::CharToString(int value) {
            if(value == 0){
                return "Miss";
            }
            if(value == 1){
                return "Hit";
            }
            if(value == 2){
                return "Sunk";

            }
            if(value == 3){
                return "Invalid Move";
            }
            else{
                return "Invalid Move";
            }
        }

int BattleShip::isVictorious() {
    int SHIPS;
    SHIPS = ShipsLeft(P_2);
    if (SHIPS == 0) {
        return 1;
    }
    SHIPS = ShipsLeft(P_1);
    if (SHIPS == 0) {
        return 2;
    }
    return 0;

}

int BattleShip::ShipsLeft(int player) {
    int ShipsCounter = 15;

    if (player == P_1) {
        for (int y = 0; y < 8; y++) {
            for (int x = 0; x < 8; x++) {
                if (W_SGrid[y][x] == 1) {
                    ShipsCounter++;
                }
            }
        }
        return ShipsCounter;
    }

    if (player == P_2) {
        for (int y = 0; y < 8; y++) {
            for (int x = 0; x < 8; x++) {
                if (W_AIGrid[y][x] == 1) {
                    ShipsCounter++;
                }
            }
        }
        return ShipsCounter;
    }
    return 9000;
}


int BattleShip::Final_BP() {

    cout << "   \t   AI Ships:\t\t\t   Your Ships:" << endl << endl;
            for(int y = 0; y < 8; y++){
                cout << "  " << y + 1 << "\t";
                for(int x = 0; x < 8; x++){
                    cout << StrSet(W_AIGrid[y][x]) << " ";
                    //cout << h_charofBoard(AI_Board[y][x]) << " ";
                }
                cout << "\t" << y + 1 << "\t";
                for(int x = 0; x < 8; x++){
                    cout << StrSet(W_SGrid[y][x]) << " ";
                    //cout << h_charofBoard(HP_Board[y][x]) << " ";
                }
                cout << endl;
            }
            cout << endl << "   \t";
            for(int r = 65; r < 73; r++){
                cout << (char)r << " ";
            }
            cout << "\t\t";
            for(int r = 65; r < 73; r++){
                cout << (char)r << " ";
            }
            return 0;
        }

string BattleShip::MakeMove_AI() {
            string hold;
            string Append;
            string a;
            string b;
            int x;
            int y;
            int counter;

            Append = "";
            counter = 0;

            do{
                do{
                    counter++;
                    x = rand() % 8;
                    y = rand() % 8;
                    x += 65;
                    Append += (char)x;
                    if(counter == 15){
                        break;
                    }
                }while(W_AIOGrid[y][x] != 0);
                if(counter < 15){
                    hold = CharToString(MakeMove(P_2, Append, y));
                }

    }while (hold == "Invalid Move");
    return hold;
}

#endif