package com.virtual.tour.arquelogia.controlador;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.hardware.SensorManager;
import android.location.Location;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;

import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.PolylineOptions;
import com.virtual.tour.arquelogia.R;
import com.virtual.tour.arquelogia.modelo.AdminSQLiteOpenHelper;
import com.virtual.tour.arquelogia.modelo.GPSTracker;
import com.virtual.tour.arquelogia.modelo.PuntoGps;
import com.virtual.tour.arquelogia.vista.MainActivity;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

/**
 * Created by Roger
 */
public class Controlador {

    //Variables Globales
    private GPSTracker gps;
    private EditText mostrarCoordenadas;
    private Context contexto;
    private float grados;
    private SQLiteDatabase bd;
    private AdminSQLiteOpenHelper admin;
    private Timer timer;
    private TimerTask timerTask;
    final Handler handler = new Handler();
    private String nombreArchivo = "";
    private String nombrePuntoImportante = "inicial";
    private Boolean importante = true;
    private ProgressDialog barProgressDialog;
    private boolean inicial = true;
    private ImageButton botonGuardar;
    private int tamanoVentana = 11;
    private ArrayList<PuntoGps> rutaMedia = null;
    SharedPreferences prefs = null;
    private int out = 0;
    private int timeout = 60;
    private SensorManager sensor;
    private ImageButton botonEmpezar;
    private static Controlador singletonInstance;
    private int buscandoPosicion = 0;
    private int tiempoMaxPosicion = 6;
    private int intervaloCaptura=0;
    private Location locationTemp;
    private boolean primeraEntrada = true;
    private ImageButton botonImportante;


    /**
     * Constructor de la clase, guarda todos los elementos necesarios para poder controlar los elementos de las activitys.
     *
     * @param coordenadas , donde se muestran las coordenadas.
     * @param btnGuardar, boton de guardado.
     * @param emp,        boton de Inicio y stop segun el estado.
     * @param imp,        boton de punto importante.
     * @param sens        , sensor de movimiento para la dirección a la cual estamos mirando.
     * @param context     , contexto de la activity MainActivity.
     */
    public Controlador(EditText coordenadas, ImageButton btnGuardar, ImageButton emp, ImageButton imp, SensorManager sens, Context context) {
        mostrarCoordenadas = coordenadas;
        botonGuardar = btnGuardar;
        contexto = context;
        botonEmpezar = emp;
        botonImportante = imp;
        sensor = sens;
        //leemos de preferencias el tañano de la ventana y el tiempo de captura de la posicion en la que nos encontramos.
        prefs = PreferenceManager.getDefaultSharedPreferences(contexto.getApplicationContext());
    }

    /**
     * Funcion para comprobar si existe una instancia del controlador, en caso de que exista,
     * devolvemos el controlador, en caso de que no exista  llamamos al constructor de la clase.
     *
     * @param coordenadas , donde se muestran las coordenadas.
     * @param btnGuardar, boton de guardado.
     * @param emp,        boton de Inicio y stop segun el estado.
     * @param imp,        boton de punto importante.
     * @param sens        , sensor de movimiento para la dirección a la cual estamos mirando.
     * @param context     , contexto de la activity MainActivity.
     * @return , devuelve el controlador.
     */
    public static Controlador getSingletonInstance(EditText coordenadas, ImageButton btnGuardar, ImageButton emp, ImageButton imp, SensorManager sens, Context context) {
        if (null == singletonInstance) {
            singletonInstance = new Controlador(coordenadas, btnGuardar, emp, imp, sens, context);

        }
        return singletonInstance;
    }

    /**
     * Iniciamos la BD
     */
    public void iniBd() {
        admin = new AdminSQLiteOpenHelper(contexto, "administracion", null, 1);
        bd = admin.getWritableDatabase();
    }


    /**
     * Inicaliza objeto del gps*
     */
    public void iniGps() {
        gps = new GPSTracker(contexto);
    }

    /**
     * Iniciamos una nueva nueva ruta.
     *
     * @return , devuelve booleano indicando si se ha podido crear la base de datos o no.
     */

    public boolean iniciarNuevaRuta() {

        boolean continuar = false;
        //indicamos que empezamos a guardar puntos.
        this.primeraEntrada = true;
        //comprobamos si existe el gps o no.
        if (gps == null) {
            iniGps();
        }
        //comprovamos que el GPS esta activo.
        continuar = checkActiveGps();

        if (continuar) {
            iniBd();
        }

        //devolvemos si salió correcto o no.
        return continuar;


    }

