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

// Programa que dados el nombre, los apellidos y la edad
// de los habitantes de un barrio, permite hacer consultas
// por nombre, apellido o intervalo de edad.

// 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];

struct tHabitante
{
  tNombre nombre, apellido1, apellido2;
  int edad;
};
typedef tHabitante tDatos[M];

// Declaración acciones y funciones

// Se leen todos los datos hasta encontrar el centinela
void LeerDatos(tDatos datos);

// Lee un sólo dato y devuelve falso si es el centinela
void LeerUnDato(tHabitante &habit);

// Se muestran las opciones del menú
void MuestraMenu();

// Escribe los datos correspondientes
void EscribirUnDato(tHabitante habit);

// Consulta los datos con un determinado nombre (num=0),
// primer apellido (num=1) o segundo apellido (num=2) dado
void ConsultaPorNomAp1Ap2(const tDatos &datos, const int &num);

// Consulta los datos con una edad comprendida en un intervalo dado
void ConsultaPorEdad(const tDatos &datos);

// Programa principal
int main()
{
  // Declaracion de variables
  tDatos datos;
  bool continuar = true;
  int opcion;

  cout << "Entre los datos de los clientes, " << endl;
  cout << "<Nombre> <PrimerApellido> <SegundoApellido> <Edad>, " << endl;
  cout << "y finalice con X X X -1:" << endl;
  LeerDatos(datos);

  while (continuar)
  {
    MuestraMenu();
    cin >> opcion;
    switch (opcion)
    {
      case 0: ConsultaPorNomAp1Ap2(datos, 0); break;
      case 1: ConsultaPorNomAp1Ap2(datos, 1); break;
      case 2: ConsultaPorNomAp1Ap2(datos, 2); break;
      case 3: ConsultaPorEdad(datos); break;
      case 4: 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 acciones y funciones

// No leemos más datos cuando llegamos al centinela
void LeerDatos(tDatos datos)
{
  int i = 0;

  LeerUnDato(datos[i]);
  // Obsérvese que para comprobar si estamos ante el centinela es
  // suficiente comparar el campo de la edad de datos[i] con -1
  while ( datos[i].edad != -1 )
  {
    i = i + 1;
    LeerUnDato(datos[i]);
  }
}

void LeerUnDato(tHabitante &habit)
{
  // {PRE: Las palabras tienes un máximo de N caracteres}
  cin >> habit.nombre;
  cin >> habit.apellido1;
  cin >> habit.apellido2;
  cin >> habit.edad;
}

void MuestraMenu()
{
  cout << "0.- Consulta por nombre" << endl;
  cout << "1.- Consulta por primer apellido" << endl;
  cout << "2.- Consulta por segundo apellido" << endl;
  cout << "3.- Consulta por intervalo de edad" << endl;
  cout << "4.- Salir" << endl;
};

void EscribirUnDato(tHabitante habit)
{
  cout << '\t' << habit.nombre << ' ';
  cout << habit.apellido1 << ' ';
  cout << habit.apellido2 << ' ';
  cout << habit.edad << endl;
}

void ConsultaPorNomAp1Ap2(const tDatos &datos, const int &num)
{
  int i = 0;
  tNombre aux;

  cout << "Nombre para consultar: " << endl;
  cin >> aux;
  // Para determinar si estamos ante el centinela,
  // es suficiente comprobar si la edad es -1
  cout << "Consulta:" << endl;
  while ( datos[i].edad != -1 )
  {
    switch (num)
    {
      case 0: if ( strcmp( datos[i].nombre, aux ) == 0 )
                EscribirUnDato( datos[i] ); break;
      case 1: if ( strcmp( datos[i].apellido1, aux ) == 0 )
                EscribirUnDato( datos[i] ); break;
      case 2: if ( strcmp( datos[i].apellido2, aux ) == 0 )
                EscribirUnDato( datos[i] ); break;
      default: cout << "Mala opcion para el nombre, el primer";
           cout << "apellido o el segundo apellido" << endl;
               break;
    }
    i++;
  }
 cout << endl;
}

void ConsultaPorEdad(const tDatos &datos)
{
  int i = 0;
  int min, max;

  cout << "Intervalo de edad (dos enteros, el menor y el mayor): ";
  cin >> min >> max;
  // Para encontrar el centinela sólo
  // es suficient comprobar que la edad es -1
  cout << "Consulta:" << endl;
  while ( datos[i].edad != -1 )
  {
    if ( ( datos[i].edad >= min ) && ( datos[i].edad <= max ) )
      EscribirUnDato( datos[i] );
    i++;
  }
}