#include <stdio.h>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <festival.h>
#include <sstream>
#include <string>
#include <termios.h>
#include <fcntl.h>
#include <dirent.h>

void ObtenerDiarioPublico(), ObtenerDiarioMarca(), ObtenerDiarioLevante(), ObtenerDiarioElPais(), ObtenerDiarioElMundo();
void InicializarControlador(), ComprobarVoces(), RefinarTexto(int), LeerNoticias(), Decir(string), VaciarBufferTeclado();
bool ProxCaracteres(FILE*,string), AntCaracteres(FILE*,string), ObtencionExitosa(), EncontrarSustitucion(FILE*,FILE*,FILE*,char), ComprobarTeclado();
int ComprobarSigNumeros(FILE*);
char BuscaControlador(), UltimaTeclaPulsada();

int heap_size = 210000;
int load_init_files = 1;

int main(int argc, char **argv)
{
    bool salir = false, haleido = false;
    char opcionchar;
    int opcionint;
    festival_initialize(load_init_files,heap_size);

    InicializarControlador();

    ComprobarVoces();

    do {
	while(!salir){	    
	    system("clear");
	    cout << "\n    PULSE ESPACIO TRAS ESCUCHAR EL DIARIO DESEADO, O ESCAPE PARA SALIR";
            cout << "\n    ------------------------------------------------------------------\n\n";
	    Decir("pulse espacio tras escuchar el diario deseado, o escape para salir");
	    sleep(1);
	    ComprobarTeclado();

	    VaciarBufferTeclado();
	    cout << "> Diario Público (www.publico.es) [5 seg. aprox]\n\n";
	    Decir("diario público");
	    sleep(1);
	    if (ComprobarTeclado())
	    {
		opcionint = 1;
		break;
	    }

	    VaciarBufferTeclado();
	    cout << "> Diario Levante (www.levante-emv.com) [20 seg. aprox]\n\n";
	    Decir("Diario Levante");
	    sleep(1);
	    if (ComprobarTeclado())
	    {
		opcionint = 2;
		break;
	    }

	    VaciarBufferTeclado();
	    cout << "> Diario Marca (www.marca.com) [5 seg. aprox]\n\n";
	    Decir("Diario Marca");
	    sleep(1);
	    if (ComprobarTeclado())
	    {
		opcionint = 3;
		break;
	    }

	    VaciarBufferTeclado();
	    cout << "> Diario El País (www.elpais.com) [5 seg. aprox]\n\n";
	    Decir("Diario el país");
	    sleep(1);
	    if (ComprobarTeclado())
	    {
		opcionint = 4;
		break;
	    }

	    VaciarBufferTeclado();
	    cout << "> Diario El Mundo (www.elmundo.es) [5 seg. aprox]\n\n";
	    Decir("Diario el mundo");
	    sleep(1);
	    if (ComprobarTeclado())
	    {
		opcionint = 5;
		break;
	    }
	}

	cout << "\nProcesando. Por favor espere...\n\n";
	Decir("procesando. Por favor espere");

	system("rm -f ./Archiweb/*");	//vaciamos el contenido de los archivos derivados de las webs

	switch (opcionint){
	    case 1: ObtenerDiarioPublico(); break;
	    case 2: ObtenerDiarioLevante(); break;
	    case 3: ObtenerDiarioMarca(); break;
	    case 4: ObtenerDiarioElPais(); break;
	    case 5: ObtenerDiarioElMundo(); break;
	}    

	if (ObtencionExitosa())
	{
	    system("clear");
	    LeerNoticias();
	    haleido = true;
	}
	else
	{
	    cout << "\n\nSe ha producido un error de acceso. Intente este diario más tarde.\n\n";
	    Decir("Se ha producido un error de acceso. Intente este diario más tarde");
	}
    } while(true);
}

//----------------------------------------------------------------------------------
//Función que verifica si se ha obtenido y procesado el fichero deseado desde la web
//----------------------------------------------------------------------------------
bool ObtencionExitosa()
{
    FILE * fichero;
    fichero = fopen("Archiaux/textovozRef.txt","r");
    if (fichero != NULL)
    {
	fclose(fichero);
	return true;
    }
    else
	return false;
}

