package logica.reportes;

import com.thoughtworks.xstream.XStream;
import logica.Search;
import logica.Utilities;
import org.json.XML;
import orm.*;

import javax.xml.transform.TransformerException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * Clase que almancena la lista de asistencia y la lista de notas por asignatura de un alumno
 */
public class ReporteAsistenciaYNotas {
    private Estudiante estudiante;
    private Asistencia[] asistencia;
    private HashMap<Asignatura, ArrayList<Nota>> notas;
    private float porcentajeAsistencia;

    public ReporteAsistenciaYNotas(Estudiante estudiante) {
        this.estudiante = estudiante;
        notas = new HashMap<>();
        asistencia = Search.buscarAsistencias(estudiante);
        float counterTotal = 0, counterAsistio = 0;
        if (asistencia != null) {
            for (Asistencia a : asistencia) {
                counterTotal++;
                if (a.getAsistio()) counterAsistio++;
            }
        }
        porcentajeAsistencia = (float) Math.floor(counterAsistio / counterTotal * 100);
        Nota[] notasList = Search.buscarNotas(estudiante);
        if (notasList != null) {
            for (Nota nota : notasList) {
                ArrayList<Nota> notaArray = new ArrayList<>();
                if (notas.containsKey(nota.getAsignatura_id_fk())) {
                    notas.get(nota.getAsignatura_id_fk()).add(nota);
                } else {
                    notaArray.add(nota);
                    notas.put(nota.getAsignatura_id_fk(), notaArray);
                }
            }
        }
    }

    /**
     * Genera los archivos del reporte segun sea indicado
     * @param xslPath La ruta de los archivos xsl
     * @param xml Si se guardara el xml
     * @param json Si se guardara el json
     * @param html Si se guardara el html
     * @param xlsx Si se guardara el xlsx
     * @param docx Si se guardara el docx
     * @return Un hashmap con los reportes.
     */
    public HashMap<String, String> generar(File xslPath, boolean xml, boolean json, boolean html, boolean xlsx, boolean docx) {
        HashMap<String, String> reporte = new HashMap<>();
        XStream xstream = new XStream();
        setXStream(xstream);
        xstream.setMode(XStream.NO_REFERENCES);

        String xmlResult = xstream.toXML(this);
        try {
            PrintWriter outXml = new PrintWriter( "files/reportes/reporteAsistenciaYNotas/" + estudiante.getRut() + "-AsistenciaYNotas.xml");
            outXml.println(xmlResult);
            outXml.close();
            if(json) {
                PrintWriter outJson = new PrintWriter("files/reportes/reporteAsistenciaYNotas/" + estudiante.getRut() + "-AsistenciaYNotas.json");
                String jsonResult = XML.toJSONObject(xmlResult).toString();
                reporte.put("json",jsonResult);
                outJson.println(jsonResult);
                outJson.close();
            }
            if (html) {
                XslTransformer.transform(
                        xslPath.getPath() + "/toHtmlAsistenciaYNotas.xsl",
                        "files/reportes/reporteAsistenciaYNotas/" + estudiante.getRut() + "-AsistenciaYNotas.xml",
                        "files/reportes/reporteAsistenciaYNotas/"  + estudiante.getRut() + "-AsistenciaYNotas.html"
                );
                reporte.put("html", Utilities.readFile("files/reportes/reporteAsistenciaYNotas/"  + estudiante.getRut() + "-AsistenciaYNotas.html"));
            }
            if (xlsx) {
                XslTransformer.transform(
                        xslPath.getPath() + "/toExcelAsistenciaYNotas.xsl",
                        "files/reportes/reporteAsistenciaYNotas/" + estudiante.getRut() + "-AsistenciaYNotas.xml",
                        "files/reportes/reporteAsistenciaYNotas/" + estudiante.getRut() + "-AsistenciaYNotas.xlsx"
                );
                reporte.put("xlsx", Utilities.readFile("files/reportes/reporteAsistenciaYNotas/"  + estudiante.getRut() + "-AsistenciaYNotas.xlsx"));
            }
            if (docx) {
                XslTransformer.transform(
                        xslPath.getPath() + "/toWordAsistenciaYNotas.xsl",
                        "files/reportes/reporteAsistenciaYNotas/" + estudiante.getRut() + "-AsistenciaYNotas.xml",
                        "files/reportes/reporteAsistenciaYNotas/" + estudiante.getRut() + "-AsistenciaYNotas.docx"
                );
                reporte.put("docx", Utilities.readFile("files/reportes/reporteAsistenciaYNotas/"  + estudiante.getRut() + "-AsistenciaYNotas.docx"));
            }
            if(!xml){
                File deleteFile = new File("files/reportes/reporteAsistenciaYNotas/" + estudiante.getRut() + "-AsistenciaYNotas.xml");
                deleteFile.delete();
            }else{
                reporte.put("xml",xmlResult);
            }
        } catch (FileNotFoundException | TransformerException e) {
            e.printStackTrace();
        }
        return reporte;
    }

