// articulos.cpp - Definición de la clase CArticulos
#include <iostream>
#include <string>
#include "registro.h"  // clase CRegistro
#include "articulos.h" // clase CArticulos
#include "leerdatos.h"
using namespace std;

/////////////////////////////////////////////////////////////////
// Constructor
CArticulos::CArticulos()
{
  modo = 0;
}

CArticulos::~CArticulos()
{
  if (is_open()) close();
}

void CArticulos::Nuevo(string& nomf) throw(failure)
{
  // Habilitar las excepciones del tipo failure
  clear(); // desactivar los indicadores que haya activos
  exceptions(ios::failbit | ios::badbit);
  // Crear un nuevo fichero
  if (nomf.empty())
    throw failure(string("Especificar un nombre para el fichero"));

  if (is_open()) close(); // cerrar el fichero si está abierto
  modo = 0;
  // Comprobar si el fichero existe
  if (existe(nomf))
  {
    cout << "El fichero " << nomf << " existe. "
         << "¿Desea sobrescribirlo? (s/n): ";
    string resp("n");
    leerDato(resp);
    if (resp == "s")
    {
      // Eliminar todos sus registros
      open(nomf.c_str(), ios::out | ios::trunc);
      close();
    }
  }
  // Abrir el fichero para añadir registros
  open(nomf.c_str(), ios::out | ios::app | ios::binary);
  modo = 2; // añadir
}

void CArticulos::Abrir(string& nomf) throw(failure)
{
  // Habilitar las excepciones del tipo failure
  clear(); // desactivar los indicadores que haya activos
  exceptions(ios::failbit | ios::badbit);
  // Abrir un fichero
  if (nomf.empty())
    throw failure(string("Especificar un nombre para el fichero"));

  if (is_open()) close(); // cerrar el fichero si está abierto
  modo = 0;
  // Opciones del menú
  static char *opciones[] = 
  { 
    "leer y escribir",
    "añadir",
  };
  int op, nOpciones = sizeof(opciones)/sizeof(char*);

  if ((op = menu(opciones, nOpciones)) == 1) // leer y escribir
    open(nomf.c_str(), ios::in | ios::out | ios::binary);
  else // añadir
    open(nomf.c_str(), ios::out | ios::app | ios::binary);
  modo = op;
}

void CArticulos::Agregar() throw(failure)
{   
  // Habilitar las excepciones del tipo failure
  clear(); // desactivar los indicadores que haya activos
  exceptions(ios::failbit | ios::badbit);
  // Escribir registros en un fichero
  if (modo != 2)
    throw failure(string("Abrir el fichero para añadir"));

  CRegistro reg;
  int tm = sizeof(reg);
  char ref[30];
  float pre;
   
  cout << "\nIntroducir datos. Para finalizar, "
       << "responder \"fin\" a Referencia:.\n\n";
  while(true)
  {
    cout << "Referencia: "; leerDato(ref);
    if (!strcmp(ref, "fin")) break;
    cout << "Precio:     "; leerDato(pre);
     
    reg.AsignarRegistro(ref, pre);
    write(reinterpret_cast<char *>(&reg), tm);
  }
}

float CArticulos::Buscar(string& str)
{
  // Deshabilitar las excepciones del tipo failure
  exceptions(ios::goodbit);
  // Buscar un registro en el fichero
  if (modo != 1)
  {
    cout << "Abrir el fichero para leer y escribir\n";
    return -1;
  }
  CRegistro reg;
  seekg(0, ios::beg); // situarse al principio
  
  int tm = sizeof(reg);
  char ref[30];
  // Buscar un artículo y devolver el precio
  string refe;
  if (str.empty()) return false;
  while (read(reinterpret_cast<char *>(&reg), tm))
  {
    // Buscar por la referencia
    refe = string(reg.ObtenerReferencia(ref));
    if (refe.empty()) continue;
    // ¿str es la referencia?
    if (str == refe)
      return reg.ObtenerPrecio();
  }
  clear(); // desactivar eofbit y failbit
  return -1;
}

bool CArticulos::existe(string& nombf)
{
  // Deshabilitar las excepciones del tipo failure
  exceptions(ios::goodbit);
  // Intentar abrir el fichero para leer
  open(nombf.c_str(), ios::in);
  if (fail())
  {
    clear();
    return false;
  }
  close();
  return true;
}

void CArticulos::Modificar() throw(failure)
{
  // Habilitar las excepciones del tipo failure
  clear(); // desactivar los indicadores que haya activos
  exceptions(ios::failbit | ios::badbit);

  if (modo != 1)
    throw failure(string("Abrir el fichero para leer y escribir"));

  // Modificar un registro
  CRegistro reg;
  int tm = sizeof(reg); // tamaño del registro
  // Calcular el número de registros
  seekp(0L, ios::end);
  long totalreg = tellp() / tm;

  // Solicitar el número de registro a modificar  
  long nreg, desp;
  do
  {
    cout << "\nNúmero de registro entre 1 y " << totalreg
         << " (0 para salir): ";
    leerDato(nreg);
    if (nreg > 0 && nreg <= totalreg)
    {
      desp = (nreg - 1) * tm;
      seekg(desp, ios::beg);  // posicionarse
      read(reinterpret_cast<char*>(&reg), tm ); // leer el registro
      cout << endl << reg; // mostrar el registro leído

      // Modificar el dato referencia, precio, ambos o ninguno
      // Opciones del menú
      static char *opciones[] = 
      { 
        "referencia",
        "precio",
        "salir y salvar los cambios",
        "salir sin salvar los cambios"
      };
      int op, nOpciones = sizeof(opciones)/sizeof(char*);
      char ref[30];
      float pre;
      do
      {
        cout << "\nModificar el dato:";
        switch(op = menu(opciones, nOpciones))
        {
          case 1: // modificar la referencia
            cout << "Referencia: "; leerDato(ref);
            reg.AsignarRegistro(ref, reg.ObtenerPrecio());
            break;
          case 2: // modificar el precio
            cout << "Precio:     "; leerDato(pre);
            reg.AsignarRegistro(reg.ObtenerReferencia(ref), pre);
            break;
          case 3: // salir y guardar los cambios
            break;
          case 4: // salir sin guardar los cambios
            break;
        }
      }
      while (op != 3 && op != 4);
      if (op == 3)
      {
        seekp(-tm, ios::cur);
        write(reinterpret_cast<char*>(&reg), tm);
      }
    }
    else if (nreg < 0)
      cout << "error: número de registro negativo\n";
  }
  while (nreg != 0);  
}
/////////////////////////////////////////////////////////////////