//------------------------------------------------------------------------------
//Función que obtiene el RSS del diario Público y extrae de él el texto legiblbe
//------------------------------------------------------------------------------
void ObtenerDiarioPublico()
{
    FILE * forigen;
    FILE * fdestino;
    char caracter;
    bool escribiendo = false;
    int aperturas = 0; // &lt;
    int cierres = 0; // &gt;

    system("wget -i -D http://www.publico.es/rss/ -o ./Archiaux/log.txt --directory-prefix=Archiweb"); //se obtiene index.html

    forigen = fopen("Archiweb/index.html","r");

    if (forigen != NULL)
    {
	fdestino = fopen("Archiaux/textovoz.txt","w");
	do{
	    caracter = fgetc(forigen);
	    if (!escribiendo)
	    {
		if (ProxCaracteres(forigen,"<item><title>") || ProxCaracteres(forigen,"<description>"))
		    escribiendo = true;
	    }
	    else
	    {
		if (ProxCaracteres(forigen,"</title>") || ProxCaracteres(forigen,"</description>"))
		{
		    escribiendo = false;
		    fputc('.',fdestino);
		    fputc('\n',fdestino);
		}
		else if (ProxCaracteres(forigen,"&lt;p&gt;"))
		{
		    if (aperturas == cierres)
		    {
			fputc('.',fdestino);
			fputc(' ',fdestino);
		    }
		}		
		else if (ProxCaracteres(forigen,"&lt;"))
		{
		    aperturas++;
		}

		else if (ProxCaracteres(forigen,"&gt;"))
		{
		    cierres++;
		}
		else if (aperturas <= cierres)
		{
		    if (ProxCaracteres(forigen,"<p>"))
			fputc('.',fdestino);
		    else if (ProxCaracteres(forigen,"&amp;"))
		    	fputc(' ',fdestino);			
		    else if (caracter == '-' || caracter =='?')
			fputc(' ',fdestino);
		    else if (caracter != '"' && caracter != 39 && caracter != '[' && caracter != ']')
			fputc(caracter,fdestino);
		}
	    }
	} while(caracter != EOF);	//hasta encontrar el fin de linea

	fflush(fdestino);
	fclose(forigen);
	fclose(fdestino);
	RefinarTexto(1); //refinar el texto ignorando la primeras linea
    }
}

//------------------------------------------------------------------------------
//Función que obtiene el RSS del diario Levante y extrae de él el texto legiblbe
//------------------------------------------------------------------------------
void ObtenerDiarioLevante()
{
    FILE * forigen;
    FILE * fdestino;
    char caracter;
    bool escribiendo = false;
    system("wget -i -D http://www.levante-emv.com/elementosInt/rss/AlMinuto -o ./Archiaux/log.txt --directory-prefix=Archiweb"); //se obtiene AlMinuto
    system ("iconv --from-code=ISO-8859-1 --to-code=UTF-8 ./Archiweb/AlMinuto > ./Archiaux/levante.xml -c -s"); //lo convertimos a UTF-8 para que el proceso de refinamiento lo pueda tratar como a cualquier otro usando la tabla ascii estandar
    forigen = fopen("Archiaux/levante.xml","r");

    if (forigen != NULL)
    {
	fdestino = fopen("Archiaux/textovoz.txt","w");
	do{
	    caracter = fgetc(forigen);
	    if (!escribiendo)
	    {
		if (ProxCaracteres(forigen,"<title><![CDATA[") || ProxCaracteres(forigen,"<description><![CDATA["))
		    escribiendo = true;
	    }
	    else
	    {
		if (ProxCaracteres(forigen,"]]></title>") || ProxCaracteres(forigen,"]]></description>"))
		{
		    escribiendo = false;
		    fputc('.',fdestino);
		    fputc('\n',fdestino);
		}
		else
		{
		    if (caracter == '-' || caracter =='?')
			fputc(' ',fdestino);
		    else
			if (caracter != '"' && caracter != 39 && caracter != '[' && caracter != ']')
			    fputc(caracter,fdestino);
		}
	    }
	} while(caracter != EOF);	//hasta encontrar el fin de linea

	fflush(fdestino);
	fclose(forigen);
	fclose(fdestino);
	RefinarTexto(4); //refinar el texto ignorando la primeras linea
    }    
}