    /**
     * Inicia XStream con propiedades deseadas, para no mostrar datos innecesarios de las clases y asignarles alias a las clases para no mostrar las rutas completas de estas.
     *
     * @param xstream Instancia de XStream a modificar.
     */
    public void setXStream(XStream xstream) {
        xstream.alias("Actividad", Actividad.class);
        xstream.alias("Anotacion", Anotacion.class);
        xstream.alias("Apoderado", Apoderado.class);
        xstream.alias("Asignatura", Asignatura.class);
        xstream.alias("Asistencia", Asistencia.class);
        xstream.alias("Colegio", Colegio.class);
        xstream.alias("Curso", Curso.class);
        xstream.alias("Estudiante", Estudiante.class);
        xstream.alias("Nota", Nota.class);
        xstream.alias("Profesor", Profesor.class);

        xstream.omitField(Actividad.class, "id_pk");
        xstream.omitField(Actividad.class, "_ormAdapter");

        xstream.omitField(Anotacion.class, "id_pk");
        xstream.omitField(Anotacion.class, "_ormAdapter");

        xstream.omitField(Apoderado.class, "id_pk");
        xstream.omitField(Apoderado.class, "colegio_id_fk");
        xstream.omitField(Apoderado.class, "ORM_estudiante");
        xstream.omitField(Apoderado.class, "_ormAdapter");
        xstream.omitField(Apoderado.class, "estudiante");

        xstream.omitField(Asignatura.class, "id_pk");
        xstream.omitField(Asignatura.class, "_ormAdapter");
        xstream.omitField(Asignatura.class, "ORM_actividad");
        xstream.omitField(Asignatura.class, "ORM_nota");
        xstream.omitField(Asignatura.class, "actividad");
        xstream.omitField(Asignatura.class, "nota");

        xstream.omitField(Asistencia.class, "id_pk");
        xstream.omitField(Asistencia.class, "_ormAdapter");

        xstream.omitField(Colegio.class, "id_pk");
        xstream.omitField(Colegio.class, "_ormAdapter");
        xstream.omitField(Colegio.class, "ORM_curso");
        xstream.omitField(Colegio.class, "ORM_apoderado");
        xstream.omitField(Colegio.class, "ORM_profesor");
        xstream.omitField(Colegio.class, "curso");
        xstream.omitField(Colegio.class, "apoderado");
        xstream.omitField(Colegio.class, "profesor");

        xstream.omitField(Curso.class, "id_pk");
        xstream.omitField(Curso.class, "_ormAdapter");
        xstream.omitField(Curso.class, "ORM_asignatura");
        xstream.omitField(Curso.class, "ORM_estudiante");
        xstream.omitField(Curso.class, "asignatura");
        xstream.omitField(Curso.class, "estudiante");

        xstream.omitField(Estudiante.class, "id_pk");
        xstream.omitField(Estudiante.class, "_ormAdapter");
        xstream.omitField(Estudiante.class, "ORM_anotacion");
        xstream.omitField(Estudiante.class, "ORM_nota");
        xstream.omitField(Estudiante.class, "ORM_asistencia");
        xstream.omitField(Estudiante.class, "anotacion");
        xstream.omitField(Estudiante.class, "nota");
        xstream.omitField(Estudiante.class, "asistencia");

        xstream.omitField(Nota.class, "id_pk");
        xstream.omitField(Nota.class, "_ormAdapter");

        xstream.omitField(Profesor.class, "id_pk");
        xstream.omitField(Profesor.class, "_ormAdapter");
        xstream.omitField(Profesor.class, "ORM_asignatura");
        xstream.omitField(Profesor.class, "ORM_anotacion");
        xstream.omitField(Profesor.class, "asignatura");
        xstream.omitField(Profesor.class, "anotacion");

    }
}