    /**
     * Función que detiene la ruta en caso de que este activa.
     */

    public void pararNuevaRuta() {
        stopTimerTask();
        stopGPS();
        stopBD();


    }

    /**
     * Función que comprueba si está activo el GPS  o No.
     *
     * @return boolean indicando si el estado del GPS.
     */

    public boolean checkActiveGps() {

        boolean continuar = false;

        //cogemos un punto
        gps.getLocation();

        //si lo hemos podido coger
        if (gps.canGetLocation()) {
			this.buscandoPosicion=0;
            this.intervaloCaptura=Integer.valueOf(prefs.getString("tiempo", "1"));
            this.timeout=60;
            this.timeout = this.timeout / intervaloCaptura;
            this.tiempoMaxPosicion = this.tiempoMaxPosicion / intervaloCaptura;
            //iniciamos el timer que recogerà puntos del GPS
            startTimer();
            continuar = true;

        } else {
            //si el gps no está activo, mostramos un mensaje indicandolo con la opción de ir a la configuración.
            gps.showSettingsAlert();
        }

        //boolean indicando si el GPS esta activo.
        return continuar;

    }

    /**
     * recoge las coordenadas del gps
     */
    public synchronized void getCoordenadas() {
        Location location = gps.getLocation();
        if (gps.canGetLocation()) {
            if (location != null) {
                this.out = 0;
                if (buscandoPosicion < tiempoMaxPosicion) {
                    locationTemp = location;
                    buscandoPosicion += 1;
                } else {
                    if (Double.compare(locationTemp.getLatitude(), location.getLatitude()) != 0 && Double.compare(locationTemp.getLongitude(), location.getLongitude()) != 0) {
                    //if(locationTemp.distanceTo(location)<=5){
                        this.mostrarCoordenadas.setText("");
                        this.mostrarCoordenadas.append("Latitud:" + location.getLatitude() + "\n");
                        this.mostrarCoordenadas.append("Longitud:" + location.getLongitude());


                        alta();
                    } else {

                        this.mostrarCoordenadas.setText("Espera punto repetido\n");
                    }
                    locationTemp=location;
                }

            } else {
                this.out += 1;
                this.mostrarCoordenadas.setText(contexto.getString(R.string.buscando));
                this.mostrarCoordenadas.append("\ntiempo intentos:" +(out*intervaloCaptura));
                if (this.out >= this.timeout) {
                    this.mostrarCoordenadas.setText(contexto.getString(R.string.timeout_gps));
                    this.out = 0;
                    errorFinalizar();
                }
            }

        } else {
            this.mostrarCoordenadas.setText(contexto.getString(R.string.fallo_gps));
            errorFinalizar();
        }
    }

    /**
     * finaliza la ruta en caso de superar el tiempo de espera en la captura
     */
    public void errorFinalizar(){
        this.out=0;
        stopTimerTask();
        stopGPS();
        ((MainActivity) contexto).setEstado(0);
        sensor.unregisterListener(((MainActivity) contexto));
        botonEmpezar.setImageResource(R.drawable.play);
        if (bdLlena()) {
            botonGuardar.setEnabled(true);
            botonGuardar.setImageResource(R.drawable.guardar_azul);
        }
    }

    /**
     * Detiene el gps
     */

    public void stopGPS() {

        if (this.gps != null) {
            this.gps.stopUsingGPS();
        }
    }


    /**
     * Detiene la Base de Datos.
     */

    public void stopBD() {
        if (this.bd != null) {
            bd.close();
            bd = null;
        }
    }

    /**
     * Elimina el contenido de la Base de Datos.
     */

    public void delBd() {
        if (bd == null) {
            iniBd();
        }
        bd.execSQL("delete from rutas");
        bd.execSQL("UPDATE sqlite_sequence SET seq =0");
        bd.close();
        bd = null;
    }


    /**
     * Función que guarda un punto del GPS en la Base de Datos.
     */

    public void alta() {
        if (primeraEntrada) {
            botonImportante.setEnabled(true);
            botonImportante.setImageResource(R.drawable.imp_azul);
            primeraEntrada = false;
        }
        ContentValues registro = new ContentValues();
        registro.put("longitud", gps.getLongitude());
        registro.put("latitud", gps.getLatitude());
        registro.put("grados", this.grados);
        //registro.put("grados", gps.getBearing());
        if (importante) {
            registro.put("importante", this.nombrePuntoImportante);
            importante = false;
            nombrePuntoImportante = "";
            if (!inicial) {
                Toast.makeText(contexto, contexto.getString(R.string.etiqueta_guardada),
                        Toast.LENGTH_SHORT).show();
            }
            if (inicial) {
                inicial = false;
            }
        } else {
            registro.put("importante", "");
        }
        bd.insert("rutas", null, registro);


    }


