// Data: 07/07/2025
// Prof. Dr. Jean M. Simão

//UNIVERSIDADE TECNOLÓGICA FEDERAL DO PARANÁ - Campus de Curitiba
//(Brasil) - Departamento Acadêmico de Informática (DAINF).

//Disciplina: Técnicas de Programação

#include <iostream>
#include <vector>
using namespace std;

// (Questão - 1)


namespace Universo{
class Ente
{
    protected:
        int massa;

    public:
        Ente(): massa (0)
        {
        }

        virtual ~Ente() { massa = -1; }

        void setMassa(const int m){ if (m>0) massa = m; else massa = 0; }
        const int getMassa() const { return massa; }

        virtual void operator--() { if (massa>0) massa--; }
        void operator++() { massa++; }
};

// (Questão - 2)

class Constelacao : public Ente
{
  private:
    int distancia_buraco;

  public:
    Constelacao(): Ente(), distancia_buraco(0){ }

    ~Constelacao() { distancia_buraco = -1; // cout << "Destrutora Constelacao." << endl; getchar();
    }

    void setDistaciaBuraco(const int db) { distancia_buraco = db; }
    const int getDistanciaBuraco() const { return distancia_buraco ; }

    void operator--() { distancia_buraco--; }
};


// (Questão - 3)
class ZonaGravitacional
{
  private:
    vector<Ente*> vet;

  public:
    ZonaGravitacional(): vet() {
        vet.clear();
        //cout << "Construtora de ZonaGravitacional." << endl; getchar();
    }

    ~ZonaGravitacional(){
        cout << "Destrutora de ZonaGravitacional." << endl; getchar();
        if (!vet.empty()) {
            int TAM = getTamanho();
            for (int i = 0; i < TAM; i++) {
                if (vet[i] != NULL) { delete vet[i]; vet[i] = NULL; }
                //eliminar(i);
            }
            vet.clear();
        }
    }

    void incluir(Ente* P)     // Método para incluir uma Nave.
    {
        if (NULL != P){ vet.push_back(P);}
        else { cout << "Ponteiro de Ente nulo" << endl; }
    }

    Ente* retornar(const int pos) const {
        if (!vet.empty())
            if ( (pos>=0) && (pos < getTamanho()) ) { return vet[pos];}
            else { cout << "Posicao inválida para retorno." << endl; return NULL; }
        else cout << "vetor vazio" << endl;
        return NULL;
    }

    const int getTamanho() const { return (int) vet.size(); }

    void eliminar(const int pos) {
        if (!vet.empty())
            if ( ( pos>=0 ) && ( pos < getTamanho() ) ) {
                Ente* p = vet[pos];
                vet[pos] = NULL;
                if (p!=NULL) delete p;
                else cerr << "Ponteiro nulo" << endl;
                p = NULL;
            }
            else {
                cout << "Posicao inválida para eliminação." << endl;
            }
        else cout << "vetor vazio" << endl;
    }
};

// (Questão - 4)

class BuracoGravitacional : public Ente   //Derivado da classe Nave.
{
    private:
        ZonaGravitacional GB;
        ZonaGravitacional GC;

    public:
        BuracoGravitacional(): Ente(), GB(), GC() { // cout << "Construtora de BuracoGravitacional." << endl; getchar();
        }

        ~BuracoGravitacional(){ cout << "Destrutora de BuracoGravitacional." << endl; getchar(); }

        void operator= (BuracoGravitacional* pBG) {
            if (pBG) {
                GB.incluir(static_cast<Ente*>(pBG)); //cout << "Buraco Gravitacional incluido!" << endl; //getchar();
            }
            else {
                cout << "Ponteiro de BuracoGravitacional (pBG) nulo." << endl;
            }
          }

          void operator= (Constelacao* pC)
          {
              if (pC) {
                  GC.incluir(static_cast<Ente*>(pC));
                  //cout << "Distancia constelacao: " << pC->getDistanciaBuraco() << endl; getchar();
              }
              else {
                  cout << "Ponteiro de Constelacao (pC) nulo." << endl;
              }
          }

