// Data: 09/07/2026
// Prof. Dr. Jean M. Simão (DAELN)

//UNIVERSIDADE TECNOLÓGICA FEDERAL DO PARANÁ - Campus de Curitiba
//(Brasil) - Departamento Acadêmico de Informática (DAINF).

#include <iostream>
#include <string>
using namespace std;

//(Questão - 1)
class Nave                        // Classe abstrata Nave;
{
    protected:
        string numero;      // Atributo alfanumérico;
    public:
        Nave() : numero ("") { }
        virtual ~Nave() { } // virtual por precaução, pois no quadro dado aqui nesta solução não precisaria...

        void setNumero(const string n) { numero = n;    }
        const string getNumero() const { return numero; }

        virtual void informe_natureza() const = 0;
};

// (Questão - 2)
// Atenção a questão que pede simplesmente encadeada... List da STL é duplamente encadeada...
class Lista_Naves
{
    private:
    // até não precaria ser aninhada, mas é boa prática
    class Elemento
    {
        private:
            Elemento* pprox;
            Nave* pinfo;

        public:
            Elemento() { pprox = NULL; pinfo = NULL; }
            ~Elemento() { pprox = NULL; pinfo = NULL; }

            void setProx( Elemento* pp) { pprox = pp; }
            Elemento* getProx() const { return pprox; }

            void setInfo( Nave* pi) { pinfo = pi; }
            Nave* getInfo() const { return pinfo; }
    };

    private:
        Elemento* pprime;   // Ponteiro para o primeiro elemento da lista simplesmente encadeada;
        Elemento* patual;   // Ponteiro para elemento atual (último) da lista simplesmente encadeada;
        int qtdde;          // Atributo que indica quantos elementos há na lista.

    public:
        Lista_Naves() : pprime(NULL), patual(NULL), qtdde (0)   { }

        ~Lista_Naves()
        {
            Elemento* paux = NULL;
            paux = pprime;

            while (paux != NULL){
                pprime = pprime->getProx();
                paux->setProx(NULL);
                paux->setInfo(NULL);
                delete (paux);
                paux = pprime;
            }
            pprime = NULL;
            patual = NULL;
            cout << endl << endl << "Lista Limpa!" << endl;
            qtdde = 0;
         }

         void incluir(Nave* P)     // Método para incluir uma Nave.
         {
            if (NULL != P)
            {
                Elemento* paux = NULL;
                paux = new Elemento();

                if (paux) paux->setInfo(P);

                qtdde++;


                if (NULL == pprime)
                {
                    pprime = paux;
                    patual = paux;
                }
                else
                {
                    patual->setProx(paux);
                    patual = paux;
                }
            }
         }

         void excluir( int pos = -1)
         {
            if (pos == -1) { pos = qtdde; }

            Elemento* paux = NULL;
            paux = pprime;

            short int cont = 1;

            while (cont < (pos - 1))
            {
                paux = paux->getProx();
                cont++;
            }

            if (pos == 1)
            {
                pprime = paux->getProx();
                paux->setProx(NULL);
                delete (paux);
            }
            else
            {
                Elemento* paux2 = NULL;
                paux2 = paux->getProx();
                paux->setProx(paux2->getProx());
                paux2->setProx(NULL);
                delete (paux2);
            }
            qtdde--;
         }

         void listar() const   // Método para listar a natureza Naves.
         {
            if (pprime != NULL)
            {
                Elemento* paux = NULL;
                paux = pprime;
                int Posicao = 1;

                while (paux != NULL)
                {
                    cout<< " " << Posicao << " - ";
                    (paux->getInfo())->informe_natureza();
                    cout<<endl;
                    paux = paux->getProx();
                    Posicao++;
                }
            }
            else cout << "Lista Vazia!" << endl << endl;
         }
};

// (Questão - 3)
class Aviao : public Nave
{
  private:
          bool supersonico;

  public:
          Aviao(): Nave(), supersonico (false)  { }
          ~Aviao() {supersonico = false; }

          void setSupersonico(const bool S) { supersonico = S; }
          const bool getSupersonico() const { return supersonico; }

          void informe_natureza() const { cout  <<  "Transporte Aereo" << endl; }
};

class Navio : public Nave
{
  private:
          int capacidade;

  public:
          Navio(): Nave(), capacidade(0)  { }
          ~Navio() { capacidade = -1; }

          void setCapacidade(const int C) { capacidade = C; }
          const int getCapacidade() const {return capacidade; }

          void informe_natureza()  const
          {
               cout << "Transporte Aquatico" << endl;
          }

          const bool operator== (const Navio& N) const
          {
            if (  ( getCapacidade() == N.getCapacidade() ) &&
                  ( getNumero()     == N.getNumero()     )    )
            {
                return true;
            }
            else
            {
                return false;
            }
          }
};

// (Questão - 4)
// Singleton na classe, mas poderia ser sem ele.
class Principal
{
  private:
           Lista_Naves LN;         //  Lista de Naves para armazenar Avioes e Navios
           Aviao A1, A2;
           Navio N1, N2;

           static Principal* p;

  private:

           Principal(): LN(), A1(), A2(), N1(), N2()
           {
                A1.setNumero("TecoTeco01");
                A1.setSupersonico( false );
                incluir_aviao(&A1);

                A2.setNumero("F15");
                A2.setSupersonico( true );
                incluir_aviao(&A2);;

                N1.setNumero("Canoa1");
                N1.setCapacidade(2);
                incluir_navio(&N1);

                N2.setNumero("Galeao1");
                N2.setCapacidade(50);
                incluir_navio(&N2);
           }

    public:

           ~Principal()
           {
           }

           void incluir_aviao (Aviao * pa) // Método para armazenar aviões na lista;
           {
               if (pa)
               {
                  Nave* pN = NULL;
                  pN = static_cast<Nave*>(pa);
                  LN.incluir(pN);
               }
               else
               {
                  cout << "Erro"  << endl;
               }
           }
           void incluir_navio (Navio* pn) // Método para armazenar navios na lista;
           {
               if (pn)
               {
                  Nave* pN = NULL;
                  pN = static_cast<Nave*>(pn);
                  LN.incluir(pN);
               }
               else
               {
				 cout << "Erro"  << endl;
               }
           }

           void executar()
           {
                // Os metodos incluir_navio e incluir_aviao já foram exercitados antes na construtora...

                cout  << "---------------------------------------------------------"
                      << "\n                   NAVES \n"
                      << "---------------------------------------------------------\n\n";

                LN.listar();

                if (N1 == N2)
                {
                    cout << endl << "A nave 1 eh igual a nave 2";
                }
                else
                {
                    cout << endl << "A nave 1 eh diferente da nave 2";
                }

                cout << endl << endl << endl;

                cout << "Excluir ultimo" << endl << endl;
                LN.excluir();
                LN.listar();

                cout << endl << endl;

                cout << "Excluir posicao 1:" << endl << endl;

                LN.excluir(1);
                LN.listar();

                cout << endl << endl;
           }

           static Principal* getPrincipal()
           {
               if (!p)
               {
                   p = new Principal();
               }
               return p;
           }
};

Principal* Principal::p = NULL;

int main()
{
    Principal* pObjPrincipal = NULL;
    pObjPrincipal = Principal::getPrincipal();

    if (pObjPrincipal)
    {
        pObjPrincipal->executar();
        delete  pObjPrincipal;
    }

    system ( "PAUSE" );

    return 0;
}

// (Questão - 5) - vide diagrama de classes, feito antes do códgio, naturalmente.
