/* biblioteca.cpp - Definiciones de los métodos
 * de la clase CBiblioteca
 */
#include <iostream>
#include "biblioteca.h"   // clase CBiblioteca
#include "fichalibro.h"   // clase CFichaLibro
#include "fichavolumen.h" // clase CFichaVolumen
#include "ficharevista.h" // clase CFichaRevista
using namespace std;

/////////////////////////////////////////////////////////////////
// Constructor
CBiblioteca::CBiblioteca(int n)
{
  if (n < 0) n = 1;
  ficha.reserve(n);
}

CBiblioteca::~CBiblioteca()
{
  for (int i = 0; i < ficha.size(); i++)
  {
    delete ficha[i];
  }
}

// Indexación
CFicha *CBiblioteca::operator[](int i)
{
  if (i >= 0 && i < ficha.size())
    return ficha[i];
  else
  {
    cout << "error: índice fuera de límites\n";
    return 0;
  }
}

// Asignar un objeto al array
void CBiblioteca::AnyadirFicha(CFicha *pficha)
{
  ficha.push_back(pficha->Clonar());
}

// Extraer un objeto
ostream& operator<<(ostream& os, CFicha *pficha)
{
  os << "Referencia........ " << pficha->ObtenerReferencia() << '\n';
  os << "Título............ " << pficha->ObtenerTitulo() << '\n';  
  if (CFichaLibro *p = dynamic_cast<CFichaLibro *>(pficha))
  {
    os << "Autor............. " << p->ObtenerAutor() << '\n';
    os << "Editorial......... " << p->ObtenerEditorial() << '\n';
  }
  if (CFichaVolumen *p = dynamic_cast<CFichaVolumen *>(pficha))
    os << "Nro. de volumen... " << p->ObtenerNroDeVolumen() << '\n';
  if (CFichaRevista *p = dynamic_cast<CFichaRevista *>(pficha))
  {
    os << "Nro. de la revista " << p->ObtenerNroDeRevista() << '\n';
    os << "Año de publicación " << p->ObtenerAnyo() << '\n';
  }
  return os;
}

int CBiblioteca::longitud()
{
  return ficha.size();
}

// Visualizar todos los objetos
void CBiblioteca::VisualizarFichas()
{
  if (!ficha.size()) 
  {
    cerr << "Error: biblioteca vacía\n";
    return;
  }
  for (int i = 0; i < ficha.size(); i++)
  {
    cout << ficha[i];
    cout << endl;
  }
}

CBiblioteca::CBiblioteca(const CBiblioteca& x)
{
  *this = x; // invoca al operador de asignación
}

CBiblioteca& CBiblioteca::operator=(const CBiblioteca& x)
{
  // Eliminar las fichas del objeto CBiblioteca destino (*this)
  if (ficha.size())
  {
    for (unsigned int i = 0; i < ficha.size(); i++)
      delete ficha[i];
    // Eliminar todos los elementos de la matriz ficha
    ficha.clear();
  }
  // Copiar la biblioteca origen, x, en la biblioteca destino
  for (unsigned int i = 0; i < x.ficha.size(); i++)
    ficha.push_back(x.ficha[i]->Clonar());
  return *this;
}

bool CBiblioteca::eliminar(string refe)
{
  // Buscar la ficha y eliminar el objeto
  for (unsigned int i = 0; i < ficha.size(); i++)
    if (refe == ficha[i]->ObtenerReferencia())
    {
      delete ficha[i];
      ficha.erase(ficha.begin()+i);
      return true;
    }
  return false;
}

int CBiblioteca::buscar(string str, int pos)
{
  // Buscar un objeto y devolver su posición
  string titu, refe;
  if (str.empty()) return -1;
  if (pos < 0) pos = 0;
  for (unsigned int i = pos; i < ficha.size(); i++)
  {
    // Buscar por el título
    titu = ficha[i]->ObtenerTitulo();
    if (titu.empty()) continue;
    // ¿str está contenida en titu?
    if (titu.find(str) != string::npos)
      return i;
    // Buscar por la referencia
    refe = ficha[i]->ObtenerReferencia();
    if (refe.empty()) continue;
    // ¿str es la referencia?
    if (str == refe)
      return i;
  }
  return -1;
}


