package logica;

import com.thedeanda.lorem.LoremIpsum;
import org.apache.commons.lang3.RandomUtils;
import org.orm.ORMDatabaseInitiator;
import org.orm.PersistentException;
import org.orm.PersistentTransaction;
import orm.*;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;

public class ExNihilo {

    //Colegio

    /**
     * Añade un nuevo colegio al sistema
     *
     * @param nombre Nombre del colegio a crear
     * @return Retorna un booleando indicando si la creacion fue correcta, si existe un colegio con el mismo nombre, no sera creado y retornara false, si no, retornara true.
     */
    public static boolean crearColegio(String nombre) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarColegio(nombre) == null) {
                    Colegio colegio = ColegioDAO.createColegio();
                    colegio.setNombre(nombre);
                    ColegioDAO.save(colegio);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Modifica los valores de el colegio entregado
     *
     * @param colegio Colegio que se modificara
     * @param nombre  Nombre nuevo que se le otorgara al colegio
     * @return Retorna un booleano indicando si el colegio existe en el sistema y si la operacion se realizo correctamente, true si es asi y false si no.
     */
    public static boolean modificarColegio(Colegio colegio, String nombre) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if(colegio!=null) {
                    if (Search.buscarColegio(colegio.getNombre()) != null) {
                        colegio.setNombre(nombre);
                        ColegioDAO.save(colegio);
                        t.commit();
                        return true;
                    } else {
                        t.rollback();
                        return false;
                    }
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Elimina un colegio y todos sus asociados.
     *
     * @param colegio Colegio que se eliminara
     * @return Retorna un booleano indicando si se ejecuto correctamente y existe ese colegio en el sistema, si fue asi, retornara true, si no, false.
     */
    public static boolean eliminarColegio(Colegio colegio) {
        try {
            Apoderado[] apoderados = Search.buscarApoderados(colegio);
            if (apoderados != null) {
                if (apoderados.length > 0) {
                    for (Apoderado apoderado : apoderados) {
                        eliminarApoderado(apoderado);
                    }
                }
            }
            Profesor[] profesores = Search.buscarProfesores(colegio);
            if (profesores != null) {
                if (profesores.length > 0) {
                    for (Profesor profesor : profesores) {
                        eliminarProfesor(profesor);
                    }
                }
            }
            Curso[] cursos = Search.buscarCursos();
            if (cursos != null) {
                if (cursos.length > 0) {
                    for (Curso curso : cursos) {
                        eliminarCurso(curso);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarColegio(colegio.getNombre()) != null) {
                    ColegioDAO.delete(colegio);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    //Curso

    /**
     * Añade un nuevo curso al sistema
     *
     * @param nivel   Nivel del curso, "1,2,3,4... "
     * @param letra   Letra del curso, "A,B...."
     * @param colegio Colegio al que se le añade el curso.
     * @return Retorna un booleano, si existe un curso con el mismo nivel y letra en un colegio o ocurre algun error, retornara false, si no, entrega un true.
     */
    public static boolean crearCurso(int nivel, String letra, Colegio colegio) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarCurso(nivel, letra) == null) {
                    Curso curso = CursoDAO.createCurso();
                    curso.setNivel(nivel);
                    curso.setLetra(letra);
                    curso.setColegio_id_fk(colegio);
                    CursoDAO.save(curso);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Modifica un curso del sistema
     *
     * @param curso   Curso que se modificara
     * @param nivel   nuevo nivel del curso
     * @param letra   nueva letra del curso
     * @param colegio nuevo colegio del curso
     * @return Retorna un booleano indicando si el curso existe en el sistema y si la operacion se realizo correctamente, true si es asi y false si no.
     */
    public static boolean modificarCurso(Curso curso, Integer nivel, String letra, Colegio colegio) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if(curso!=null) {
                    if (Search.buscarCurso(curso.getNivel(), curso.getLetra()) != null) {
                        if (nivel != null) {
                            curso.setNivel(nivel);
                        }
                        if (letra != null) {
                            curso.setLetra(letra);
                        }
                        if (colegio != null) {
                            curso.setColegio_id_fk(colegio);
                        }
                        CursoDAO.save(curso);
                        t.commit();
                        return true;
                    } else {
                        t.rollback();
                        return false;
                    }
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Elimina un curso del sistema y todos sus asociados
     *
     * @param curso Curso a eliminar
     * @return Retorna un boleano respecto si la operacion se realizo correctamente y el curso existia previamente en el sistema, si es asi, retornara true, si no un false.
     */
    public static boolean eliminarCurso(Curso curso) {
        try {
            Asignatura[] asignaturas = Search.buscarAsignaturas(curso);
            if (asignaturas != null) {
                if (asignaturas.length > 0) {
                    for (Asignatura asignatura : asignaturas) {
                        eliminarAsignatura(asignatura);
                    }
                }
            }
            Estudiante[] estudiantes = Search.buscarEstudiantes(curso);
            if (estudiantes != null) {
                if (estudiantes.length > 0) {
                    for (Estudiante estudiante : estudiantes) {
                        eliminarEstudiante(estudiante);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarCurso(curso.getNivel(), curso.getLetra()) != null) {
                    curso.setColegio_id_fk(null);
                    CursoDAO.delete(curso);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    //Apoderado

    /**
     * Añade un nuevo apoderado a la base de datos.
     *
     * @param nombre Nombre completo del apoderado
     * @param rut    Rut perteneciente al apoderado
     * @return retorna un booleano correspondiente a si la operacion se ejecuto correctamente, si fue asi, retorna un true, si ocurre algun error, se repite el rut en alguna otra persona del colegio o algun otro error, retornara false;
     */
    public static boolean crearApoderado(Colegio colegio, String nombre, String rut) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarApoderado(rut) == null && Search.buscarEstudiante(rut) == null && Search.buscarProfesor(rut) == null) {
                    Apoderado apoderado = ApoderadoDAO.createApoderado();
                    apoderado.setNombre(nombre);
                    apoderado.setRut(rut);
                    apoderado.setColegio_id_fk(colegio);
                    ApoderadoDAO.save(apoderado);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Modifica un apoderado del sistema
     *
     * @param apoderado Apoderado a modificar
     * @param nombre    nuevo nombre del apoderado
     * @param rut       nuevo rut del apoderado
     * @return Retorna un booleano indicando si el apoderado existe en el sistema y si la operacion se realizo correctamente, true si es asi y false si no.
     */
    public static boolean modificarApoderado(Apoderado apoderado, String nombre, String rut) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if(apoderado!=null) {
                    if (Search.buscarApoderado(apoderado.getRut()) != null &&
                            Search.buscarEstudiante(rut) == null &&
                            Search.buscarProfesor(rut) == null &&
                            Search.buscarApoderado(rut) == null) {
                        if (nombre != null) {
                            apoderado.setNombre(nombre);
                        }
                        if (rut != null) {
                            apoderado.setRut(rut);
                        }
                        ApoderadoDAO.save(apoderado);
                        t.commit();
                        return true;
                    } else {
                        t.rollback();
                        return false;
                    }
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Elimina el apoderado entregado del sistema.
     *
     * @param apoderado Apoderado a eliminar.
     * @return Retorna un booleano dependiendo si la operacion se realizo correctamente, si el apoderado ya no existe en el sistema o si ocurre algun otro error, se retornara false, si no, retornara true;
     */
    public static boolean eliminarApoderado(Apoderado apoderado) {
        try {
            Estudiante[] estudiantes = Search.buscarEstudiantes(apoderado);
            if (estudiantes != null) {
                if (estudiantes.length > 0) {
                    for (Estudiante estudiante : estudiantes) {
                        eliminarEstudiante(estudiante);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarApoderado(apoderado.getRut()) != null) {
                    apoderado.setColegio_id_fk(null);
                    ApoderadoDAO.delete(apoderado);
                    t.commit();
                    return true;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    //Estudiante

    /**
     * Añade un nuevo estudiante al sistema
     *
     * @param nombre    Nombre completo del estudiante
     * @param rut       Rut del estudiante
     * @param curso     Curso al que se añade el estudiante
     * @param apoderado Apoderado del estudiante
     * @return Retorna un booleano, si se crea correctamente y el rut no esta repetido en ninguna parte del colegio, retornara un true, si no retornara false.
     */
    public static boolean crearEstudiante(String nombre, String rut, Curso curso, Apoderado apoderado) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarEstudiante(rut) == null && Search.buscarProfesor(rut) == null && Search.buscarApoderado(rut) == null) {
                    Estudiante estudiante = EstudianteDAO.createEstudiante();
                    estudiante.setRut(rut);
                    estudiante.setNombre(nombre);
                    estudiante.setCurso_id_fk(curso);
                    estudiante.setApoderado_id_fk(apoderado);
                    EstudianteDAO.save(estudiante);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Modifica un estudiante del sistema
     *
     * @param estudiante Estudiante que se modificara
     * @param nombre     nuevo nombre del estudiante
     * @param rut        nuevo rut del estudiante
     * @param curso      nuevo curso del estudiante
     * @param apoderado  nuevo apoderado del estudiante
     * @return Retorna un booleano indicando si el estudiante existe en el sistema y si la operacion se realizo correctamente, true si es asi y false si no.
     */
    public static boolean modificarEstudiante(Estudiante estudiante, String nombre, String rut, Curso curso, Apoderado apoderado) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if(estudiante!=null) {
                    if (Search.buscarEstudiante(estudiante.getRut()) != null &&
                            Search.buscarEstudiante(rut) == null &&
                            Search.buscarProfesor(rut) == null &&
                            Search.buscarApoderado(rut) == null) {
                        if (nombre != null) {
                            estudiante.setNombre(nombre);
                        }
                        if (rut != null) {
                            estudiante.setRut(rut);
                        }
                        if (curso != null) {
                            estudiante.setCurso_id_fk(curso);
                        }
                        if (apoderado != null) {
                            estudiante.setApoderado_id_fk(apoderado);
                        }
                        EstudianteDAO.save(estudiante);
                        t.commit();
                        return true;
                    } else {
                        t.rollback();
                        return false;
                    }
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Elimina un Estudiante del sistema y todos sus asociados
     *
     * @param estudiante Estudiante a eliminar
     * @return Retorna un boleano respecto si la operacion se realizo correctamente y el estudiante existe en el sistema, si es asi, retornara true, si no un false.
     */
    public static boolean eliminarEstudiante(Estudiante estudiante) {
        try {
            Anotacion[] anotaciones = Search.buscarAnotaciones(estudiante);
            if (anotaciones != null) {
                if (anotaciones.length > 0) {
                    for (Anotacion anotacion : anotaciones) {
                        eliminarAnotacion(anotacion);
                    }
                }
            }
            Asistencia[] asistencias = Search.buscarAsistencias(estudiante);
            if (asistencias != null) {
                if (asistencias.length > 0) {
                    for (Asistencia asistencia : asistencias) {
                        eliminarAsistencia(asistencia);
                    }
                }
            }
            Nota[] notas = Search.buscarNotas(estudiante);
            if (notas != null) {
                if (notas.length > 0) {
                    for (Nota nota : notas) {
                        eliminarNota(nota);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarEstudiante(estudiante.getRut()) != null) {
                    estudiante.setApoderado_id_fk(null);
                    estudiante.setCurso_id_fk(null);
                    EstudianteDAO.delete(estudiante);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    //Asistencia

    /**
     * Añade una asistencia al sistema.
     *
     * @param dia        Dia en el que asiste o no el estudiante.
     * @param asistio    Indica si el estudiante o no, con true o false respectivamente
     * @param estudiante Estudiante al que se le ingresa la asistencia ese dia
     * @return Retorna un booleano si la operacion se ejecuta correctamente, si no esta repetida o no ocurre ningun error, retornara true, si ocurre lo contrario, entonces retornara false.
     */
    public static boolean crearAsistencia(Date dia, boolean asistio, Estudiante estudiante) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarAsistencia(estudiante, dia, asistio) == null) {
                    Asistencia asistencia = AsistenciaDAO.createAsistencia();
                    asistencia.setAsistio(asistio);
                    asistencia.setDia(dia);
                    asistencia.setEstudiante_id_fk(estudiante);
                    AsistenciaDAO.save(asistencia);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return asistio;
    }

    /**
     * Modifica una asistencia del sistema
     *
     * @param asistencia Asistencia a modificar
     * @param dia        nuevo dia de la asistencia
     * @param asistio    nuevo booleano indicando si asistio o no
     * @param estudiante nuevo estudiante al que pertenece la asistencia
     * @return Retorna un booleano indicando si la asistencia existe en el sistema y si la operacion se realizo correctamente, true si es asi y false si no.
     */
    public static boolean modificarAsistencia(Asistencia asistencia, Date dia, Boolean asistio, Estudiante estudiante) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if(asistencia!=null) {
                    if (Search.buscarAsistencia(asistencia.getEstudiante_id_fk(), asistencia.getDia(), asistencia.getAsistio()) != null) {
                        if (dia != null) {
                            asistencia.setDia(dia);
                        }
                        if (asistio != null) {
                            asistencia.setAsistio(asistio);
                        }
                        if (estudiante != null) {
                            asistencia.setEstudiante_id_fk(estudiante);
                        }
                        AsistenciaDAO.save(asistencia);
                        t.commit();
                        return true;
                    } else {
                        t.rollback();
                        return false;
                    }
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Elimina una asistencia del sistema
     *
     * @param asistencia Asistencia a eliminar
     * @return Retorna un booleano indicando si la asistencia existe en el sistema y si la operacion se realizo correctamente, true si es asi y false si no.
     */
    public static boolean eliminarAsistencia(Asistencia asistencia) {

        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarAsistencia(asistencia.getEstudiante_id_fk(), asistencia.getDia(), asistencia.getAsistio()) != null) {
                    asistencia.setEstudiante_id_fk(null);
                    AsistenciaDAO.delete(asistencia);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    //Nota

    /**
     * Añade una nota al sistema.
     *
     * @param valor      Valor de la nota.
     * @param asignatura Asignatura a la que pertenece la nota
     * @param estudiante Estudiante al que se le añade la nota
     * @return Retorna un booleano respecto si la operacion se completo correctamente, si algo falla, retornara false, si no un true.
     */
    public static boolean crearNota(double valor, Asignatura asignatura, Estudiante estudiante) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                Nota nota = NotaDAO.createNota();
                nota.setValor(valor);
                nota.setEstudiante_id_fk(estudiante);
                nota.setAsignatura_id_fk(asignatura);
                NotaDAO.save(nota);
                t.commit();
                return true;
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Modifica una nota del sistema
     *
     * @param nota       Nota a modificarse
     * @param valor      nuevo valor que tendra la nota
     * @param asignatura nueva asignatura a la que pertenecera la nota
     * @param estudiante nuevo estudiante al que pertenecera la nota
     * @return Retorna un booleano indicando si la nota existe en el sistema y si la operacion se realizo correctamente, true si es asi y false si no.
     */
    public static boolean modificarNota(Nota nota, Double valor, Asignatura asignatura, Estudiante estudiante) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if(nota!=null) {
                    if (Search.buscarNota(nota.getEstudiante_id_fk(), nota.getAsignatura_id_fk(), nota.getValor()) != null) {
                        if (valor != null) {
                            nota.setValor(valor);
                        }
                        if (asignatura != null) {
                            nota.setAsignatura_id_fk(asignatura);
                        }
                        if (estudiante != null) {
                            nota.setEstudiante_id_fk(estudiante);
                        }
                        NotaDAO.save(nota);
                        t.commit();
                        return true;
                    } else {
                        t.rollback();
                        return false;
                    }
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Elimina una nota del sistema.
     *
     * @param nota Nota que se eliminara
     * @return Retorna un booleano indicando si se ejecuto correctamente y existe esa nota en el sistema, si fue asi, retornara true, si no, false.
     */
    public static boolean eliminarNota(Nota nota) {

        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarNota(nota.getEstudiante_id_fk(), nota.getAsignatura_id_fk(), nota.getValor()) != null) {
                    nota.setAsignatura_id_fk(null);
                    nota.setEstudiante_id_fk(null);
                    NotaDAO.delete(nota);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    //Anotacion

    /**
     * Añade una nueva anotacion a la base de datos
     *
     * @param positiva    si la anotacion es positiva, true, si es negativa, false
     * @param descripcion Descripcion de la anotacion
     * @param estudiante  Estudiante al que se le añade la anotacion
     * @param profesor    Profesor al cual se le añade la anotacion
     * @return Retorna un booleano respecto a si se creo el objeto correctamente, si esta ingresado anteriormente o ocurre algun otro error, retornara false, si se crea correctamente, retorna true.
     */
    public static boolean crearAnotacion(boolean positiva, String descripcion, Estudiante estudiante, Profesor profesor) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarAnotacion(estudiante, profesor, descripcion, positiva) == null) {
                    Anotacion anotacion = AnotacionDAO.createAnotacion();
                    anotacion.setPositiva(positiva);
                    anotacion.setDescripcion(descripcion);
                    anotacion.setEstudiante_id_fk(estudiante);
                    anotacion.setProfesor_id_fk(profesor);
                    AnotacionDAO.save(anotacion);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    public static boolean modificarAnotacion(Anotacion anotacion, Boolean positiva, String descripcion, Estudiante estudiante, Profesor profesor) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if(anotacion!=null) {
                    if (Search.buscarAnotacion(anotacion.getEstudiante_id_fk(), anotacion.getProfesor_id_fk(), anotacion.getDescripcion(), anotacion.getPositiva()) != null) {
                        if (positiva != null) {
                            anotacion.setPositiva(positiva);
                        }
                        if (descripcion != null) {
                            anotacion.setDescripcion(descripcion);
                        }
                        if (estudiante != null) {
                            anotacion.setEstudiante_id_fk(estudiante);
                        }
                        if (profesor != null) {
                            anotacion.setProfesor_id_fk(profesor);
                        }
                        AnotacionDAO.save(anotacion);
                        t.commit();
                        return true;
                    } else {
                        t.rollback();
                        return false;
                    }
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Elimina la anotacion indicada del sistema.
     *
     * @param anotacion Anotacion a eliminarse
     * @return Retorna un booleano indicando si la operacion se realizo correctamente, cuando no se encuentra la anotacion indicada en el sistema o ocurre algun error interno, retornara false, si no retornara un true.
     */
    public static boolean eliminarAnotacion(Anotacion anotacion) {

        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarAnotacion(
                        anotacion.getEstudiante_id_fk(), anotacion.getProfesor_id_fk(), anotacion.getDescripcion(), anotacion.getPositiva()) != null) {
                    anotacion.setEstudiante_id_fk(null);
                    anotacion.setProfesor_id_fk(null);
                    AnotacionDAO.delete(anotacion);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    //Profesor

    /**
     * Añade un nuevo profesor al sistema.
     *
     * @param colegio Colegio al que pertenece el profesor
     * @param nombre  Nombre del profesor
     * @param rut     Rut del profesor
     * @return Retorna un boleano dependiendo si la creacion fue correcta y el rut no se repite en otra persona del colegio, si es asi, retornara true, si no, retornara false
     */
    public static boolean crearProfesor(Colegio colegio, String nombre, String rut) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarProfesor(rut) == null && Search.buscarApoderado(rut) == null && Search.buscarEstudiante(rut) == null) {
                    Profesor profesor = ProfesorDAO.createProfesor();
                    profesor.setColegio_id_fk(colegio);
                    profesor.setNombre(nombre);
                    profesor.setRut(rut);
                    ProfesorDAO.save(profesor);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Modifica un profesor del sistema
     *
     * @param profesor Profesor a modificar
     * @param nombre   nuevo nombre del profesor
     * @param rut      nuevo rut del profesor
     * @return Retorna un booleano indicando si el profesor existe en el sistema y si la operacion se realizo correctamente, true si es asi y false si no.
     */
    public static boolean modificarProfesor(Profesor profesor, String nombre, String rut) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if(profesor!=null) {
                    if (Search.buscarProfesor(profesor.getRut()) != null &&
                            Search.buscarEstudiante(rut) == null &&
                            Search.buscarProfesor(rut) == null &&
                            Search.buscarApoderado(rut) == null) {
                        if (nombre != null) {
                            profesor.setNombre(nombre);
                        }
                        if (rut != null) {
                            profesor.setRut(rut);
                        }
                        ProfesorDAO.save(profesor);
                        t.commit();
                        return true;
                    } else {
                        t.rollback();
                        return false;
                    }
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Elimina un profesor y todos sus asociados.
     *
     * @param profesor Profesor que se eliminara
     * @return Retorna un booleano indicando si se ejecuto correctamente y existe ese profesor en el sistema, si fue asi, retornara true, si no, false.
     */
    public static boolean eliminarProfesor(Profesor profesor) {
        try {
            Anotacion[] anotaciones = Search.buscarAnotaciones(profesor);
            if (anotaciones != null) {
                if (anotaciones.length > 0) {
                    for (Anotacion anotacion : anotaciones) {
                        eliminarAnotacion(anotacion);
                    }
                }
            }
            Asignatura[] asignaturas = Search.buscarAsignaturas(profesor);
            if (asignaturas != null) {
                if (asignaturas.length > 0) {
                    for (Asignatura asignatura : asignaturas) {
                        eliminarAsignatura(asignatura);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarProfesor(profesor.getRut()) != null) {
                    profesor.setColegio_id_fk(null);
                    ProfesorDAO.delete(profesor);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    //Asignatura

    /**
     * Añade una nueva asignatura al sistema.
     *
     * @param nombre   Nombre de la asignatura
     * @param curso    Curso al que pertenecera la asignatura
     * @param profesor Profesor que impartira la asignatura
     * @return Retorna un booleano dependiendo si la operacion se ejecuto correctamente, si no existe una asignatura con el mismo nombre en el curso, retornara true, si ocurre algun error o el nombre de la asignatura en el curso esta repetida, retorna false
     */
    public static boolean crearAsignatura(String nombre, Curso curso, Profesor profesor) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarAsignatura(nombre, curso) == null) {
                    Asignatura asignatura = AsignaturaDAO.createAsignatura();
                    asignatura.setNombre(nombre);
                    asignatura.setCurso_id_fk(curso);
                    asignatura.setProfesor_id_fk(profesor);
                    AsignaturaDAO.save(asignatura);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Modifica una asignatura del sistema
     *
     * @param asignatura Asignatura la cual sera modificada
     * @param nombre     nuevo nombre de la asignatura
     * @param curso      nuevo curso de la asignatura
     * @param profesor   nuevo profesor de la asignatura
     * @return Retorna un booleano indicando si la asignatura existe en el sistema y si la operacion se realizo correctamente, true si es asi y false si no.
     */
    public static boolean modificarAsignatura(Asignatura asignatura, String nombre, Curso curso, Profesor profesor) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if(asignatura!=null) {
                    if (Search.buscarAsignatura(asignatura.getNombre(), asignatura.getCurso_id_fk()) != null) {
                        if (nombre != null) {
                            asignatura.setNombre(nombre);
                        }
                        if (curso != null) {
                            asignatura.setCurso_id_fk(curso);
                        }
                        if (profesor != null) {
                            asignatura.setProfesor_id_fk(profesor);
                        }
                        AsignaturaDAO.save(asignatura);
                        t.commit();
                        return true;
                    } else {
                        t.rollback();
                        return false;
                    }
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Elimina una asignatura y todos sus asociados.
     *
     * @param asignatura Asignatura que se eliminara
     * @return Retorna un booleano indicando si se ejecuto correctamente y existe esa Asignatura en el sistema, si fue asi, retornara true, si no, false.
     */
    public static boolean eliminarAsignatura(Asignatura asignatura) {


        try {
            Actividad[] actividades = Search.buscarActividades(asignatura);
            if (actividades != null) {
                if (actividades.length > 0) {
                    for (Actividad actividad : actividades) {
                        eliminarActividad(actividad);
                    }
                }
            }
            Nota[] notas = Search.buscarNotas(asignatura);
            if (notas != null) {
                if (notas.length > 0) {
                    for (Nota nota : notas) {
                        eliminarNota(nota);
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarAsignatura(asignatura.getNombre(), asignatura.getCurso_id_fk()) != null) {
                    asignatura.setCurso_id_fk(null);
                    asignatura.setProfesor_id_fk(null);
                    AsignaturaDAO.delete(asignatura);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    //Actividad

    /**
     * Añade una nueva actividad en la base de datos
     *
     * @param fecha      Fecha en la que se realiza la actividad
     * @param tipo       Tipo de la actividad, Prueba, Taller, etc.
     * @param asignatura Asignatura a la que pertence.
     * @return Retorna un booleano si es que se creo la actividad, false si no se pudo crear o si no existe, true si se creo con exito.
     */
    public static boolean crearActividad(Date fecha, String tipo, Asignatura asignatura) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarActividad(asignatura, fecha, tipo) == null) {
                    Actividad actividad = ActividadDAO.createActividad();
                    actividad.setFecha(fecha);
                    actividad.setTipo(tipo);
                    actividad.setAsignatura_id_fk(asignatura);
                    ActividadDAO.createActividad();
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Modifica una actividad del sistema
     *
     * @param actividad  Actividad a ser modificada
     * @param fecha      nueva fecha de la actividad
     * @param tipo       nuevo tipo de la actividad
     * @param asignatura nueva asignatura de la actividad
     * @return Retorna un booleano indicando si la actividad existe en el sistema y si la operacion se realizo correctamente, true si es asi y false si no.
     */
    public static boolean modificarActividad(Actividad actividad, Date fecha, String tipo, Asignatura asignatura) {
        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if(actividad!=null) {
                    if (Search.buscarActividad(actividad.getAsignatura_id_fk(), actividad.getFecha(), actividad.getTipo()) != null) {
                        if (fecha != null) {
                            actividad.setFecha(fecha);
                        }
                        if (tipo != null) {
                            actividad.setTipo(tipo);
                        }
                        if (asignatura != null) {
                            actividad.setAsignatura_id_fk(asignatura);
                        }
                        ActividadDAO.save(actividad);
                        t.commit();
                        return true;
                    } else {
                        t.rollback();
                        return false;
                    }
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * Elimina la actividad que se le entrega.
     *
     * @param actividad Actividad que sera eliminada.
     * @return Retorna un booleano indicando si la eliminacion fue correcta, se considera incorrecta cuando la actividad no existe en la base de datos o ocurre algun error de parte de hibernate, retornara false cuando sea asi, si no retornara true.
     */
    public static boolean eliminarActividad(Actividad actividad) {

        try {
            PersistentTransaction t = ColegioPersistentManager.instance().getSession().beginTransaction();
            try {
                if (Search.buscarActividad(actividad.getAsignatura_id_fk(), actividad.getFecha(), actividad.getTipo()) != null) {
                    actividad.setAsignatura_id_fk(null);
                    ActividadDAO.delete(actividad);
                    t.commit();
                    return true;
                } else {
                    t.rollback();
                    return false;
                }
            } catch (Exception e) {
                t.rollback();
                return false;
            }
        } catch (PersistentException e) {
            e.printStackTrace();
        }
        return false;
    }

    //fill randomly
    public static void fill() {
        crearColegio("Colegio San Francisco");
        Colegio colegio = Search.buscarColegio("Colegio San Francisco");
        for (int x = 0; x < 2; x++) {
            crearCurso(x + 1, "A", colegio);
            crearCurso(x + 1, "B", colegio);
        }
        for (Curso curso : Search.buscarCursos()) {

            ArrayList<String> nombres = new ArrayList<>();
            nombres.add("Lenguaje");
            nombres.add("Educacion Fisica");
            nombres.add("Matematicas");
            nombres.add("Religion");
            nombres.add("Historia");

            for (int y = 0; y < 5; y++) {
                String rut = Utilities.getRandomRut();
                crearProfesor(colegio, Utilities.getRandomName(), rut);
                crearAsignatura(nombres.remove(RandomUtils.nextInt(0, nombres.size())), curso, Search.buscarProfesor(rut));

            }

            for (int y = 0; y < 2; y++) {
                String rut = Utilities.getRandomRut();
                crearApoderado(colegio, Utilities.getRandomName(), rut);
                crearEstudiante(Utilities.getRandomName(), Utilities.getRandomRut(), curso, Search.buscarApoderado(rut));
            }

            for (Asignatura asignatura : Search.buscarAsignaturas(curso)) {
                for (Estudiante estudiante : Search.buscarEstudiantes(curso)) {
                    crearNota(RandomUtils.nextDouble(0.0D, 7.0D), asignatura, estudiante);
                }
            }
        }

        for (Asignatura asignatura : Search.buscarAsignaturas()) {
            for (int x = 0; x < 5; x++) {
                if (RandomUtils.nextBoolean()) {
                    crearActividad(Utilities.getRandomDate(), "Prueba", asignatura);
                } else {
                    crearActividad(Utilities.getRandomDate(), "Taller", asignatura);
                }
            }
        }

        for (Estudiante estudiante : Search.buscarEstudiantes()) {
            int max = RandomUtils.nextInt(1, 10);
            Curso curso = estudiante.getCurso_id_fk();
            Asignatura[] asignaturas = Search.buscarAsignaturas(curso);
            Asignatura asignatura = asignaturas[RandomUtils.nextInt(0, asignaturas.length)];
            for (int x = 0; x < 5; x++) {
                crearAnotacion(RandomUtils.nextBoolean(), LoremIpsum.getInstance().getWords(5), estudiante, asignatura.getProfesor_id_fk());
            }
            for (int x = 0; x < 5; x++) {
                crearAsistencia(Utilities.getRandomDate(), RandomUtils.nextBoolean(), estudiante);
            }
        }
    }

    //delete all from all tables
    public static void deleteAll() {
        Colegio[] colegios = Search.buscarColegios();
        if (colegios != null) {
            if (colegios.length > 0) {
                for (Colegio colegio : colegios) {
                    eliminarColegio(colegio);
                }
            }
        }
    }

    public static void createDatabase(){
        try {
            ORMDatabaseInitiator.createSchema(ColegioPersistentManager.instance());
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (PersistentException e) {
            e.printStackTrace();
        }
    }
}