//------------------------------------------------------------------------------
//Función que obtiene el RSS del diario MARCA y extrae de él el texto legiblbe
//------------------------------------------------------------------------------
void ObtenerDiarioMarca()
{
    FILE * forigen;
    FILE * fdestino;
    char caracter;
    bool escribiendo = false;
    int aperturas = 0; // &lt;
    int cierres = 0; // &gt;

    system("wget -i -D http://estaticos.marca.com/rss/portada.xml -o ./Archiaux/log.txt --directory-prefix=Archiweb"); //se obtiene portada.xml

    forigen = fopen("Archiweb/portada.xml","r");

    if (forigen != NULL)
    {
	fdestino = fopen("Archiaux/textovoz.txt","w");
	do{
	    caracter = fgetc(forigen);
	    if (!escribiendo)
	    {
		if (ProxCaracteres(forigen,"<item><title>") || ProxCaracteres(forigen,"<description>"))
		    escribiendo = true;
	    }

	    else
	    {
		if (ProxCaracteres(forigen,"</title>") || ProxCaracteres(forigen,"</description>"))
		{
		    escribiendo = false;
		    fputc('.',fdestino);
		    fputc('\n',fdestino);
		}

		else if (ProxCaracteres(forigen,"&amp;"))
		{
		    fputc('.',fdestino);
		    fputc('\n',fdestino);


		    escribiendo = false;
		}

		else if (ProxCaracteres(forigen,"&lt;"))
		{
		    aperturas++;
		}

		else if (ProxCaracteres(forigen,"&gt;"))
		{
		    cierres++;
		}
		else if (aperturas <= cierres)
		{
		    if (caracter == '-' || caracter =='?')
			fputc(' ',fdestino);
		    else
			if (caracter != '"' && caracter != 39 && caracter != '[' && caracter != ']')
			    fputc(caracter,fdestino);
		}
	    }
	} while(caracter != EOF);	//hasta encontrar el fin de linea


	fflush(fdestino);
	fclose(forigen);
	fclose(fdestino);
	RefinarTexto(2); //refinar el texto ignorando la primeras linea
    }
}

//------------------------------------------------------------------------------
//Función que obtiene el RSS del diario El País y extrae de él el texto legiblbe
//------------------------------------------------------------------------------
void ObtenerDiarioElPais()
{
    FILE * forigen;
    FILE * fdestino;
    char caracter;
    bool escribiendo = false;
    int aperturas = 0; // &lt;
    int cierres = 0; // &gt;
    system("wget -i -D http://www.elpais.com/rss/feed.html?feedId=1022 -o ./Archiaux/log.txt --directory-prefix=Archiweb"); //feedId=1022
    system ("iconv --from-code=ISO-8859-1 --to-code=UTF-8 ./Archiweb/feed.html?feedId=1022 > ./Archiaux/elpais.xml -c -s"); //lo convertimos a UTF-8 para que el proceso de refinamiento lo pueda tratar como a cualquier otro usando la tabla ascii estandar
    forigen = fopen("Archiaux/elpais.xml","r");

    if (forigen != NULL)
    {
	fdestino = fopen("Archiaux/textovoz.txt","w");
	do{
	    caracter = fgetc(forigen);
	    if (!escribiendo)
	    {
		if (ProxCaracteres(forigen,"<title><![CDATA[") || ProxCaracteres(forigen,"<description><![CDATA["))
		    escribiendo = true;
	    }
	    else
	    {
		if (ProxCaracteres(forigen,"]]></title>") || ProxCaracteres(forigen,"]]></description>"))
		{
		    escribiendo = false;
		    fputc('.',fdestino);
		    fputc('\n',fdestino);
		}
		else if (ProxCaracteres(forigen,"<"))
		{
		    aperturas++;
		}

		else if (ProxCaracteres(forigen,">"))
		{
		    cierres++;
		}
		else if (aperturas <= cierres)
		{
		    if (caracter == '-' || caracter =='?')
			fputc(' ',fdestino);
		    else
			if (caracter != '"' && caracter != 39 && caracter != '[' && caracter != ']')
			    fputc(caracter,fdestino);
		}
	    }
	} while(caracter != EOF);	//hasta encontrar el fin de linea

	fflush(fdestino);
	fclose(forigen);
	fclose(fdestino);
	RefinarTexto(4); //refinar el texto ignorando la primeras linea
    }    
}

