#include <iostream>
#include <string>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;

///////////////////////////////
//       Declarations        //
///////////////////////////////
void banner (string name, string type = "\\", int size = 40);
class character{
public:
    character();                    // Constructor
    bool operator== (character);    // use when comparing init of objects
    bool operator< (character);
    bool operator> (character);
    string getname ()const ;        // return name of object
    string getname ();
    int getinit () const;           // return init of object
    int getinit ();
    void set_init (int a);          // set init of object to 'a'
    void heal_full();               // max out hp and 0 nl dam
    void heal(int amt);             // modify hp by given amount
    void heal_nl (int amt);         // heal nl dam by given amount
    void dam_nl (int amt);          // give nl dam by given amount, checks for disabled or unconscious state.
    int getHP();                    // return current hp
    int getnlDam();                 // return nl dam
    void SetnMob (character* nmob); // Sets next mob
    character* GetnMob ();          // Gets the address of next mob.

private:
    string name;            // name of character
    int mHP;                // max hit points
    int HP;                 // current hit points
    int nlDam;              // amount of non lethal damage object currently has
    int init;               // initiative of character
    character* nextMob;     // points to next mob to iterate to
};
class encounter{
public:
    encounter (character*, int);        // Constructor
    void listFull ();
private:
    int ENEMIES;                        // number of enemies in this encounter
    character enemy[];                  // array of all enemies in encounter
    character* holding[];               // array of pointers to all mobs currently holding turn
    character* player;                  // pointer to array of player mobs
    character* firstMob;                // pointer to highest init mob
    void setInits (character ary[], int arraySize);
    character* sortAryLL (character* ary[], int arraySize);
};
void rebuildCharArray (character arry[], int size){
    delete[] arry;
    arry = new character[size];
}
///////////////////////////////
//        Main Function      //
///////////////////////////////
int main(){
    int input = 1;
    string select;
    int PLAYERS;
    banner ("COMBAT HELPER", "=");
    cout << "Welcome to D&D Combat Helper.\n"
         << "Lets begin by adding all players.\n"
         << "How many players are there?";
    cin  >> PLAYERS;
    character* player = new character[PLAYERS];


//////////////////////////////////
//          MAIN MENU           //
//////////////////////////////////

while (input != 0)
{
    banner ("MAIN MENU");

    cout << "\nPlease select from the following options:\n"
    << "1. (Re)build all players\n"
    << "2. Start a new encounter\n"
    << "3. Reset all player's health\n"
    << "0. Quit\n";
    cin >> input;
    switch (input)
  {
    case 1: //New players
    {
    break;
    };
    case 2: //new fight
    {
        encounter crnt_enco (player, PLAYERS);
        break;
    };
    case 3: //Heal players
    {
        cout << "All players restored to full health";
        break;
    };
    case 0: // quit
    {
        cout << "Thank you for using D&D Combat Helper.\nHave a nice day.";
        break;
    };
    default: // incorrect input
    {
        cout << "Invalid selection, please try again.";
        break;
    };
  }; // Switch end
}; //While end

}
///////////////////////////////
// Misc Function Definitions //
///////////////////////////////
void banner (string name, string type, int size){
    cout << endl;
    for (int i=0; i < size; i++)    { cout << type; };

    cout << "\n" << type << type
    << setw (((size-4)/2) + ((name.size())/2) /*- (name.size()%2)*/ ) << name
    << setw (((size-4)/2) - ((name.size())/2) + (name.size()%2))
    << type << type << "\n";

    for (int i=0; i < size; i++)    { cout << type; };
    cout << endl;
};
///////////////////////////////
//      character class      //
///////////////////////////////
character::character() {
    string select;
    cout << "\nCreating new character.\nWhat is their name?";
    cin >> name;
    cout << "\nWhat is their max HP?";
    cin >> mHP;
    cout << "Are they currently injured? (y/n)";
    cin >> select;
    if (select == "y"){
        cout << "What is their current HP?";
        cin >> HP;
        cout << "How much non-lethal damage do they currently have?";
        cin >> nlDam;
        }
    else{
        HP = mHP;
        nlDam = 0;
    };
    init = 1;
};
bool character::operator== (character b) {return init == b.init;}
bool character::operator> (character b) {return init > b.init;}
bool character::operator< (character b) {return init < b.init;}
string character::getname () const { return name; }
string character::getname () { return name; }
int character::getinit () const { return init; }
int character::getinit () { return init; }
void character::set_init (int a) { init = a; }
void character::heal_full() {
    HP = mHP;
    nlDam = 0;
};
void character::heal(int amt) { HP += amt; }
void character::heal_nl (int amt) {
    if (nlDam < 0)
    {
        nlDam -= (amt - nlDam);
        cout << name << "now has "<< nlDam << " non lethal damage" << endl;
    }
    else if (nlDam >= 0)
        { cout << name << " has no non lethal damage. No action required" << endl;};

}
void character::dam_nl (int amt) {
     nlDam += amt;
     if ( nlDam == HP )
     {
         cout << name << " is now Staggered, and can only take one standard action.";
     }
     else if (nlDam > HP)
     {
         cout << name << " is now unconscious.";
     }
}
int character::getHP() { return HP; }
int character::getnlDam() { return nlDam; }
void character::SetnMob(character* nmob) { nextMob = nmob;}