    /**
     * Función que guarda los datos de la base de datos en un Fichero .txt y un Fichero .Gpx.
     *
     * @param fila consulta a la bd
     */

    public void guardarDatosFichero(Cursor fila) {


        File sdCard = Environment.getExternalStorageDirectory();
        File dir = new File(sdCard.getAbsolutePath());
        dir.mkdir();
        File file = new File(dir, nombreArchivo + ".txt");
        File fileGpx = new File(dir, nombreArchivo + ".gpx");

        Calendar cal = Calendar.getInstance();
        cal.getTime();
        final String TAG = nombreArchivo;

        String header = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n<gpx creator=\"ArcheoloGPS\" version=\"1.0\">\n<name>" + nombreArchivo + "</name>\n";
        String name = "<trk><name>" + TAG + "</name>\n<trkseg>\n";

        String waypoints = "";
        String segments = "";


        String footer = "</trkseg></trk></gpx>";


        FileOutputStream os = null;
        try {
            os = new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        if (rutaMedia == null) {
            while (fila.moveToNext()) {

                String data = fila.getInt(0) + "-" + fila.getString(2) + "-" + fila.getString(1) + "-" + fila.getLong(3) + "-" + fila.getString(4) + "\n";
                segments += "<trkpt lat=\"" + fila.getString(2) + "\" lon=\"" + fila.getString(1) + "\"><time>" + cal.getTime() + "</time></trkpt>\n";
                if (!fila.getString(4).equals("") && !fila.getString(4).equals("inicial")) {
                    waypoints += "<wpt lat=\"" + fila.getString(2) + "\" lon=\"" + fila.getString(1) + "\">" + "<name>" + fila.getString(4) + "</name></wpt>\n";
                }

                try {
                    os.write(data.getBytes());

                    // active the update handler
                    updateBarHandler.sendMessage(updateBarHandler.obtainMessage());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } else {
            for (PuntoGps point : rutaMedia) {
                String data = point.getId() + "-" + point.getLatitud() + "-" + point.getLongitud() + "-" + point.getGrados() + "-" + point.getDescripcion() + "\n";
                segments += "<trkpt lat=\"" + point.getLatitud() + "\" lon=\"" + point.getLongitud() + "\"><time>" + cal.getTime() + "</time></trkpt>\n";
                if (!point.getDescripcion().equals("") && !point.getDescripcion().equals("inicial")) {
                    waypoints += "<wpt lat=\"" + point.getLatitud() + "\" lon=\"" + point.getLongitud() + "\">" + "<name>" + point.getDescripcion() + "</name></wpt>\n";
                }

                try {
                    os.write(data.getBytes());

                    // active the update handler
                    updateBarHandler.sendMessage(updateBarHandler.obtainMessage());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            rutaMedia = null;

        }
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        barProgressDialog.dismiss();


        try {
            os.close();

            //delBd();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            FileWriter writer = new FileWriter(fileGpx, false);
            writer.append(header);
            writer.append(waypoints);
            writer.append(name);
            writer.append(segments);
            writer.append(footer);
            writer.flush();
            writer.close();

        } catch (IOException e) {


        }
        importante = true;
        nombrePuntoImportante = "inicial";

    }


    /**
     * Handler para incrmentar el numero de ficheros processados al guardar la ruta
     */

    Handler updateBarHandler = new Handler() {
        public void handleMessage(Message msg) {

            barProgressDialog.incrementProgressBy(1);

        }
    };

    /**
     * Función que prepara el timer que llamarà a la función que recoje los puntos del GPX cada X segundos.
     */

    public void startTimer() {
        //set a new Timer
        timer = new Timer();
        //initialize the TimerTask's job
        initializeTimerTask();
        //schedule the timer, after the first 2000ms the TimerTask will run every 1000ms
        int tiempo = Integer.valueOf(prefs.getString("tiempo", "1"));
        timer.schedule(timerTask, 2000, tiempo * 1000);
    }

    /**
     * Detiene el timer que que recoje puntos GPS.
     */

    public void stopTimerTask() {
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
    }

    /**
     * Función que inicializa el timer que llama a la función que recoje puntos de la Base de Datos.
     */
    public void initializeTimerTask() {

        timerTask = new TimerTask() {
            public void run() {

                //use a handler to run a toast that shows the current timestamp
                handler.post(new Runnable() {
                    public void run() {
                        //get the current timeStamp
                        getCoordenadas();
                    }
                });
            }
        };
    }

    /**
     * Función que pide un nombre de fichero para la ruta que queremos guardar.Ademàs llama a la función de calcularMediana o clacularMedia para mejorar la ruta
     * en caso de que el usuario así lo haya indicado.Y llama a la funcion de guardado guardarDatosFichero y  la función que muestra la barra de progresso del guardado.
     */
    public void pedirNombre(final int opc, final Context con) {
        if (opc == 2) {
            calcularMedia();
        }
        if (opc == 3) {
            calcularMediana();
        }

        LayoutInflater li = LayoutInflater.from(contexto);
        View promptsView = li.inflate(R.layout.guardar, null);

        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
                con);

        // set guardar.xml to alertdialog builder
        alertDialogBuilder.setView(promptsView);
        AlertDialog alertDialog;

        final EditText userInput = (EditText) promptsView
                .findViewById(R.id.editTextDialogUserInput);

        // set dialog message
        alertDialogBuilder
                .setCancelable(false)
                .setPositiveButton(R.string.guardar,
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                nombreArchivo = userInput.getText().toString();
                                launchBarDialog(opc,con);
                                dialog.dismiss();
                            }
                        })
                .setNegativeButton(R.string.cancelar,
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                rutaMedia = null;
                                dialog.dismiss();
                            }
                        });

        // create alert dialog
        alertDialog = alertDialogBuilder.create();


        // show it
        alertDialog.show();
    }