//------------------------------------------------------------------------------
//Función que obtiene el RSS del diario El Mundo y extrae de él el texto legiblbe
//------------------------------------------------------------------------------
void ObtenerDiarioElMundo()
{
    FILE * forigen;
    FILE * fdestino;
    char caracter;
    bool escribiendo = false;
    int aperturas = 0; // &lt;
    int cierres = 0; // &gt;
    system("wget -i -D http://elmundo.feedsportal.com/elmundo/rss/portada.xml -o ./Archiaux/log.txt --directory-prefix=Archiweb"); //se obtiene portada.xml
    forigen = fopen("Archiweb/portada.xml","r");

    if (forigen != NULL)
    {
	fdestino = fopen("Archiaux/textovoz.txt","w");
	do{
	    caracter = fgetc(forigen);
	    if (!escribiendo)
	    {
		if (ProxCaracteres(forigen,"<item><title>") || ProxCaracteres(forigen,"<description>"))
		    escribiendo = true;
	    }
	    else
	    {
		if (ProxCaracteres(forigen,"</title>") || ProxCaracteres(forigen,"</description>"))
		{
		    escribiendo = false;
		    fputc('.',fdestino);
		    fputc('\n',fdestino);
		}
		else if (ProxCaracteres(forigen,"#160"))
		{
		    if (aperturas == cierres)
		    {
			fputc('\n',fdestino);
			escribiendo = false;
		    }
		}
		else if (ProxCaracteres(forigen,"#34"))
		{
		    if (aperturas == cierres)
		    {
			fputc(' ',fdestino);
		    }
		}
		else if (ProxCaracteres(forigen,"&lt;"))
		{
		    aperturas++;
		}

		else if (ProxCaracteres(forigen,"&gt;"))
		{
		    cierres++;
		}
		else if (aperturas <= cierres)
		{
		    if (ProxCaracteres(forigen,"<p>"))
			fputc('.',fdestino);
		    else if (ProxCaracteres(forigen,"&amp;"))
		    	fputc(' ',fdestino);			
		    else if (caracter == '-' || caracter =='?')
			fputc(' ',fdestino);
		    else if (caracter != '"' && caracter != 39 && caracter != '[' && caracter != ']')
			fputc(caracter,fdestino);
		}
	    }
	} while(caracter != EOF);	//hasta encontrar el fin de linea

	fflush(fdestino);
	fclose(forigen);
	fclose(fdestino);
	RefinarTexto(2); //refinar el texto ignorando la primeras linea
    }    
}

//-------------------------------------------------------------------------------------------------------------
//Función que comprueba si en las siguientes posiciones al puntero del fichero indicado se encuentra la cadena.
//-------------------------------------------------------------------------------------------------------------
bool ProxCaracteres(FILE * fdesc, string laetiqueta)
{
    char proxcaracter;
    char *etiqueta = strdup(laetiqueta.c_str());
    int posCursorInicial = ftell(fdesc);
 
    fseek(fdesc,-1,SEEK_CUR);
    for (int i=0; i <= strlen(etiqueta)-1; i++)
    {
	proxcaracter = fgetc(fdesc);
	if (proxcaracter != etiqueta[i])
	{
	    fseek(fdesc,posCursorInicial,SEEK_SET);
	    return false;
	}
    }

    return true;
}

//-------------------------------------------------------------------------------------------------------------
//Función que comprueba si en las anteriores posiciones al puntero del fichero indicado se encuentra la cadena.
//-------------------------------------------------------------------------------------------------------------
bool AntCaracteres(FILE * fdesc, string laetiqueta)
{
    char proxcaracter;
    char *etiqueta = strdup(laetiqueta.c_str());
    int posCursorInicial = ftell(fdesc);
 
    fseek(fdesc,-(strlen(etiqueta)+1),SEEK_CUR);
    for (int i=0; i <= strlen(etiqueta)-1; i++)
    {
	proxcaracter = fgetc(fdesc);
	if (proxcaracter != etiqueta[i])
	{
	    fseek(fdesc,posCursorInicial,SEEK_SET);
	    return false;
	}
    }
    fseek(fdesc,posCursorInicial,SEEK_SET);
    return true;
}

//--------------------------------------------------------------------------------------------------------
//Función que devuelve el número de cifras que aparecen seguidas en las siguientes posiciones del fichero.
//--------------------------------------------------------------------------------------------------------
int ComprobarSigNumeros(FILE * fdesc)
{
    char proxcaracter;
    int posCursorInicial = ftell(fdesc);
    int numCifras = 0;
    bool haycifras = true;
 
    do
    {
	proxcaracter = fgetc(fdesc);
	if (proxcaracter >= 48 && proxcaracter <= 57)
	{
	    numCifras++;
	}
	else
	    haycifras = false;
    } while(haycifras);

    fseek(fdesc,posCursorInicial,SEEK_SET);
    return numCifras;
}

