Source: vistas/vistatarea.js

/**
Vista con los datos de una tarea.
**/

import { Vista } from './vista.js'

export class VistaTarea extends Vista{
  /**
  Constructor de la clase.
  @param {Object} controlador Controlador de la vista.
  @param {Node} base Nodo al que se añadirá la vista.
  **/
  constructor (controlador, base) {
	super(controlador)
    this.base = base
    this.callback = null // Función que se llamará al cerrar el diálogo.


    // Cogemos referencias a los elementos del interfaz
    this.iTitulo = this.base.getElementsByTagName('input')[0]
    this.iFechaInicio = this.base.getElementsByTagName('input')[1]
    this.iFechaFin = this.base.getElementsByTagName('input')[2]
		this.imgAmpliada = this.base.querySelectorAll('img')[0]
    this.iImagenes = this.base.getElementsByTagName('input')[3]
    this.taDescripcion =  this.base.getElementsByTagName('textarea')[0]
    this.divImagenes =  this.base.querySelectorAll('div')[0] //Primer div dentro de divTarea
    this.divActividades =  this.base.querySelectorAll('div')[1] //Segundo div dentro de divTarea
    this.sCalificacion = this.base.getElementsByTagName('select')[0]
    this.taComentarioCalificacionEmpresa =  this.base.getElementsByTagName('textarea')[1]
    this.divEvaluaciones =  this.base.querySelectorAll('div')[2]	//Es el tercer div dentro de divTarea
    this.divBotones = this.base.querySelectorAll('div')[3]	//Cuarto div dentro de divTarea
    this.btnCancelar =  this.base.getElementsByTagName('button')[0]
    this.btnAceptar =  this.base.getElementsByTagName('button')[1]
    this.btnAnterior =  this.base.getElementsByTagName('button')[2]
    this.btnSiguiente =  this.base.getElementsByTagName('button')[3]

    // Asociamos eventos
    this.btnCancelar.onclick = this.cancelar.bind(this)
    this.btnAceptar.onclick = this.aceptar.bind(this, 0)
    this.btnSiguiente.onclick = this.aceptar.bind(this, +1)
    this.btnAnterior.onclick = this.aceptar.bind(this, -1)
    this.iFechaInicio.addEventListener('change',this.cambioFecha.bind(this))
		this.imgAmpliada.onclick = () => this.imgAmpliada.classList.toggle('ampliada')
		
    this.numImagenes = 0
    this.imagenes = []
    this.iImagenes.addEventListener('change',this.anadirImagen.bind(this))

		this.tareas = null	//Lista de tareas
    this.tarea = null		// Referencia a la tarea que se está mostrando
		this.indiceTareaActual = null //Índice de la tarea actual en la lista de tareas.
		this.deshabilitado = null //Indica si la edición de tareas está habilitada
		this.idImagenesBorrar = []	//Array con los ids de las imágenes que hay que borrar
  }

