// Prof Simão - DAINF/UTFPR - Ctba - TecProg S71 - 1 Sem 2026 - 1a Parcial
// Hah couts e elses suplementares para fins de entendimento da execução.

#include <iostream>
#include <list>
#include <vector>
using namespace std;

#include <stdlib.h>
#include <time.h>
#include <Windows.h>

//classe base abstrata

namespace ETs
{
class Alien
{
    private:
        static long int cont_id;
        long int id;

    protected:
        bool tardio;

    public:
        Alien():id (cont_id++), tardio(false) { }

        virtual ~Alien(){ //cout << "Destruindo o alien de número: " << id << endl; // << endl;
            id = -1;
        }

        virtual void agir() = 0;

        const int getId () const { return (const int)id;}

        static void sementear() {
            rand(); Sleep(100); time_t t;       // https://pt.wikipedia.org/wiki/Time_t
            srand((unsigned) time(&t)); rand(); // Para função srand e rand vide: https://www.tutorialspoint.com/c_standard_library/c_function_srand.htm
        }
};
long int Alien::cont_id(0);

// Classe para Huma(noide) derivada de Alien.
class Huma : public Alien
{
    private:
        int energia;
        static list<Huma*> equipe;
        static const short int max_equipe;

    public:

        Huma(): Alien(), energia( 0 )
        {
            sementear(); // Alien::sementear();
            energia = ( ( rand()%100 ) + 1 ) * getId();
            conhecer(this);
        }

        ~Huma()
        {
            if (!equipe.empty())
            if (!tardio)
            {
                list<Huma*>::iterator it;
                it = equipe.begin();
                while (it != equipe.end()){
                    if (*it){
                        if ((*it)->tardio){
                            cout << "Deletando tardio: " <<  (*it)->getId() << endl;
                            delete *it;
                            *it = NULL;
                        }
                    }
                    it++;
                }
            }
            equipe.remove(this);
            energia = -1;
        }

        void agir()
        {
            if (energia>0) energia--;

            if ( getTamEquipe() < max_equipe ) {
                sementear(); //Alien::sementear();
                if ( ! ( rand()%10 ) )
                {
                    Huma* pH = NULL;
                    pH = new Huma();
                    if (pH) {  pH->tardio = true;}
                    else { cerr << "Huma(noide) não alocado!" << endl; }
                } //else { cout << "Humanopide tarido não criado" << endl; }
            }else { cout << "Equipe já completa!" << endl; }
        }

        static const int getTamEquipe() { return (int)equipe.size(); }

        static void conhecer(Huma* p) {
            if (p)
               if ( getTamEquipe() < max_equipe )
                equipe.push_back(p);
        }

        static const int retirar(const float forca)
        {
            cout << "Retirando (primeiro) elemento da equipe!" << endl;

            if (equipe.empty()) { return 0; }

            Huma* p = NULL;
            p = equipe.front();
            equipe.pop_front();

            if (!p) { cout << "Ponteiro Nulo!" << endl; return 0; }

            int reg = p->energia; // Aqui se acessa atributo privado pois está no âmbito da mesma classe.
            p->energia = 0;       // Idem.

            if (p->tardio) delete p;

            if (forca > (float)reg)
                return reg;
            else
                return 0;
        }
};

list<Huma*> Huma::equipe;

const short int Huma::max_equipe(15);

// Classe para Reptialiano derivada de Alien.
class Rept : public Alien
{
    private:
        bool pacifico;
        float forca;

    public:

        Rept(float f = 0.0) : Alien(), pacifico(true), forca(f)
        {
            sementear(); pacifico = (rand()%10)< 7;
            if ( f < 50) { f = 50; } else if ( f > 150) { f = 150; }
        }

        ~Rept() { forca = -1; }

        void agir()
        {
           sementear();
           if ( !((bool)rand%100) ) { pacifico = !pacifico; }
           if (!pacifico) { forca += (float)Huma::retirar(forca); }
        }
};
} using namespace ETs;

class V_ALs
{
    private:

        vector<Alien*> aliens;
        vector<Alien*>::iterator it;

    public:

        V_ALs() : aliens(), it(aliens.begin())
        {
            aliens.clear();
            primeiro();
            criarHumas();
            criarRepts();
        }

        ~V_ALs()
        {
            if (!aliens.empty())
            for (int i = 0; i < (int)aliens.size(); i++)
            {
                if (aliens[i])
                {
                    delete aliens[i];
                    aliens[i] = NULL;
                }
            }
            aliens.clear();
            primeiro();
        }

    private:

        void criarHumas()
        {
            int max = 10;
            for (int i = 0; i < max; i++)
            {
                Huma* pH = NULL;
                pH = new Huma();
                if (pH) {
                    aliens.push_back(static_cast<Alien*>(pH));
                    //Huma::conhecer(pH);
                }
                else { cerr << "Huma não pode ser criado!" << endl; }
            }
        }

        void criarRepts()
        {
            int max = 2;
            for (int i = 0; i < max; i++)
            {
                Rept* pR = NULL;
                Alien::sementear();
                float v = (float)(rand()%100);
                pR = new Rept(v+51.0);
                if (pR) { aliens.push_back(static_cast<Rept*>(pR)); }
                else { cerr << "Rept não pode ser criado!" << endl; }
            }
        }

    public:

        void primeiro()
        {
            it = aliens.begin();
        }

        bool operator++()
        {
            if (it != aliens.end())
            {
                if (*it) {
                    cout << "Alien de id " << (*it)->getId() << " agindo!" << endl;
                    (*it)->agir();
                }
                it++;
                return true;
            }
            else
            {
                return false;
            }
        }
};

class Nave {
    private:
       V_ALs v;

    public:

        Nave(): v() { v.primeiro(); }

        ~Nave()
        {
            cout << "A quantidade de elemento da equipe de Humas eh: " << Huma::getTamEquipe() << endl;
        }

        void executar()
        {
            v.primeiro();

            bool ok = true;
            do{
                ok = v.operator++();
            }while(ok);
        }
};

int main()
{
    Nave n;
    n.executar();

    cout << endl;
    cout << "FIM" << endl;

    return 0;
}