//--------------------------------------------------------
//Función que adecúa el texto para la lectura en Festival.
//--------------------------------------------------------
void RefinarTexto(int lineasinutiles)
{
    FILE * forigen;
    FILE * fdestino;
    FILE * fdiccionario;

    char caracteractual, ultimoescrito, caracteraux;

    forigen = fopen("Archiaux/textovoz.txt","r");
    fdestino = fopen("Archiaux/textovozRef.txt","w");
    fdiccionario = fopen("sustituciones","r");

    int numlineas = 0;
    while(numlineas < lineasinutiles)
    {
	caracteractual = fgetc(forigen);
	if (caracteractual == '\n')
	    numlineas++;
    }

    do{
	caracteractual = fgetc(forigen);
	if (!ProxCaracteres(forigen," ") && !ProxCaracteres(forigen,"«") && !ProxCaracteres(forigen,"»")) // (Aunque lo primero parece un espacio, es un multicaracter que no se procesa correctamente y se debe omitir).
	{
	    switch(caracteractual)
	    {
		case ' ':	// Tratamos aparte los espacios.
		    if (ultimoescrito != ' ' && ultimoescrito != '\n') // Los espacios se omiten si van precedidos de otro espacio o un salto de linea
		    {
			if (ProxCaracteres(forigen," .") && ultimoescrito != '.') //o si después de ellos viene un punto.
			{
			    fputc('.',fdestino);
			    ultimoescrito = '.';
			}
			else if (ProxCaracteres(forigen," (")) // Si después de ellos viene un paréntesis abierto.
			{
			    fputc(',',fdestino); // Se pone un punto.
			    ultimoescrito = ',';
			}
			else if (ProxCaracteres(forigen," - ")) // Si después de ellos viene un guión y un espacio.
			{
			    fputc(',',fdestino); // Se pone un punto.
			    ultimoescrito = ',';
			}
			else
			{
			    fputc(' ',fdestino);	// En otro caso se mantiene el espacio.
			    ultimoescrito = ' ';
			}
		    }
		    break;
		case '.':	// Tratamos aparte los puntos.
		    if (ultimoescrito >= 48 && ultimoescrito <= 57)	// Si el caracter anterior al punto era un número:
		    {
			switch(ComprobarSigNumeros(forigen)) //comprobamos si lo que sigue al punto es una cifra,
			{
			    case 2: fputc('.',fdestino); //Si la cifra es de 2 dígitos, ponemos el punto y la siguiente cifra sin espacio, pues
				fputc(fgetc(forigen),fdestino);	//probablemente es una hora.
				break;
			    case 3: break;	//Y si es una cifra de 3 dígitos quitamos el punto porque festival no lo reconoce como separador.
			    default: fputc('.',fdestino);	// En otro caso lo mantenemos.
				ultimoescrito = '.';
			}
		    }
		    else if (ultimoescrito != '.' && ultimoescrito != ' ' && ultimoescrito != ',' && ultimoescrito != '\n')
		    {	// Si el caracter anterior al punto no es ni una cifra, ni un punto, ni un espacio, ni una coma, ni un salto de linea,
			fputc('.',fdestino);	//lo mantenemos.
			ultimoescrito = '.';
		    }
		    break;
		case ',':	// Tratamos aparte las comas.
		    if (ultimoescrito >= 48 && ultimoescrito <= 57 && ComprobarSigNumeros(forigen) > 0) //si la coma está precedida y seguida de cifras...
		    {	//sustituimos el signo ',' por la palabra 'coma' para que la pronuncie en lugar de hacer una pausa.
			fputc(' ',fdestino); fputc('c',fdestino); fputc('o',fdestino); fputc('m',fdestino); fputc('a',fdestino); fputc(' ',fdestino);
			ultimoescrito = ' ';
		    }
		    else if (ultimoescrito != ',' && ultimoescrito != ' ')
		    {
			fputc(',',fdestino);
			ultimoescrito = ',';
		    }
		    break;
		case '(':	// Los paréntesis los cambiamos por comas para que haga una pausa
		    {
			if (ultimoescrito != ',' && ultimoescrito != '.')
			{
			    fputc(',',fdestino);
			    ultimoescrito = ',';			    
			}
		    }
		    break;
		case ')':
		    {
			if (ProxCaracteres(forigen,")."))
			{
			    fputc('.',fdestino);
			    ultimoescrito = '.';
			}
			else
			{
			    fputc(',',fdestino);
			    ultimoescrito = ',';
			}
		    }
		    break;
		default: //Cualquier otro caracter no tratado especialmente lo mostramos sin más,
		    if (ultimoescrito == '.' || ultimoescrito == ',') //poniendo antes un espacio si va justo después de un punto o una coma.
			fputc(' ',fdestino);
		    if (!EncontrarSustitucion(forigen,fdestino,fdiccionario,ultimoescrito))
		    {
			fputc(caracteractual,fdestino);
			ultimoescrito = caracteractual;
		    }
		    else
			ultimoescrito = '_'; // (cualquier carácter no interceptado en posteriores iteraciones)
	    }
	}
    } while(caracteractual != EOF);

    fflush(fdestino);
    fclose(forigen);
    fclose(fdestino);
    fclose(fdiccionario);
}