///////////////////////////////
//      encounter class      //
///////////////////////////////
encounter::encounter (character players_in[], int PLAYERS ){
    banner ("NEW ENCOUNTER", "*");
    character* high;
    player = players_in;
    cout<< "How many enemies?";
    cin >> ENEMIES;
    enemy[ENEMIES];
    cout<< "Roll for initiative and input for each person or enemy:"
        << "\n(Don't worry about ties, they will be resolved shortly)";
    setInits(player, PLAYERS);       // get players init
    setInits(enemy, ENEMIES);        // get enemies init
    character* highestPlayer = sortAryLL(player&, PLAYERS);
    character* highestEnemy = sortAryLL(enemy&, ENEMIES);
    for (int i = 0; i < PLAYERS; i++) {        // sort players by init w/ linked list
        if (player[i].getinit() > high->getinit() ) {

        }
        else if (player[i].getinit() == high->getinit() ) {

        }
        else if (player[i].getinit() < high->getinit() ) {

        }
    }
    for (int i = 0; i < ENEMIES; i++) {     // sort enemies by init w/ linked list
        if (enemy[i].getinit() > high->getinit() ) {

        }
        else if (enemy[i].getinit() == high->getinit() ) {

        }
        else if (enemy[i].getinit() > high->getinit() ) {

        }
    }
    for ( int i = 0 , j = 0 ; i < PLAYERS && j < ENEMIES ; ) {   //sort all mobs w/ linked list
        if ( player[i] > enemy[j] ) {
            player[i].SetnMob( &enemy[j] );
            i++;
        }
        else if ( player[i] > enemy[j] ) {
            enemy[j].SetnMob( &player[i] );
            j++;
        }
        else if ( player[i] == enemy[j] ) {
            bool a = false;
            while (a == false) {
                cout<< player[i].getname() << " and " << enemy[j].getname()
                    << "are tied. Please roll again and select higher init."
                    << "\n1. " << player[i].getname()
                    << "\n2. " << enemy[j].getname();
                int select;
                cin >> select;
                if (select == 1) {
                    player[i].SetnMob( &enemy[j] );
                    i++;
                    a = true;
                }
                else if (select == 2) {
                    enemy[j].SetnMob( &player[i] );
                    j++;
                    a = true;
                }
                else {
                    cout << "Invalid selection, Please try again";
                }
            }
        }
    }
}
void encounter::setInits (character ary[], int arraySize) {
    for ( int i = 0; i < arraySize; i++) {
        int in;
        cout << ary[i].getname() << ": ";
        cin >> in;
        ary[i].set_init(in);
    }
}
character* encounter::sortAryLL (character* ary[], int arraySize) {
    int iteration = 0;
    int high = 0;
    int i = 0;
    while (iteration < arraySize) {
        if (ary[i]->getinit() < ary[high]->getinit() ) {
            
        }
        else if (ary[i]->getinit() > ary[high]->getinit() ) {
            ary[high]->SetnMob(ary[i]);
        }
        else if ( ary[i]->getinit() == ary[high]->getinit() ) {
            
        }
    }
}
