#include"TriviaApp.h"
#include"Pregunta.h"
#include"PreguntaSeleccionUnica.h"
#include"PreguntaNumerica.h"
#include"PreguntaTextual.h"
#include<QFile>
#include<QMessageBox>
#include<QDomDocument>
#include <ctime>

TriviaApp::TriviaApp(int argc, char *argv[])
    :QApplication(argc, argv), //Llama al constructor de QApplication, clase padre
    puntaje(0),
    preguntasRealizadas(0),
    preguntasAcertadas(0),
    preguntasFallidas(0)
{
}

TriviaApp::~TriviaApp()
{

    qDeleteAll(preguntas);

}

int TriviaApp::exec(){
    /*
    Codigo de resultados y errores

    Codigo      Significado
      0         Exitoso
      1         Error al abrir archivo
      2         Error al "parsear" archivo
      3         Error al cargar (leer) una pregunta
    */
    int resultado = iniciar();
    if(resultado == 0){

        srand(time(NULL));
        int aleatoreo = rand() % preguntas.size();
        ventana.mostrarPregunta(preguntas[aleatoreo]);
        ventana.show();
        return QApplication::exec();

    }else{

        return resultado;

    }
}

inline void mostrarError(const QString& mensaje){

    QMessageBox::critical(0,"Error",mensaje); //Emite un mensaje de error y cierra el programa

}

int TriviaApp::iniciar(){

    //bool continuar = true;

    QFile archivo(nombreArchivo); //Crea un archivo con el nombre que tiene la variable estatica
    /*
    Este IF evalua si se puede abrir el archivo en modo lectura,
    si no se puede muestra el error y cierra el programa.
    Si se pudo abrir, evalua si se puede "parsear" el archivo .xml,
    si no se puede, se informa el error, se cierra el archivo y el programa.
    Si se pudo "parsear", se evalua si se pueden cargar (crear y leer) las preguntas correctamente,
    si no se puede, se informa el error y se cierra el programa.
    Si todo se cumple, se realizan preguntas al azar al asuario, mientras este quiera jugar
    */
    if(! archivo.open(QIODevice::ReadOnly | QIODevice::Text)){

        mostrarError(QString("No se pudo abrir %1").arg(nombreArchivo));
        return 1;//Ver Codigo de resultados y significado en exec() TriviaApp.cpp

    }else{

        QDomDocument documento("trivia");

        if(! parsingXML(archivo, nombreArchivo, documento)){

            archivo.close();
            return 2; //Ver Codigo de resultados y significado en exec() TriviaApp.cpp

        }else{

            archivo.close();
            QDomElement elementosTrivia = documento.documentElement();
            if(! cargarPreguntas(elementosTrivia)){

                return 3; //Ver Codigo de resultados y significado en exec() TriviaApp.cpp

            }//Fin if(! cargarPreguntas(...))

        }//Fin if(! parsingXML(...)

    }//Fin if(! archivo.open(...))

    return 0; //Ver Codigo de resultados y significado en exec() TriviaApp.cpp

}

bool TriviaApp::parsingXML(QFile& archivo, const QString& nombreArchivo, QDomDocument &documento){

    QString errorMsg; //Variable que contiene el mensaje de error
    int lineaError = 0;
    int columnaError = 0;
    //Se trata de establecer el codificado que requiere un archivo .xml, en el
    //objeto que representa a ese archivo. Si no se establecer se muestra el error
    if(! documento.setContent(&archivo, &errorMsg, &lineaError, &columnaError)){

        mostrarError(QString("%1:%2.%3: %4").arg(nombreArchivo).arg(lineaError).arg(columnaError).arg(errorMsg));
        return false;

    }

    return true;

}

bool TriviaApp::cargarPreguntas(const QDomElement &elementosTrivia){
    //Este FOR recorre el arbol DOM entre los nodos de un mismo nivel (hermanos)
    //encontrando a todas las preguntas para su posterior creacion (y lectura)
    for(QDomNode nodo = elementosTrivia.firstChild(); ! nodo.isNull(); nodo = nodo.nextSibling()){

        QDomElement elemento = nodo.toElement();

        if(elemento.isNull() || elemento.tagName() != "question"){

            continue;

        }else{

            Pregunta* pregunta = crearPregunta(elemento.attribute("type"));
            //Este IF evalua si de verdad se creo una pregunta valida
            if(pregunta){
                //Este IF evalua si de verdad pudo "leer" la pregunta
                if(pregunta->leerPregunta(elemento)){

                    preguntas.append(pregunta);

                }else{

                    mostrarError(QString("Error al leer preguntas, revisar archivo %1").arg(nombreArchivo));
                    return false;

                }


            }else{

                delete pregunta;

            }//Fin if(pregunta)

        }//Fin if(elemento.isNull()...)

    }//Fin for()

    return true;

}

void TriviaApp::actualizarEstadistica(const int& valor){

    if(valor == puntajeMaximo){

        ++preguntasRealizadas;
        ++preguntasAcertadas;
        puntaje += puntajeMaximo;

    }else{

        ++preguntasRealizadas;
        ++preguntasFallidas;
        puntaje += puntajeMinimo;

    }

}

Pregunta* TriviaApp::crearPregunta(const QString& tipo){
    //Estos IF's permiten determinar que pregunta se creara de acuerdo
    //a lo indicado por el parametro tipo
    //Si el tipo no corresponde regresa 0 (pregunta a puntero "null")
    if(tipo == "single_choice") return new PreguntaSeleccionUnica();
    else if(tipo == "numeric") return new PreguntaNumerica();
    else if(tipo == "textual") return new PreguntaTextual();
    else return 0;

}