//---------------------------------------------------------------------------------------------------------------
//Función que busca si para la próxima palabra hay una pronunciación más adecuada en el fichero de sustituciones.
//---------------------------------------------------------------------------------------------------------------
bool EncontrarSustitucion(FILE * orig, FILE * dest, FILE * dicci, char ultchar)
{
    if (!(ultchar ==' ' || ultchar =='.' || ultchar ==',' || ultchar =='(' || ultchar ==')' || ultchar ==':' || ultchar =='\n'))
	return false;
    char pal_dicci[1440];
    char ultimochar;
    int posEncontrada = 0;
    char palabra[1440];
    int posCursorInicial = ftell(orig);
    bool quedan = true;

    fseek(orig,-1,SEEK_CUR);
    fgets(palabra,1440,orig);

    fseek(orig,posCursorInicial,SEEK_SET);
    fseek(dicci,0,SEEK_SET);

    while(quedan)
    {
	if (fgets(pal_dicci,1440,dicci)) // Vamos comprobando linea a linea del fichero.
	{
	    if (tolower(pal_dicci[0]) == tolower(palabra[0])) // Si las palabras empiezan igual
	    {
		for (int i=1; i <= strlen(pal_dicci)-1; i++)
		{
		    if (pal_dicci[i] == '>' && (palabra[i]==' ' || palabra[i]=='.' || palabra[i]==',' || palabra[i]==')' || palabra[i]=='\n'))
		    { //si han coincidido todas las letras hasta encontrar '>' significa que la palabra está contemplada
			for (int j=i+1; j <= strlen(pal_dicci)-2; j++)
			{
			    fputc(pal_dicci[j],dest); //así que se escribe lo que haya en la parte derecha del '>'
			}
			fseek(orig,i-1,SEEK_CUR);
			return true;
		    }
		    else
		    {
			if (tolower(palabra[i]) != tolower(pal_dicci[i])) //cuando una letra no coincide entre las cadenas, se acaba con esa linea
			    break;
		    }
		}
	    }
	}
	else
	{
	    quedan = false;
	}
    }

    return false;
}

//---------------------------------------------
//Función que lee el fichero de noticias final.
//---------------------------------------------
void LeerNoticias()
{
    //primero se convierte la codificación UTF-8 a ISO-8859-1 para que se pronuncien tildes y ñ's entre otros
    system ("iconv --from-code=UTF-8 --to-code=ISO-8859-1 ./Archiaux/textovozRef.txt > ./Archiaux/textovozISO8859.txt -c -s");

    FILE * fichero;
    char linea[1440];
    fichero = fopen("./Archiaux/textovozISO8859.txt","r");
    
    bool salir = false;

    do{
	festival_eval_command("(voice_JuntaDeAndalucia_es_pa_diphone)");
	for (int i=0; i<=1; i++)
	{
	    if (fgets(linea,1440,fichero) == NULL)
		salir = true;
	    else
		festival_say_text(linea);
	}
	sleep(1);
	festival_eval_command("(voice_JuntaDeAndalucia_es_sf_diphone)");
	for (int i=0; i<=1; i++)
	{
	    if (fgets(linea,1440,fichero) == NULL)
		salir = true;
	    else
		festival_say_text(linea);
	}
	sleep(1);
    } while(!salir);

    festival_wait_for_spooler();
}

