package com.uva.rafael.tfg_goniometer.view.fragments;

import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TableLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.uva.rafael.tfg_goniometer.R;
import com.uva.rafael.tfg_goniometer.dependencyInjection.App;
import com.uva.rafael.tfg_goniometer.interfaces.ViewFunctions;
import com.uva.rafael.tfg_goniometer.presenter.PerfilPacientePresenter;

import java.util.ArrayList;

import javax.inject.Inject;

/**
 * Esta clase es el <tt>Fragment</tt> que se encarga de:
 *
 * 1.- Mostrar la información almacenada en la Base de Datos del paciente en concreto (datos
 * personales, síntomas, etc.)
 * 2.- Mostrar/Ocultar el botón para borrar un paciente del sistema. Este botón se mostrará siempre
 * y cuando no se vaya a añadir una nueva medición al paciente en cuestión.
 * 3.- Mostrar/Ocultar el botón para añadir una nueva medición al paciente en cuestión. Este botón
 * se mostrará si previamente se ha realizado una medición en <tt>MedicionFragment</tt>.
 * 4.- Mostrar una tabla con el listado de mediciones que se han realizado previamente al paciente
 * en cuestión (o una tabla vacía en caso contrario).
 *
 * <p>Además de estas tareas, se encarga de notificar a <tt>PerfilPacientePresenter</tt> cuando el
 * usuario ha pulsado sobre el botón para añadir una nueva medición, o al botón para borrar el
 * perfil del paciente.</p>
 *
 * <p>Por último, se encarga de notificar al usuario si un paciente ha sido eliminado correctamente
 * (o no se ha podido eliminar) de la Base de Datos.</p>
 *
 * <p>Esta clase forma parte de la aplicación TFG-Goniometer, desarrollada para el Trabajo de
 * Fin de Grado - Grado en Ingeniería Informática (Universidad de Valladolid)</p>
 *
 * @author Rafael Matamoros Luque
 * @see PerfilPacientePresenter
 * @see TableLayout
 * @version 1.0
 */