          void executar() {
              BuracoGravitacional*  pBG = NULL;
              Constelacao*          pC  = NULL;
              const int NUM_ITERACOES = 100;

              for (int i = 0; i < NUM_ITERACOES; i++)
              {
                  int TAM = GC.getTamanho();
                  cout << "Tamanho Grupo Constelações: " << TAM << endl;
                  for (int j = 0; j < TAM; j++)
                  {
                      pC = static_cast<Constelacao*>(GC.retornar(j));

                      if (pC){
                            pC->operator--();
                            if ( pC->getDistanciaBuraco() <= 0 )
                            {
                                cout << "Distancia constelacao: " << pC->getDistanciaBuraco() << endl;
                                cout << "MASSA DA Constelação sendo consumida :" << pC->getMassa() << endl; //getchar();
                                massa+=pC->getMassa();
                                GC.eliminar(j);
                            }
                            else
                            {
                                //cout << "Distancia constelacao: " << pC->getDistanciaBuraco() << endl;
                                //cout << "Constelação NAO sendo consumida :" << pC->getMassa() << endl; //getchar();
                            }
                      }
                      else
                      {
                           //cout << "Ponteiro pC nulo!" << endl;
                      }

                  }

                  cout << endl;

                  TAM = GB.getTamanho();
                  for (int j = 0; j < TAM; j++)
                  {
                      pBG = static_cast<BuracoGravitacional*>(GB.retornar(j));

                      if (pBG)
                      {
                            if ( pBG->getMassa() < getMassa() )
                            {
                                pBG->operator--();
                                operator++();
                            }

                            if ( pBG->getMassa() <= ( getMassa()/2 ) )
                            {
                                cout << "MASSA DO Buraco gravitacional sendo consumido: " << pBG->getMassa() << endl; //getchar();
                                massa += pBG->getMassa();
                                GB.eliminar(j);
                                //cont++;
                            }
                            else
                            {
                                //cout << "Buraco gravitacional NAO sendo consumido: " << pBG->getMassa() << endl; // getchar();
                            }
                      }
                      else
                      {
                        // cout << "Ponteiro pB nulo!" << endl;
                      }
                  }

                  //cout << "Quantidade de buracos consumidos: " << cont << endl; // getchar();

                  cout << endl;
              }
          }
};

// (Questão - 5)
class Galaxia {
    private:
        Constelacao          *pAuxC;
        BuracoGravitacional  *pMaior, *pMedio, *pMenor;

    public:
        Galaxia(): pAuxC(NULL), pMaior(NULL), pMedio(NULL), pMenor(NULL)
        {
            //cout << "Construtora de Galaxia." << endl; getchar();
            criarBuracosGravitacionais();
            criarConstelacoes();
        }
        ~Galaxia()
        {
            // cout << "Destrutora de Galaxia." << endl; getchar();
            if (pMaior) delete pMaior; pMaior = NULL;
            pMedio = NULL;
            pMenor = NULL;
            pAuxC  = NULL;
        }

        void criarBuracosGravitacionais() {
            pMaior = new BuracoGravitacional();
            if (pMaior)
            {
                pMaior->setMassa(100);

                pMedio = new BuracoGravitacional();
                if (pMedio)
                {
                    pMedio->setMassa(50);
                    pMaior->operator=(pMedio);
                }

                pMenor = new BuracoGravitacional();
                if (pMenor)
                {
                    pMenor->setMassa(5);
                    pMaior->operator=(pMenor);
                }
            }
        }

        void criarConstelacoes(){
            const int max = 100;

            if (pMaior)
            for (int i = 0; i <max; i++)
            {
                pAuxC = NULL;
                pAuxC = new Constelacao();

                if (pAuxC) {

                    pAuxC->setDistaciaBuraco(i + 1);
                    //cout << "Distancia constelacao: " << pAuxC->getDistanciaBuraco() << endl; getchar();
                    pAuxC->setMassa (10*i);

                    pMaior->operator=(pAuxC);
                }
            }

            pAuxC = NULL;
        }

        void executar() {
            if (pMaior) pMaior->executar();
        }
};
} using namespace Universo;

int main()
{
    Galaxia FiatLux;

    FiatLux.executar();

    //system ( "PAUSE" );

    return 0;
}