//--------------------------------------------------------------------------
//Función que lee el texto indicado previa conversión al charset ISO-8859-1.
//--------------------------------------------------------------------------
void Decir(string eltexto)
{
    char *texto = strdup(eltexto.c_str());
    FILE * archiaux;

    archiaux = fopen("./Archiaux/archiaux","w");
    fputs(texto,archiaux);
    fflush(archiaux);
    fclose(archiaux);
    system ("iconv --from-code=UTF-8 --to-code=ISO-8859-1 ./Archiaux/archiaux > ./Archiaux/archiauxISO8859 -c -s");
    archiaux = fopen("./Archiaux/archiauxISO8859","r");
    system("rm -f archiaux");
    fgets(texto,1440,archiaux);
    festival_eval_command("(voice_el_diphone)");
    festival_say_text(texto);
    fclose(archiaux);
    system("rm -f ./Archiaux/archiauxISO8859");
    festival_wait_for_spooler();
}

//-----------------------------------------------------------------------------------
//Función que devuelve la última tecla pulsada o fuerza la salida si ésta era Escape.
//-----------------------------------------------------------------------------------
bool ComprobarTeclado()
{
    char tecla = UltimaTeclaPulsada();
    if (tecla == ' ')
    {
	return true;
    }
    if (tecla == 27)
    {
	cout << "\n\nGracias por usar nuestro programa. Vuelva pronto.\n\n";
	Decir("Gracias por usar nuestro programa. Vuelva pronto");
	exit(1);
    }
    return false;
}

//---------------------------------------------
//Función que devuelve la última tecla pulsada.
//---------------------------------------------
char UltimaTeclaPulsada() // Esta es una versión modificada del Kbhit para linux, para que devuvelva la última tecla pulsada
{
  struct termios oldt, newt;
  int ch;
  int oldf;

  tcgetattr(STDIN_FILENO, &oldt);
  newt = oldt;
  newt.c_lflag &= ~(ICANON | ECHO);
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
  fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

  ch = getchar();

  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  fcntl(STDIN_FILENO, F_SETFL, oldf);

    if(ch != EOF)
    {
	ungetc(ch, stdin);
	return ch;
    }

  return NULL;
}

//-----------------------------------------
//Función para vaciar el buffer de entrada.
//-----------------------------------------
void VaciarBufferTeclado()
{
    setvbuf(stdin, NULL, _IONBF,0); // Al deshabilitar la entrada estandar se vacía el buffer,
    setvbuf(stdin, NULL, _IOFBF,0); //tras lo cual volvemos a habilitarla.
}

//-----------------------------------------------------------------------------------------
//Función que comprueba si las voces a utilizar están instaladas y avisa en caso contrario.
//-----------------------------------------------------------------------------------------
void ComprobarVoces()
{
    DIR* directorio;
    bool estavoz1 = false, estavoz2 = false, estavoz3 = false;
    char dirvoz1[72] = "/usr/share/festival/voices/spanish/JuntaDeAndalucia_es_pa_diphone"; //voz masculina de la Junta de Andalucía
    char dirvoz2[72] = "/usr/share/festival/voices/spanish/JuntaDeAndalucia_es_sf_diphone"; //voz femenina de la Junta de Andalucía
    char dirvoz3[48] = "/usr/share/festival/voices/spanish/el_diphone";	//voz masculina estándar
    char carpetavoz1[32] = "JuntaDeAndalucia_es_pa_diphone";
    char carpetavoz2[32] = "JuntaDeAndalucia_es_sf_diphone";
    char carpetavoz3[12] = "el_diphone";

    if ((directorio = opendir(dirvoz1)) != NULL)
	estavoz1 = true;

    if ((directorio = opendir(dirvoz2)) != NULL)
	estavoz2 = true;

    if ((directorio = opendir(dirvoz3)) != NULL)
	estavoz3 = true;

    if (!estavoz1 || !estavoz2 || !estavoz3)
    {
	printf("Algunas voces utilizadas no están instaladas. Esto puede afectar sensiblemente la calidad de la experiencia:\n");
	if (!estavoz1)
	    printf("%s\n",carpetavoz1);
	if (!estavoz2)
	    printf("%s\n",carpetavoz2);
	if (!estavoz3)
	    printf("%s\n",carpetavoz3);
	fflush(stdout);
	Decir("algunas voces utilizadas no están instaladas. Esto puede afectar sensiblemente la calidad de la experiencia");
    }	
}