  /**
    Carga en la vista la información de una tarea.
    @param tarea {Tarea} Información de la tarea.
  **/
  setTarea (tarea) {
    this.iImagenes.disabled = false
    this.tarea = tarea
    this.iTitulo.value = tarea.titulo
    this.iFechaInicio.value = tarea.fecha
    this.iFechaFin.value = tarea.fecha_fin
    this.taDescripcion.value = tarea.descripcion
    this.taComentarioCalificacionEmpresa.value = tarea.comentario_calificacion_empresa
    
    // Seleccionamos la calificación de la empresa
    this.cargarCalificaciones()
      .then(respuesta => {
        this.sCalificacion.value = tarea.id_calificacion_empresa
        if (this.controlador.getUsuario().rol === 'alumno') {
          if (tarea.id_calificacion_empresa || tarea.calificacion) { this.deshabilitar(true) }
          for (const modulo of tarea.modulos) {
            if (modulo.calificacion) { this.deshabilitar(true) }
          }
        } else {
          for (const modulo of tarea.modulos) {
            if (modulo.revisado) { this.deshabilitarActividades(true) }
          }
        }
      })
    // Creamos el interfaz para mostrar las revisiones de los módulos
    while (this.divEvaluaciones.firstChild) { this.divEvaluaciones.firstChild.remove() }
    for (const modulo of tarea.modulos) {
      const div = document.createElement('div')
      this.divEvaluaciones.appendChild(div)
      div.classList.add('alto')
      this.crearSpanModulo(div, modulo)
      if (this.controlador.getUsuario().rol === 'alumno') {
        let revision = ' Sin revisar'
        if (modulo.revisado) { revision = ` Revisado. ${modulo.comentario}` }
        div.appendChild(document.createTextNode(revision))
      }
      if (this.controlador.getUsuario().rol === 'profesor') {
        const iCalificacion = document.createElement('input')
        div.appendChild(iCalificacion)
        iCalificacion.value = modulo.revisado
        iCalificacion.setAttribute('type', 'checkbox')
        if(iCalificacion.value== 1){
          iCalificacion.checked = true
        }
        else{
          iCalificacion.checked = false
        }
        this.sCalificacion.value = iCalificacion.value
        const revisado = document.createElement('label')
        div.appendChild(revisado)
        revisado.textContent = 'Revisado'
        revisado.style.fontWeight = 'lighter'
        div.modulo = modulo
        div.appendChild(document.createElement('br'))
        const taEvaluacion = document.createElement('textarea')
        div.appendChild(taEvaluacion)
        taEvaluacion.value = modulo.comentario
        taEvaluacion.setAttribute('placeholder', 'Comentario de evaluación de ' + modulo.titulo)
      }
    }
    // Marcamos las actividades de la tarea
    for (const actividad of tarea.actividades) { this.divActividades.querySelector('input[data-idActividad="' + actividad.id + '"').checked = true }

		// Cargamos las imágenes
		for (const imagen of tarea.imagenes)
			this.crearImagen(imagen.imagen, imagen.id)

		this.tareas = this.controlador.getTareas()
		this.indiceTareaActual = this.tareas.findIndex( (tarea) => tarea.id === this.tarea.id)
		if (this.indiceTareaActual === 0)
			this.btnAnterior.style.display = 'none'
		if (this.indiceTareaActual === this.tareas.length - 1)
			this.btnSiguiente.style.display = 'none'
  }

  /**
    Crea el span asociado a un módulo y lo añade al div.
    @param div {DivElement} Elemento div al que se añadirá el span.
    @param alumno {Modulo} Datos del módulo.
    @param index {Number} Índice del alumno en el array.
    @param array {Array} Array de alumnos.
    TODO: Refactorizar con vistatareas.js
  **/
  crearSpanModulo (div, modulo, index, array) {
    this.array = array
    const span = document.createElement('span')
    div.appendChild(span)
    span.classList.add('modulo')
    span.textContent = modulo.codigo
    span.setAttribute('title', modulo.titulo)
    span.style.backgroundColor = modulo.color_fondo
    span.style.color = modulo.color_letra
  }

  /**
    Cambia la capacidad de editar los campos de la vista (para el alumno).
    @param deshabilitar {Boolean} True para deshabilitar los campos.
  **/
  deshabilitar (deshabilitar) {
		this.deshabilitado = deshabilitar
    this.iTitulo.disabled = deshabilitar
    this.iFechaInicio.disabled = deshabilitar
    this.iFechaFin.disabled = deshabilitar
    this.iImagenes.disabled = deshabilitar
    this.taDescripcion.disabled = deshabilitar
    this.taComentarioCalificacionEmpresa.disabled = deshabilitar
    this.sCalificacion.disabled = deshabilitar
    this.deshabilitarActividades(deshabilitar)
    if (deshabilitar) { 
			this.btnAceptar.style.display = 'none'
			this.btnAnterior.textContent = 'Ver Tarea Anterior'
			this.btnSiguiente.textContent = 'Ver Tarea Siguiente'
		} else { 
			this.btnAceptar.style.display = 'inline'
			this.btnAnterior.textContent = 'Tarea Anterior (sin guardar)'
			this.btnSiguiente.textContent = 'Aceptar y Siguiente'
		}
		//Quitamos los iconos para eliminar imágenes
		this.divImagenes.querySelectorAll('img[title="eliminar la imagen"]').forEach( icono => {icono.style.display = 'none'})
  }

  /**
    Deshabilita la modificación de actividades
    @param deshabilitar {Boolean} True para deshabilitar los campos.
  **/
  deshabilitarActividades (deshabilitar) {
    for (const input of this.divActividades.getElementsByTagName('input')) { input.disabled = deshabilitar }
  }