public class PerfilPacienteFragment extends Fragment implements View.OnClickListener, ViewFunctions,
        ViewFunctions.PerfilPacienteFunctions {

    /*
     * Presentador asociado con este Fragment (Vista). Su instancia se obtiene mediante Inversión
     * de Dependencias
     */
    @SuppressWarnings({"unused", "CanBeFinal"})
    @Inject
    PerfilPacientePresenter presenter;

    // Variables locales para almacenar la información obtenida desde el Bundle
    private String nombrePaciente;
    private int idPaciente;
    private double lectura_goniometro;
    private String fechaHora; // Fecha y hora en la que se realizó la medición

    private boolean mostrarOpcionesNuevaMedicion; // Mostrar/Ocultar el botón para añadir medición
    private boolean mostrarOpcionesBorrarPaciente; // Mostrar/Ocultar el botón para borrar el paciente

    /*
     * EditText y TextView que muestran la información almacenada sobre el paciente en cuestión en
     * la BD.
     *
     * En los campos "nombre", "diagnostico", "comentarios_adicionales" y "tags" se utiliza un
     * objeto de tipo EditText para poder desplazarlo horizontalmente si la información escrita
     * es demasiado larga como para entrar en el tamaño del TextView establecido.
     */
    private EditText nombre, diagnostico, comentarios_adicionales, tags;
    private TextView edad, sexo, id;
    private TableLayout listado_mediciones; // Tabla con el listado de mediciones del paciente

    // Bundle donde almacenar los argumentos recibidos en la creación del Fragment
    private Bundle args;

    /**
     * Called when the activity is starting.
     * <p>
     * <p>En este punto se comprueba si se ha pasado información al <tt>Fragment</tt> a través de un
     * Bundle, y, de ser así, es almacenada en las variables globales del <tt>Fragment</tt>.</p>
     *
     * @param savedInstanceState <tt>Bundle</tt>: If the activity is being re-initialized after
     *                           previously being shut down then this <tt>Bundle</tt> contains the
     *                           data it most recently supplied in
     *                           <tt>onSaveInstanceState(Bundle)</tt>. Otherwise it is null.
     */
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Por defecto no se muestra el botón para añadir una nueva medición al paciente
        mostrarOpcionesNuevaMedicion = false;

        // Obtención de la instancia de PerfilPacientePresenter
        ((App) getActivity().getApplication()).getComponent(this).injectPerfilPacienteFragment(this);

        args = getArguments();

        // Se comprueba si se ha pasado información en el Bundle
        if (args != null) {
            // Solicitar la información al Presentador
            presenter.onCreate();
        }
    }

    /**
     * Método llamado para instanciar el <tt>Fragment</tt> con su layout asociada
     * (R.layout.perfil_paciente_fragment, en este caso).
     *
     * <p>Se encarga de mostrar al usuario la información que se tiene almacenada en la Base de Datos
     * sobre ese paciente (tanto datos personales como mediciones que se han realizado sobre él).
     * Además, se encarga de mostrar/ocultar el botón para borrar el perfil del paciente y añadir
     * una nueva medición al paciente, en función del valor de las variables globales empleadas para
     * controlar ese comportamiento.</p>
     *
     * <p>Por último, se encarga de notificar a <tt>PerfilPacientePresenter</tt> cuando el usuario
     * ha pulsado sobre el botón para añadir una nueva medición.</p>
     *
     * @param inflater The LayoutInflater object that can be used to inflate any view in the
     *                 fragment.
     * @param container If non-null, this is the parent view that the fragment's UI should be
     *                  attached to. The fragment should not add the view itself, but this can be
     *                  used to generate the LayoutParams of the view.
     * @param savedInstanceState If non-null, this fragment is being re-constructed from a previous
     *                           saved state as given here. Return the View for the fragment's UI,
     *                           or null.
     */
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             Bundle savedInstanceState) {

        // Inflar el layout del Fragment
        View vista = inflater.inflate(R.layout.perfil_paciente_fragment, container, false);

        /*
         * Bindeo de los EditText y TextView donde se muestra la información que se tiene del
         * paciente en la BD
         */
        nombre = (EditText) vista.findViewById(R.id.nombre_editText);
        edad = (TextView) vista.findViewById(R.id.edad_textView);
        sexo = (TextView) vista.findViewById(R.id.sexo_textView);
        id = (TextView) vista.findViewById(R.id.id_textView);
        diagnostico = (EditText) vista.findViewById(R.id.diagnostico_editText);
        comentarios_adicionales = (EditText) vista.findViewById(R.id.comentarios_adicionales_editText);
        tags = (EditText) vista.findViewById(R.id.tags_editText);

        // Bindeo de los botones para almacenar una nueva medición y borrar el perfil del paciente
        Button almacenar_medicion = (Button) vista.findViewById(R.id.almacenar_nueva_medicion);
        Button borrar_perfil_paciente = (Button) vista.findViewById(R.id.borrar_perfil);

        // Se añade un evento "onClickListener" al botón de borrar el perfil del paciente
        borrar_perfil_paciente.setOnClickListener(this);

        // Se actualiza el valor de la variable "mostrarOpcionesNuevaMedicion", desde el Modelo
        presenter.onCreateView();

        /*
         * Comprobar si es necesario mostrar los botones para borrar el perfil del paciente y
         * añadir una nueva medición
         */
        if (!mostrarOpcionesBorrarPaciente)
            borrar_perfil_paciente.setVisibility(View.GONE);
        else
            borrar_perfil_paciente.setVisibility(View.VISIBLE);

        if (mostrarOpcionesNuevaMedicion) {
            almacenar_medicion.setVisibility(View.VISIBLE);

            /*
             * Notificar a PerfilPacientePresenter cuando el usuario pulse sobre el botón para
             * añadir una nueva medición
             */
            almacenar_medicion.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    presenter.onAlmacenarMedicionClicked(nombrePaciente, idPaciente,
                            lectura_goniometro, fechaHora);
                }
            });
        } else
            almacenar_medicion.setVisibility(View.GONE);

        // Mostrar al usuario la información que se tiene almacenada sobre el paciente
        presenter.mostrarInformacionPaciente(nombrePaciente, idPaciente);

        // Bindeo del TableLayout donde se muestran todas las mediciones realizadas al paciente
        listado_mediciones = (TableLayout) vista.findViewById(R.id.listado_mediciones);
        // Mostrar al usuario todas las mediciones del paciente
        presenter.mostrarMedicionesPaciente(nombrePaciente, idPaciente);

        return vista;
    }

    /**
     * Método "setter" para actualizar el valor de la variable "mostrarOpcionesNuevaMedicion" con el
     * fin de gestionar si es necesario mostrar o no el botón para añadir una nueva medición al
     * paciente.
     *
     * @param mostrarOpcionesNuevaMedicion Valor nuevo para actualizar la variable
     */
    public void setMostrarOpcionesNuevaMedicion(boolean mostrarOpcionesNuevaMedicion) {
        this.mostrarOpcionesNuevaMedicion = mostrarOpcionesNuevaMedicion;
    }

    /**
     * Método "setter" para actualizar el valor de la variable "mostrarOpcionesBorrarPaciente" con
     * el fin de gestionar si es necesario mostrar o no el botón para borrar el perfil de un
     * paciente.
     *
     * @param mostrarOpcionesBorrarPaciente Valor nuevo para actualizar la variable
     */
    public void setMostrarOpcionesBorrarPaciente(boolean mostrarOpcionesBorrarPaciente) {
        this.mostrarOpcionesBorrarPaciente = mostrarOpcionesBorrarPaciente;
    }

    /**
     * Evento <tt>ClickListener</tt> que se llama cuando el usuario ha pulsado sobre el botón
     * para borrar el perfil del paciente actual.
     *
     * Se encarga de notificar a <tt>PerfilPacientePresenter</tt> de esta situación, pasando como
     * parámetro el nombre del paciente a borrar.
     *
     * @param view <tt>View</tt> sobre la que se aplica
     */
    @Override
    public void onClick(View view) {
        presenter.onDeletePatientClicked(nombrePaciente, idPaciente);
    }

    /**
     * Método que se encarga de asignar a las variables locales, la información contenida en el
     * <tt>Bundle</tt>
     *
     * @param constantesBundle <tt>ArrayList<String></tt> con las constantes para obtener la
     *                         información del <tt>Bundle</tt>
     */
    @Override
    public void setConstantesBundle(ArrayList<String> constantesBundle) {
        nombrePaciente = args.getString(constantesBundle.get(0));
        idPaciente = args.getInt(constantesBundle.get(1));
        lectura_goniometro = args.getDouble(constantesBundle.get(2));
        fechaHora = args.getString(constantesBundle.get(3));
    }

    /**
     * Método que se encarga de escribir en el <tt>TextView</tt> indicado el texto que recibe como
     * parámetro.
     *
     * @param textView <tt>TextView</tt> en el que se debe escribir
     * @param text Texto a escribir
     */
    @Override
    public void setText(int textView, String text) {
        // Selección múltiple del TextView sobre el que escribir el texto
        switch (textView) {
            case 0:
                nombre.setText(text);
                break;
            case 1:
                edad.setText(text);
                break;
            case 2:
                sexo.setText(text);
                break;
            case 3:
                id.setText(text);
                break;
            case 4:
                diagnostico.setText(text);
                break;
            case 5:
                comentarios_adicionales.setText(text);
                break;
            case 6:
                tags.setText(text);
                break;
        }
    }

    /**
     * Método que se encarga de añadir una <tt>View</tt> hija al <tt>Table Layout</tt> que
     * contiene el listado de mediciones del paciente
     *
     * @param view <tt>View</tt> hija a añadir
     */
    @Override
    public void addView(View view) {
        listado_mediciones.addView(view);
    }

    /**
     * Método que simplemente muestra el <tt>AlertDialog</tt> que ha recibido como parámetro.
     *
     * @param dialog <tt>AlertDialog</tt> a mostrar
     */
    @Override
    public void displayResult(AlertDialog dialog) {
        dialog.show();
    }

    /**
     * Método que muestra un mensaje de éxito cuando se ha logrado eliminar correctamente un
     * paciente de la Base de Datos.
     */
    @Override
    public void displaySuccess() {
        Toast toast = Toast.makeText(getActivity(), R.string.delete_patient_success,
                Toast.LENGTH_LONG);

        TextView textView = (TextView) toast.getView().findViewById(android.R.id.message);

        if (textView != null)
            textView.setGravity(Gravity.CENTER); // Centrar el mensaje en el Toast

        toast.show();
    }

    /**
     * Método que muestra un mensaje de error cuando se ha intentado eliminar un paciente de la Base
     * de Datos.
     */
    @Override
    public void displayError() {
        Toast toast = Toast.makeText(getActivity(),
                R.string.delete_patient_error, Toast.LENGTH_LONG);

        TextView textView = (TextView) toast.getView().findViewById(android.R.id.message);

        if (textView != null)
            textView.setGravity(Gravity.CENTER); // Centrar el mensaje en el Toast

        toast.show();
    }

    /**
     * Perform any final cleanup before an activity is destroyed.
     */
    @Override
    public void onDestroy() {
        presenter.onDestroy();
        super.onDestroy();
    }
}
