// Programación en C++ para Ingenieros, Ed. Thomson Paraninfo, 2006
// Capitulo 6: Tipos Estructurados

// Programa que dados el nombre, los dos apellidos, el número del DNI,
// la letra del DNI y la cuota de los socios de un club de ajedrez,
// permite consultar, dar de alta y dar de baja a los socios.

// Inclusión de bibliotecas
#include <iostream>
#include <string>

using namespace std;

// Definición de constantes
const int N = 15;   // Las palabras tienen un máximo de N caracteres
const int M = 1000; // Hay un máximo de M vecinos


// Definición de tipos
typedef char tNombre[N+1];

// El nombre completo lo forman el nombre y los dos apellidos
struct tNombreCompleto
{
  tNombre nombre, apellido1, apellido2;
};

// El DNI esta formado por el número y la letra correspondiente
struct tNIF
{
  long int numero;
  char     letra;
};

// La fecha de alta de un socio contiene el día, el mes y el año
struct tFecha
{
  int dia, mes, ano;
};

// Cada socio tiene el nombre completo, el DNI y una cuota
struct tSocio
{
  tNombreCompleto nombre;
  tNIF            dni;
  tFecha          fecha;
  float           cuota;
};

// Hay un máximo de M socios
typedef tSocio tDatos[M];

// Para saber en todo momento el número de socios consideramos
// una tabla parcialmente llena
struct tDatosCompletos
{
  tDatos socios;
  int    numero;
};

// Declaración de acciones y funciones

// Se leen los datos de un sólo socio y devuelve falso si es el centinela
bool LeerUnSocio(tSocio &socio);

// Se leen los datos de todos los socios hasta encontrar el centinela
void LeerSocios(tDatosCompletos &datos);

// Se muestran las posibles opciones arbitrarias del menu
void MuestraMenu();

// Consulta los datos de un socio
void ConsultarUnSocio(const tSocio & socio);

// Consultar los datos de los todos los socios
void ConsultarSocios(const tDatosCompletos &datos);

// Buscamos el NIF aux en la tabla datos de la tupla datos
int BuscarIndiceSocio(const tNIF &aux, const tDatosCompletos &datos);

// Alta de un nuevo socio
void AltaSocio(tDatosCompletos &datos);

// Se copian los datos de a en b
void CopiarSocio(tSocio &b, const tSocio &a);

// Baja de un socio
void BajaSocio(tDatosCompletos &datos);

// Programa principal
int main()
{
  // Declaración de variables
  tDatosCompletos datos;
  bool continuar = true;
  int opcion;

  cout << "Entre los datos de los socios, " << endl;
  cout << "<Nombre> <1rApellido> <2oApellido> <numNIF> <letraNIF> <dia> <mes> <ano> <Cuota>, " << endl;
  cout << "y finalice con X X X -1 -1 -1 -1:" << endl;
  LeerSocios(datos);

  while (continuar)
  {
    MuestraMenu();
    cin >> opcion;
    switch (opcion)
    {
      case 0: ConsultarSocios(datos); break;
      case 1: AltaSocio(datos); break;
      case 2: BajaSocio(datos); break;
      case 3: cout << "Fin." << endl;
              continuar = false; break;
      default: cout << "No has entrado ninguna opcion valida.";
               cout << endl << "Fin." << endl;
               continuar = false; break;
    }
  }

  return 0;
}

// Definición de las acciones y funciones
bool LeerUnSocio(tSocio &socio)
{
  // {PRE: Las palabras tienes un máximo de N caracteres}
  cin >> socio.nombre.nombre;
  cin >> socio.nombre.apellido1;
  cin >> socio.nombre.apellido2;
  cin >> socio.dni.numero;
  cin >> socio.dni.letra;
  cin >> socio.fecha.dia;
  cin >> socio.fecha.mes;
  cin >> socio.fecha.ano;
  cin >> socio.cuota;

  return ( socio.cuota != -1 );
}

void LeerSocios(tDatosCompletos &datos)
{
  int i = 0;
  while ( LeerUnSocio(datos.socios[i]) ) i = i + 1;
  datos.numero = i; // Inicialiazamos el número de socios
}

void MuestraMenu()
{
  cout << "0.- Consulta de socios" << endl;
  cout << "1.- Alta de socio" << endl;
  cout << "2.- Baja de socio" << endl;
  cout << "3.- Salir" << endl;
};

void ConsultarUnSocio(const tSocio &socio)
{
  cout << '\t' << socio.nombre.nombre << ' ';
  cout << socio.nombre.apellido1 << ' ';
  cout << socio.nombre.apellido2 << '\t';
  cout << socio.dni.numero << ' ';
  cout << socio.dni.letra << '\t';
  cout << socio.fecha.dia << ' ';
  cout << socio.fecha.mes << ' ';
  cout << socio.fecha.ano << '\t';
  cout << socio.cuota << endl;
}

void ConsultarSocios(const tDatosCompletos &datos)
{
  int i = 0;

  while ( i < datos.numero )
  {
    ConsultarUnSocio( datos.socios[i] );
    i++;
  }
}

void AltaSocio(tDatosCompletos &datos)
{
  tSocio nuevosocio;
  int    i;

  cout << "Por favor, entre los datos " << endl;
  cout << "(<Nombre> <1rApellido> <2oApellido> <nNIF> <lNIF> <dia> <mes> <ano> <cuota>): " << endl;

  LeerUnSocio(nuevosocio);
  // Comprobamos si ya era socio
  i = BuscarIndiceSocio(nuevosocio.dni, datos);
  if ( i == -1 )
  {
    // No era socio
    CopiarSocio(datos.socios[datos.numero], nuevosocio);
    (datos.numero)++;
  }
  else
    cout << "Ya existe un socio con el mismo NIF.\n";
}

// Para comprobar si alguien ya es socio es suficiente con comparar el NIF.
// Se devuelve el índice de la tabla socios de la tupla datos correspondiente al NIF aux,
// si no es socio se devuelve -1.
int BuscarIndiceSocio(const tNIF &aux, const tDatosCompletos &datos)
{
  int i = 0;

  while ( ( i < datos.numero ) &&
          !( datos.socios[i].dni.numero == aux.numero &&
             datos.socios[i].dni.letra == aux.letra ) )
    i++;
  if (i == datos.numero) i = -1;

  return i;
}

// Se copian los datos de a en b
void CopiarSocio(tSocio &b, const tSocio &a)
{
  strcpy(b.nombre.nombre,    a.nombre.nombre);
  strcpy(b.nombre.apellido1, a.nombre.apellido1);
  strcpy(b.nombre.apellido2, a.nombre.apellido2);

  // Asignación directa entre tuplas
  b.dni   = a.dni;
  b.fecha = a.fecha;

  b.cuota = a.cuota;
}

// Para dar de baja a un socio lo buscamos en la tabla
// y ponemos el último socio en su lugar
void BajaSocio(tDatosCompletos &datos)
{
  int i = 0; tNIF aux;

  cout << "Por favor, entre el DNI (numero y letra): ";
  cin >> aux.numero >> aux.letra;

  i = BuscarIndiceSocio(aux, datos);

  if ( i == -1 )
    cout << "Este NIF no corresponde a ningun socio" << endl;
  else
  {
    CopiarSocio(datos.socios[i], datos.socios[datos.numero-1]);
    (datos.numero)--;
    cout << "Socio dado de baja" << endl;
  }
}