  /**
    Muestra u oculta.
    Al mostrar la vista carga las actividades.
    @param ver {Boolean} True para mostrar, false para ocultar
    @param tarea {Tarea} Información de la tarea que se quiere mostrar (solo en edición).
  **/
  mostrar (ver, tarea = null) {
    if (ver) {
      this.limpiar()
      this.deshabilitar(false)
      for (const input of this.divActividades.getElementsByTagName('input')) { input.checked = false }
      this.iTitulo.focus()

      if (tarea) {
				//Mostramos los botones de Anterior y Siguiente
				this.btnAnterior.style.display = 'inline'
				this.btnSiguiente.style.display = 'inline'
        this.cargarActividades(tarea.id_curso)
          .then(() => this.setTarea(tarea))
      } else {
        this.cargarActividades(this.controlador.getUsuario().idCurso)
        this.tarea = null
        const hoy = new Date()
        this.iFechaInicio.value = hoy.toLocaleDateString('en-CA')
        this.cargarCalificaciones()
      }
    }
    super.mostrar(ver)
  }

  /**
    Borra los datos del interfaz.
  **/
  limpiar () {
    this.iTitulo.value = ''
    this.iFechaInicio.value = ''
    this.iFechaFin.value = ''
    this.taDescripcion.value = ''
    this.sCalificacion.selectedIndex = 0
    this.taComentarioCalificacionEmpresa.value = ''
    while (this.divImagenes.firstChild) { this.divImagenes.firstChild.remove() }
    while (this.divEvaluaciones.firstChild) { this.divEvaluaciones.firstChild.remove() }
		//Ocultamos los botones de Anterior y Siguiente
    this.btnAnterior.style.display = 'none'
    this.btnSiguiente.style.display = 'none'

		this.idImagenesBorrar = []	//Vaciamos la lista de imágenes a borrar
  }

  /**
    Carga la lista de Actividades de un curso.
    @param idCurso {Number} Identificador del curso.
    @return Promise
  **/
  cargarActividades (idCurso) {
    return this.controlador.verActividades(idCurso)
      .then(actividades => {
        this.eliminarHijos(this.divActividades)
        for (const actividad of actividades) {
          const div = document.createElement('div')
          this.divActividades.appendChild(div)
          const input = document.createElement('input')
          div.appendChild(input)
          input.setAttribute('type', 'checkbox')
          input.setAttribute('data-idActividad', actividad.id)
          const label = document.createElement('label')
          div.appendChild(label)
          label.textContent = actividad.orden + '. ' + actividad.titulo
          label.setAttribute('title', actividad.descripcion)
        }
      })
  }

  /**
    Carga la lista de Calificaciones.
    @param calificaciones {Calificaciones[]} Array de Calificaciones definidas.
    @return Promise de la petición.
  **/
  cargarCalificaciones (calificaciones) {
    return this.controlador.verCalificaciones()
      .then(calificaciones => {
        this.eliminarHijos(this.sCalificacion, 2)
        for (const calificacion of calificaciones) {
          const option = document.createElement('option')
          this.sCalificacion.appendChild(option)
          option.setAttribute('value', calificacion.id)
          option.setAttribute('title', calificacion.descripcion)
          if (this.controlador.getUsuario().rol === 'profesor') { option.textContent = calificacion.titulo} else { option.textContent = calificacion.titulo }
        }
      })
  }

  /**
    Vuelve a la vista de tareas del alumno.
  **/
  volver () {
    this.controlador.mostrarTareasAlumno(this.controlador.getUsuario())
  }

