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.HashMap;

/**
 * Clase que almacena los datos de notas, planificaciones y anotaciones de los alumnos de un apoderado
 */
public class ReporteApoderado {

    private HashMap<Estudiante, Nota[]> notas;
    private HashMap<Estudiante, HashMap<Asignatura, Actividad[]>> planificaciones;
    private HashMap<Estudiante, Anotacion[]> anotaciones;

    private ReporteApoderado(Apoderado apoderado) {
        notas = new HashMap<>();
        planificaciones = new HashMap<>();
        anotaciones = new HashMap<>();
        Estudiante[] estudiantes = Search.buscarEstudiantes(apoderado);
        if (estudiantes != null) {
            for (Estudiante estudiante : estudiantes) {
                notas.put(estudiante, Search.buscarNotas(estudiante));
                anotaciones.put(estudiante, Search.buscarAnotaciones(estudiante));
                Asignatura[] asignaturas = Search.buscarAsignaturas(estudiante.getCurso_id_fk());
                if (asignaturas != null) {
                    for (Asignatura asignatura : asignaturas) {
                        if (planificaciones.containsKey(estudiante)) {
                            Actividad[] actividades = Search.buscarActividades(asignatura);
                            planificaciones.get(estudiante).put(asignatura, actividades);
                        } else {
                            HashMap<Asignatura, Actividad[]> temp = new HashMap<>();
                            Actividad[] actividades = Search.buscarActividades(asignatura);
                            temp.put(asignatura, actividades);
                            planificaciones.put(estudiante, temp);
                        }
                    }
                }
            }
        }
    }

    /**
     * Guarda el reporte generado segun lo indicado en los boleanos entregados
     *
     * @param xslPath ruta en la cual se encuentran los xsl para la transformacion
     * @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 generados en el
     */
    public static HashMap<String, String> generar(File xslPath, boolean xml, boolean json, boolean html, boolean xlsx, boolean docx) {
        HashMap<String, String> reportes = new HashMap<>();
        XStream xstream = new XStream();
        xstream.setMode(XStream.NO_REFERENCES);
        setXStream(xstream);

        HashMap<Apoderado, ReporteApoderado> reporte = new HashMap<>();
        Apoderado[] apoderados = Search.buscarApoderados();
        if (apoderados != null) {
            for (Apoderado apoderado : apoderados) {
                reporte.put(apoderado, new ReporteApoderado(apoderado));
            }
        }
        String xmlResult = xstream.toXML(reporte);
        try {
            PrintWriter outXml = new PrintWriter("files/reportes/reporteApoderado/reporteGeneral.xml");
            outXml.println(xmlResult);
            outXml.close();
            if (json) {
                PrintWriter outJson = new PrintWriter("files/reportes/reporteApoderado/reporteGeneral.json");
                String jsonResult = XML.toJSONObject(xmlResult).toString();
                reportes.put("json",jsonResult);
                outJson.println(jsonResult);
                outJson.close();
            }
            if (html) {
                XslTransformer.transform(
                        xslPath.getPath() + "/toHtmlReporteGeneral.xsl",
                        "files/reportes/reporteApoderado/reporteGeneral.xml",
                        "files/reportes/reporteApoderado/reporteGeneral.html"
                );
                reportes.put("html",Utilities.readFile("files/reportes/reporteApoderado/reporteGeneral.html"));
            }
            if (xlsx) {
                XslTransformer.transform(
                        xslPath.getPath() + "/toExcelReporteGeneral.xsl",
                        "files/reportes/reporteApoderado/reporteGeneral.xml",
                        "files/reportes/reporteApoderado/reporteGeneral.xlsx"
                );
                reportes.put("xlsx",Utilities.readFile("files/reportes/reporteApoderado/reporteGeneral.xlsx"));
            }
            if (docx) {
                XslTransformer.transform(
                        xslPath.getPath() + "/toWordReporteGeneral.xsl",
                        "files/reportes/reporteApoderado/reporteGeneral.xml",
                        "files/reportes/reporteApoderado/reporteGeneral.docx"
                );
                reportes.put("docx",Utilities.readFile("files/reportes/reporteApoderado/reporteGeneral.docx"));
            }
            if (!xml) {
                File deleteFile = new File("files/reportes/reporteApoderado/reporteGeneral.xml");
                deleteFile.delete();
            } else {
                reportes.put("xml",Utilities.readFile("files/reportes/reporteApoderado/reporteGeneral.xml"));
            }
        } catch (FileNotFoundException | TransformerException e) {
            e.printStackTrace();
        }
        return reportes;
    }

    /**
     * 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 static 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");

    }
}
