package com.uva.rafael.tfg_goniometer.presenter;

import android.app.Activity;
import android.app.Fragment;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

import com.uva.rafael.tfg_goniometer.R;
import com.uva.rafael.tfg_goniometer.interfaces.PresenterFunctions;
import com.uva.rafael.tfg_goniometer.model.MainModel;
import com.uva.rafael.tfg_goniometer.view.MainActivity;
import com.uva.rafael.tfg_goniometer.view.fragments.HomeFragment;
import com.uva.rafael.tfg_goniometer.view.fragments.MedicionFragment;
import com.uva.rafael.tfg_goniometer.view.fragments.PacientesFragment;
import com.uva.rafael.tfg_goniometer.view.fragments.SobreAppFragment;
import com.uva.rafael.tfg_goniometer.view.fragments.UltimasMedicionesFragment;

/**
 * Este es el Presentador asociado a la actividad principal de la aplicación (<tt>MainActivity</tt>).
 * Se encarga de llevar a cabo toda la lógica asociada a las acciones del usuario realizadas en la IU.
 *
 * <p>Estas tareas consisten en crear y añadir el <tt>Fragment HomeFragment</tt> inicial de
 * la aplicación, inicializar la clase de tipo <tt><SQLiteHelper/tt> que servira de conexión con la
 * BD (<tt>GoniometerDBHelper</tt>). Ademas, gestiona el comportamiento de la aplicación cuando
 * se pulsa sobre un elemento del <tt>NavigationView</tt>.</p>
 *
 * <p>Esta clase forma parte de la aplicación TFG-Goniometer, desarrollada para el Trabajo de
 * Fin de Grado - Grado en Ingeniería Informatica (Universidad de Valladolid)</p>
 *
 * @author Rafael Matamoros Luque
 * @see DrawerLayout
 * @see NavigationView
 * @see MainActivity
 * @see MainModel
 * @version 1.0
 */
public class MainPresenter implements PresenterFunctions, PresenterFunctions.MainFunctions {

    private final MainModel model;
    // Referencias a la actividad (Vista) con la que esta asociado y al Modelo de la aplicación
    private MainActivity activity;
    // Referencias al NavigationView y DrawerLayout obtenidos desde MainActivity
    private NavigationView navigationView;
    private DrawerLayout drawerLayout;

    /**
     * Constructor principal de la clase.
     *
     * @param activity Actividad (Vista) con la que mantiene una relación 1-a-1.
     * @param model    Modelo (único) de la aplicación.
     */
    public MainPresenter(Activity activity, MainModel model) {
        this.activity = (MainActivity) activity;
        this.model = model;
    }

    /**
     * Método que realiza las operaciones iniciales cuando se crea la actividad
     * <tt>MainActivity</tt>.
     *
     * Crea el <tt>Fragment</tt> inicial de la aplicación (<tt>HomeFragment</tt>) y lo añade
     * al contenedor de <tt>Fragments</tt>. Ademas, proporciona el <tt>Context</tt> a la clase
     * <tt>SQLiteHelper</tt> que sirve de conexión con la BD (<tt>GoniometerDBHelper</tt>).
     */
    @Override
    public void setUpInitialSettings() {
        //Fragmento inicial "Home" de la App
        HomeFragment homeFragment = new HomeFragment();

        activity.getFragmentManager()
                .beginTransaction()
                .add(R.id.content_frame, homeFragment)
                .commit();

        // Realizar las operaciones de inicialización del Modelo a partir del Context
        model.setInitialSettings(activity);
    }

    /**
     * Método que obtiene las referencias al <tt>NavigationView</tt> y <tt>DrawerLayout</tt> de
     * <tt>MainActivity</tt>. Ademas asigna un evento de tipo <tt>NavigationItemListener</tt> al
     * <tt>NavigationView</tt> y crea los respectivos <tt>Fragments</tt> cuando se pulsa sobre uno
     * de los elementos del mismo.
     *
     * @param navigationView Menú sobre el que se aplicara el evento <tt>NavigationItemListener</tt>
     * @param drawerLayout DrawerLayout que contiene al <tt>NavigationView</tt>
     */
    @Override
    public void setNavigationItemSelectedListener(NavigationView navigationView,
                                                  final DrawerLayout drawerLayout) {
        // Obtención de las referencias desde MainActivity
        this.navigationView = navigationView;
        this.drawerLayout = drawerLayout;

        // Bloquear el DrawerLayout para que sólo se pueda abrir pulsando sobre el icono
        drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);

        // Creación y asignación del evento Listener sobre el NavigationView
        navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                Fragment fragment;