//-----------------------------------------------------------------------------------------------------------------
//Función que carga el controlador de sonido indicado en el fichero configaudio, que en caso de no existir lo crea.
//-----------------------------------------------------------------------------------------------------------------
void InicializarControlador()
{
    FILE * archiconfig;
    char codigodriver;

    archiconfig = fopen("configaudio","r");
    if (archiconfig == NULL)
    {
	codigodriver = BuscaControlador();
	if (codigodriver == '0')
	{
	    cout << "\n¡No se encuentra un controlador de sonido adecuado!\nSaliendo de la aplicación...\n\n";
	    exit(1);
	}
	archiconfig = fopen("configaudio","w");
	fputc(codigodriver,archiconfig);
	fclose(archiconfig);
    }
    else
    {
	codigodriver = fgetc(archiconfig);
	fclose(archiconfig);
	switch (codigodriver)
	{
	    case '1': festival_eval_command("(Parameter.set 'Audio_Command \"aplay -D plug:dmix -q -c 1 -t raw -f S16_BE -r $SR $FILE\")"); break;
	    case '2': festival_eval_command("(Parameter.set 'Audio_Command \"esdaudio $FILE\")"); break;
	    case '3': festival_eval_command("(Parameter.set 'Audio_Command \"sun16audio $FILE\")"); break;
	    case '4': festival_eval_command("(Parameter.set 'Audio_Command \"sunaudio $FILE\")"); break;
	    case '5': festival_eval_command("(Parameter.set 'Audio_Command \"freebsd16audio $FILE\")"); break;
	    case '6': festival_eval_command("(Parameter.set 'Audio_Command \"linux16audio $FILE\")"); break;
	}
	festival_eval_command("(Parameter.set 'Audio_Method 'Audio_Command)");
	festival_eval_command("(Parameter.set 'Audio_Required_Format 'snd)");	
    }
    system("clear");
}

//-------------------------------------------------------------------------------------------------------------
//Función que se encarga de ir probando los controladores uno a uno hasta que encuentra uno válido y lo guarda.
//-------------------------------------------------------------------------------------------------------------
char BuscaControlador()
{
    time_t Tantes, Tdespues;

    system("clear");
    cout << "Detectada primera ejecución. Buscando controlador de audio adecuado...";
    fflush(stdout);
    sleep(3);

    festival_eval_command("(Parameter.set 'Audio_Command \"aplay -D plug:dmix -q -c 1 -t raw -f S16_BE -r $SR $FILE\")");
    festival_eval_command("(Parameter.set 'Audio_Method 'Audio_Command)");
    festival_eval_command("(Parameter.set 'Audio_Required_Format 'snd)");
    time(&Tantes);
    Decir("detectado el controlador ALSA");
    system("clear");
    time(&Tdespues);
    if (difftime(Tdespues,Tantes) >= 2)
	return '1';

    festival_eval_command("(Parameter.set 'Audio_Method 'esdaudio)");
    festival_eval_command("(Parameter.set 'Audio_Required_Format 'snd)");
    time(&Tantes);
    Decir("detectado el controlador E S D.");
    system("clear");
    time(&Tdespues);
    if (difftime(Tdespues,Tantes) >= 2)
	return '2';

    festival_eval_command("(Parameter.set 'Audio_Method 'sun16audio)");
    festival_eval_command("(Parameter.set 'Audio_Required_Format 'snd)");
    time(&Tantes);
    Decir("detectado el controlador san audio 16 bits");
    system("clear");
    time(&Tdespues);
    if (difftime(Tdespues,Tantes) >= 2)
	return '3';

    festival_eval_command("(Parameter.set 'Audio_Method 'sunaudio)");
    festival_eval_command("(Parameter.set 'Audio_Required_Format 'snd)");
    time(&Tantes);
    Decir("detectado el controlador san audio");
    system("clear");
    time(&Tdespues);
    if (difftime(Tdespues,Tantes) >= 2)
	return '4';

    festival_eval_command("(Parameter.set 'Audio_Method 'freebsd16audio)");
    festival_eval_command("(Parameter.set 'Audio_Required_Format 'snd)");
    time(&Tantes);
    Decir("detectado el controlador frii B S D audio 16 bits");
    system("clear");
    time(&Tdespues);
    if (difftime(Tdespues,Tantes) >= 2)
	return '5';

    festival_eval_command("(Parameter.set 'Audio_Method 'linux16audio)");
    festival_eval_command("(Parameter.set 'Audio_Required_Format 'snd)");
    time(&Tantes);
    Decir("detectado el controlador Linux audio 16 bits");
    system("clear");
    time(&Tdespues);
    if (difftime(Tdespues,Tantes) >= 2)
	return '6';

    return '0';
}