  /**
    Recoge los datos de la Tarea y la envía al controlador.
		@param siguiente {Numnber} 0 - Volver al menú de Tareas, -1 - Ir a la tarea anterior, +1 - Ir a la siguiente tarea
  **/
  aceptar (siguiente = 0) {
		let siguienteTarea = null
		if (siguiente != 0)
			siguienteTarea = this.tareas[this.indiceTareaActual + siguiente]

		if (this.deshabilitado){
        this.controlador.mostrarTarea(siguienteTarea)
				window.scroll(0,0)
				return
			}
    try {
      // Validación de datos.
      if (this.iTitulo.value.length < 5) { throw Error('Debes especificar un título para la tarea que sea descriptivo.') }
      if (this.iFechaInicio.value === '') { throw Error('Debes especificar una fecha válida para la tarea.') }
      if (this.iFechaFin.value === '') { throw Error('Debes especificar una fecha de fin válida para la tarea.') }
      if (new Date(this.iFechaFin.value) < new Date(this.iFechaInicio.value)) { throw Error('La fecha de fin no puede ser anterior a la de inicio.') }
      if (new Date(this.iFechaInicio.value) > new Date()) { throw Error('No registres tareas que no hayas hecho todavía.') }
      if (this.taDescripcion.length < 10) { throw Error('Debes describir detalladamente la tarea.') }

      const tarea = {}
      tarea.titulo = this.iTitulo.value
      tarea.fecha = this.iFechaInicio.value
      tarea.fecha_fin = this.iFechaFin.value
      tarea.descripcion = this.taDescripcion.value
			tarea.imagenes = []
			this.divImagenes.querySelectorAll('.imgTarea').forEach( 
				img => tarea.imagenes.push({'id': img.getAttribute('data-idImagen'), 'src': img.src})
			)
      tarea.actividades = []
      for (const iActividad of document.querySelectorAll('input[data-idActividad]')) {
        if (iActividad.checked) { tarea.actividades.push(iActividad.getAttribute('data-idActividad')) }
      }
      tarea.idCalificacionEmpresa = this.sCalificacion.value
      tarea.comentarioCalificacionEmpresa = this.taComentarioCalificacionEmpresa.value
      tarea.evaluaciones = []
      if (this.controlador.getUsuario().rol === 'profesor') {
        for (const divEvaluacion of this.divEvaluaciones.getElementsByTagName('div')) {
          if(divEvaluacion.getElementsByTagName('input')[0].checked == true){
            divEvaluacion.getElementsByTagName('input')[0].value = 1
          }
          else{
            divEvaluacion.getElementsByTagName('input')[0].value = 0
          }
          const revisado = divEvaluacion.getElementsByTagName('input')[0].value
          const comentario = divEvaluacion.getElementsByTagName('textarea')[0].value
          const evaluacion = {
            id: divEvaluacion.modulo.id,
            revisado,
            comentario
          }
          tarea.evaluaciones.push(evaluacion)
        }
      }

      if (this.tarea) {
        tarea.id = this.tarea.id
				tarea.idImagenesBorrar = this.idImagenesBorrar
        this.controlador.modificarTarea(tarea, siguienteTarea)
      } else { this.controlador.crearTarea(tarea, siguienteTarea) }
    } catch (e) {
      this.controlador.gestionarError(e)
      window.scroll(0,0)
    }
		window.scroll(0,0)
  }

  /**
    Cancela la acción y vuelve a la vista anterior.
  **/
  cancelar () {
    this.controlador.mostrarTareasAlumno()
  }

    /*
    Cambia la fecha fin si se cambia la fecha de inicio
    */
    cambioFecha(){
      this.iFechaFin.value = this.iFechaInicio.value
    }

    /**
     * Añadir imagen al array y aumenta el valor del numImagenes para saber cuantas podemos introducir
     */
    async anadirImagen(){
        let valorimagen = null
        const archivo = this.iImagenes.files[0]
        const lector = new FileReader()
        lector.addEventListener('load',() => {
          valorimagen = lector.result
          if (valorimagen.length > 4000000){
            this.controlador.gestionarError('La imagen es demasiado grande.')
          }
          else
		    this.crearImagen(valorimagen)
          this.iImagenes.value = ''
        })
        lector.readAsDataURL(archivo)
    }

		/**
			Crea un div con la imagen y el icono de borrado y los añade al divImagenes.
			@param base64Imagen {String} Texto con la imagen codificada en Base64.
		**/
		crearImagen(base64Imagen, idImagen = null){
			let img = document.createElement('img')
			this.divImagenes.appendChild(img)
			img.src = base64Imagen
			img.setAttribute('data-idImagen', idImagen)
			img.classList.add('imgTarea')
    	img.onclick = () => {
				this.imgAmpliada.src = img.src
				this.imgAmpliada.classList.toggle('ampliada')
			}

			let iconoEliminar = document.createElement('img')
			iconoEliminar.src = './iconos/delete.svg'
			iconoEliminar.title = 'eliminar la imagen'
    	iconoEliminar.onclick = () => {
				img.remove()
				iconoEliminar.remove()
				if (idImagen)
					this.idImagenesBorrar.push(idImagen)
			}

			this.divImagenes.appendChild(img)
			this.divImagenes.appendChild(iconoEliminar)
		}
}