                // Menú lateral
                switch (item.getItemId()) {
                    case R.id.menu_home:

                        // Pantalla principal de la aplicación

                        fragment = activity.getFragmentManager().findFragmentById(R.id.content_frame);

                        /*
                         * Antes de crear un nuevo Fragment, se comprueba que no se encuentra
                         * ya en un Fragment de ese tipo.
                         */
                        if (!(fragment instanceof HomeFragment)) {
                            HomeFragment homeFragment = new HomeFragment();

                            activity.getFragmentManager()
                                    .beginTransaction()
                                    .replace(R.id.content_frame, homeFragment)
                                    .addToBackStack("HomeFragment")
                                    .commit();
                        }

                        break;

                    case R.id.menu_nueva_medicion:

                        // "NUEVA MEDICIÓN"

                        fragment = activity.getFragmentManager().findFragmentById(R.id.content_frame);

                        /*
                         * Antes de crear un nuevo Fragment, se comprueba que no se encuentra
                         * ya en un Fragment de ese tipo.
                         */
                        if (!(fragment instanceof MedicionFragment)) {
                            MedicionFragment medicionFragment = new MedicionFragment();

                            activity.getFragmentManager()
                                    .beginTransaction()
                                    .replace(R.id.content_frame, medicionFragment)
                                    .addToBackStack("MedicionFragment")
                                    .commit();
                        }

                        break;

                    case R.id.menu_ultimas_mediciones:

                        // "ÚLTIMAS 10 MEDICIONES"

                        fragment = activity.getFragmentManager().findFragmentById(R.id.content_frame);

                        /*
                         * Antes de crear un nuevo Fragment, se comprueba que no se encuentra
                         * ya en un Fragment de ese tipo.
                         */
                        if (!(fragment instanceof UltimasMedicionesFragment)) {
                            UltimasMedicionesFragment ultimasMedicionesFragment =
                                    new UltimasMedicionesFragment();

                            activity.getFragmentManager()
                                    .beginTransaction()
                                    .replace(R.id.content_frame, ultimasMedicionesFragment)
                                    .addToBackStack("UltimasMedicionesFragment")
                                    .commit();
                        }
                        break;

                    case R.id.menu_pacientes:

                        // "PERFILES DE PACIENTES"

                        fragment = activity.getFragmentManager().findFragmentById(R.id.content_frame);

                        /*
                         * Antes de crear un nuevo Fragment, se comprueba que no se encuentra
                         * ya en un Fragment de ese tipo.
                         */
                        if (!(fragment instanceof PacientesFragment)) {
                            PacientesFragment pacientesFragment = new PacientesFragment();

                            activity.getFragmentManager()
                                    .beginTransaction()
                                    .replace(R.id.content_frame, pacientesFragment)
                                    .addToBackStack("PacientesFragment")
                                    .commit();
                        }
                        break;

                    case R.id.menu_sobre_app:

                        // "Sobre TFG-Goniometer"

                        fragment = activity.getFragmentManager().findFragmentById(R.id.content_frame);

                        /*
                         * Antes de crear un nuevo Fragment, se comprueba que no se encuentra
                         * ya en un Fragment de ese tipo.
                         */
                        if (!(fragment instanceof SobreAppFragment)) {
                            SobreAppFragment sobreAppFragment = new SobreAppFragment();

                            activity.getFragmentManager()
                                    .beginTransaction()
                                    .replace(R.id.content_frame, sobreAppFragment)
                                    .addToBackStack("SobreAppFragment")
                                    .commit();
                        }
                        break;
                }

                // Una vez se ha hecho "click" sobre un elemento del NavigationView, se cierra el menú
                drawerLayout.closeDrawers();

                // Se devuelve "true" para que se muestren los cambios
                return true;
            }
        });
    }

    /**
     * Initialize the contents of the Activity's standard options menu.
     *
     * @param menu The options menu in which we place our items.
     */
    @Override
    public void onCreateOptionsMenu(Menu menu) {
        MenuInflater menuInflater = activity.getMenuInflater();
        menuInflater.inflate(R.menu.menu_lateral, menu);
    }

    /**
     * Prepare the Screen's standard options menu to be displayed
     *
     * @param menu The options menu as last shown or first initialized by
     *             <tt>onCreateOptionsMenu()</tt>.
     */
    @Override
    public void onPrepareOptionsMenu(Menu menu) {
        menu.clear();
    }

    /**
     * This hook is called whenever an item in your options menu is selected.
     *
     * @param item The menu item that was selected.
     * @return Return false to allow normal menu processing to proceed, true to consume it here.
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                drawerLayout.openDrawer(GravityCompat.START);
                return true;
        }
        return false;
    }

    /**
     * Método que se emplea para marcar como seleccionado uno de los distintos items en el
     * <tt>NavigationView</tt>.
     *
     * @param code Posición del item a marcar dentro del <tt>NavigationView</tt>
     */
    @Override
    public void setNavigationItem(int code) {
        if (!(navigationView.getMenu().getItem(code).isChecked()))
            navigationView.getMenu().getItem(code).setChecked(true);
    }

    /**
     * Called when the activity (<tt>MainActivity</tt>) has detected the user's press of the back key.
     */
    @Override
    public void onBackPressed() {
        // Se comprueba si el DrawerLayout esta abierto, de ser así, se cierra
        if (drawerLayout.isDrawerOpen(navigationView))
            drawerLayout.closeDrawers();
    }

    /**
     * Perform any final cleanup before an activity is destroyed.
     *
     * Se encarga de liberar la referencia a la <tt>Activity</tt> con la que esta asociado.
     */
    @Override
    public void onDestroy() {
        activity = null;
    }
}