    /**
     * Función que pide un nombre para un punto que el usuario a considerado como importante.
     */

    public void pedirPuntoImportante() {

        LayoutInflater li = LayoutInflater.from(contexto);
        View promptsView = li.inflate(R.layout.importante, null);

        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
                contexto);

        // set guardar.xml to alertdialog builder
        alertDialogBuilder.setView(promptsView);

        final EditText userInput = (EditText) promptsView
                .findViewById(R.id.editTextNombreImportante);

        // set dialog message
        alertDialogBuilder
                .setCancelable(false)
                .setPositiveButton("Guardar",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                nombrePuntoImportante = userInput.getText().toString();
                                importante = true;
                            }
                        })
                .setNegativeButton("Cancelar",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                dialog.cancel();
                            }
                        });

        // create alert dialog
        AlertDialog alertDialog = alertDialogBuilder.create();

        // show it
        alertDialog.show();

    }

    /**
     * Función que muestra el progreso del guardado de la ruta.
     */
    public void launchBarDialog(int opc,Context con) {

        if (bd == null) {
            iniBd();
        }

        final Cursor fila = bd.rawQuery("select * from rutas", null);

        if (fila.getCount() > 0) {

            barProgressDialog = new ProgressDialog(con);
            barProgressDialog.setCancelable(false);
            barProgressDialog.setMessage(contexto.getString(R.string.guardar_datos));
            barProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            barProgressDialog.setProgress(0);

            if (rutaMedia != null) {
                barProgressDialog.setMax(rutaMedia.size());
            } else {
                barProgressDialog.setMax(fila.getCount());
            }
            // display the progressbar
            barProgressDialog.show();

            Thread background = new Thread(new Runnable() {
                public void run() {

                    guardarDatosFichero(fila);
                }
            });
            background.start();


        } else {
            Toast.makeText(contexto, contexto.getString(R.string.no_datos),
                    Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * Dada una ruta calcula la media de esta Ruta, utilizando para ello una ventana deslizante dl tamaño que haya eligido el usuario en la
     * pantalla de opciones.
     *
     * @return Arraylist con los puntos de la ruta media.
     */
    private ArrayList<PuntoGps> calcularMedia() {
        tamanoVentana = Integer.valueOf(prefs.getString("ventana", "11"));
        ArrayList<PuntoGps> ruta = new ArrayList<>();
        rutaMedia = new ArrayList<>();
        ruta = getRuta();
        int contador = 0;
        boolean puntIni = true;
        PuntoGps puntoImp = null;
        while (contador + this.tamanoVentana <= ruta.size() - 1) {
            double total_lat = 0;
            double total_long = 0;
            float total_grados = 0;
            puntoImp = null;
            for (int i = contador; i < contador + tamanoVentana; i++) {
                if (!ruta.get(i).getDescripcion().equals("") && i == contador + (tamanoVentana / 2) || ruta.get(i).getDescripcion().equals("inicial") && puntIni) {
                    if (ruta.get(i).getDescripcion().equals("inicial")) {
                        puntIni = false;
                    }
                    puntoImp = ruta.get(i);

                }

                total_lat = total_lat + (ruta.get(i).getLatitud());
                total_long = total_long + (ruta.get(i).getLongitud());
                total_grados = total_grados + (ruta.get(i).getGrados());

            }
            total_lat = total_lat / tamanoVentana;
            total_long = total_long / tamanoVentana;
            total_grados = total_grados / tamanoVentana;
            if (puntoImp != null) {
                rutaMedia.add(new PuntoGps(contador, total_lat, total_long, total_grados, puntoImp.getDescripcion()));
            } else {
                rutaMedia.add(new PuntoGps(contador, total_lat, total_long, total_grados, ""));
            }

            contador += 1;
        }
        double total_lat = 0;
        double total_long = 0;
        float total_grados = 0;
        puntoImp = null;
        int divisor = 0;
        for (int i = contador; i <= ruta.size() - 1; i++) {
            divisor += 1;
            total_lat = total_lat + (ruta.get(i).getLatitud());
            total_long = total_long + (ruta.get(i).getLongitud());
            total_grados = total_grados + (ruta.get(i).getGrados());
            if (!ruta.get(i).getDescripcion().equals("")) {
                puntoImp = ruta.get(i);
            }

        }
        total_lat = total_lat / divisor;
        total_long = total_long / divisor;
        total_grados = total_grados / divisor;
        if (puntoImp != null) {
            rutaMedia.add(new PuntoGps(contador, total_lat, total_long, total_grados, puntoImp.getDescripcion()));
        } else {
            rutaMedia.add(new PuntoGps(contador, total_lat, total_long, total_grados, ""));
        }


        return rutaMedia;
    }


    /**
     * Dada una ruta calcula la mediana de esta Ruta, utilizando para ello una ventana deslizante dl tamaño que haya eligido el usuario en la
     * pantalla de opciones.
     *
     * @return Arraylist con los puntos de la ruta mediana.
     */

    private ArrayList<PuntoGps> calcularMediana() {
        tamanoVentana = Integer.valueOf(prefs.getString("ventana", "11"));
        ArrayList<PuntoGps> ruta = new ArrayList<>();
        rutaMedia = new ArrayList<>();


        ruta = getRuta();
        int contador = 0;
        boolean puntIni = true;
        PuntoGps puntoImp = null;
        while (contador + (this.tamanoVentana) <= ruta.size() - 1) {
            ArrayList<Double> latitud = new ArrayList<>();
            ArrayList<Double> longitud = new ArrayList<>();
            ArrayList<Float> grados = new ArrayList<>();
            puntoImp = null;
            for (int i = contador; i < contador + tamanoVentana; i++) {
                if (!ruta.get(i).getDescripcion().equals("") && i == contador + (tamanoVentana / 2) || ruta.get(i).getDescripcion().equals("inicial") && puntIni) {
                    if (ruta.get(i).getDescripcion().equals("inicial")) {
                        puntIni = false;
                    }
                    puntoImp = ruta.get(i);

                }

                latitud.add(ruta.get(i).getLatitud());
                longitud.add(ruta.get(i).getLongitud());
                grados.add(ruta.get(i).getGrados());

            }
            Collections.sort(latitud);
            Collections.sort(longitud);
            Collections.sort(grados);
            double medianLatitud;
            double medianLongitud;
            float medianGrados;
            medianLatitud = (double) latitud.get((latitud.size() / 2));
            medianLongitud = (double) longitud.get((longitud.size() / 2));
            medianGrados = (float) grados.get((grados.size() / 2));


            if (puntoImp != null) {
                rutaMedia.add(new PuntoGps(contador, medianLatitud, medianLongitud, medianGrados, puntoImp.getDescripcion()));
            } else {
                rutaMedia.add(new PuntoGps(contador, medianLatitud, medianLongitud, medianGrados, ""));
            }

            contador += 1;
        }
        ArrayList<Double> latitud = new ArrayList<>();
        ArrayList<Double> longitud = new ArrayList<>();
        ArrayList<Float> grados = new ArrayList<>();
        puntoImp = null;
        for (int i = contador; i <= ruta.size() - 1; i++) {
            latitud.add(ruta.get(i).getLatitud());
            longitud.add(ruta.get(i).getLongitud());
            grados.add(ruta.get(i).getGrados());
            if (!ruta.get(i).getDescripcion().equals("")) {
                puntoImp = ruta.get(i);
            }
        }
        Collections.sort(latitud);
        Collections.sort(longitud);
        Collections.sort(grados);
        double medianLatitud;
        double medianLongitud;
        float medianGrados;
        if (latitud.size() % 2 == 0)
            medianLatitud = ((double) latitud.get(latitud.size() / 2 + 1) + (double) latitud.get(latitud.size() / 2)) / 2;
        else
            medianLatitud = (double) latitud.get((latitud.size() / 2));
        if (longitud.size() % 2 == 0)
            medianLongitud = ((double) longitud.get(longitud.size() / 2 + 1) + (double) longitud.get(longitud.size() / 2)) / 2;
        else
            medianLongitud = (double) longitud.get((longitud.size() / 2));
        if (latitud.size() % 2 == 0)
            medianGrados = ((float) grados.get(grados.size() / 2 + 1) + (float) grados.get(grados.size() / 2)) / 2;
        else
            medianGrados = (float) grados.get((grados.size() / 2));
        if (puntoImp != null) {
            rutaMedia.add(new PuntoGps(contador, medianLatitud, medianLongitud, medianGrados, puntoImp.getDescripcion()));
        } else {
            rutaMedia.add(new PuntoGps(contador, medianLatitud, medianLongitud, medianGrados, ""));
        }


        return rutaMedia;
    }


    /**
     * Función que comprueba si la BD esta llena o vacía.
     *
     * @return boolean indicando si la BD esta llena o vacía.
     */
    public boolean bdLlena() {

        if (bd == null) {
            iniBd();
        }
        boolean llena = false;

        final Cursor fila = bd.rawQuery("select * from rutas", null);

        if (fila.getCount() > 0) {
            llena = true;
        }
        return llena;

    }


    /**
     * Función que muestra los puntos de una ruta en el Google Maps
     *
     * @param map
     */


    public void crearMap(GoogleMap map) {
        ArrayList<PuntoGps> puntosRuta = getRuta();
        map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
        map.setMyLocationEnabled(true);
        PolylineOptions options = new PolylineOptions().width(5).color(Color.BLUE).geodesic(true);
        for (int z = 0; z < puntosRuta.size(); z++) {
            LatLng point = new LatLng(puntosRuta.get(z).getLatitud(), puntosRuta.get(z).getLongitud());
            if (z == 0) {
                map.addMarker(new MarkerOptions().position(point).title("Inicio")).showInfoWindow();
                CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(point, 18);
                map.animateCamera(cameraUpdate);
            }
            if (!puntosRuta.get(z).getDescripcion().equals("") && puntosRuta.get(z).getDescripcion() != "inicial") {
                MarkerOptions marker = (new MarkerOptions().position(point).title(puntosRuta.get(z).getDescripcion()));
                marker.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE));
                map.addMarker(marker);
            }
            if (z==puntosRuta.size()-1){
                map.addMarker(new MarkerOptions().position(point).title("Fin")).showInfoWindow();
            }
            options.add(point);
        }
        map.addPolyline(options);
    }


    /**
     * Función que lee los puntos de la BD y los introduce en un arrayList para ser usados por otras funciones.
     *
     * @return
     */
    public ArrayList<PuntoGps> getRuta() {
        ArrayList<PuntoGps> ruta = new ArrayList<>();
        final Cursor fila = bd.rawQuery("select * from rutas", null);
        PuntoGps point = null;

        while (fila.moveToNext()) {
            point = new PuntoGps(Integer.valueOf(fila.getString(0)), Double.valueOf(fila.getString(2)), Double.valueOf(fila.getString(1)), fila.getLong(3), fila.getString(4));
            ruta.add(point);
        }
        return ruta;
    }


    /**
     *Setter de los grados a los que mira el dispositivo.
     * @param grados
     */
    public void setGrados(float grados) {
        this.grados = grados;
    }

    /**
     * Comprueba si el dispositivo tiene internet.
     * @param con contexto de la activity.
     * @return boleano indicando si hay o no internet.
     */

    public boolean isConnectingToInternet(Context con) {
        ConnectivityManager connectivity = (ConnectivityManager) con.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivity != null) {
            NetworkInfo[] info = connectivity.getAllNetworkInfo();
            if (info != null)
                for (int i = 0; i < info.length; i++)
                    if (info[i].getState() == NetworkInfo.State.CONNECTED) {
                        return true;
                    }

        }
        return false;
    }
}
