package com.cc.infosur.map;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

import com.cc.infosur.greendao.DaoMaster;
import com.cc.infosur.greendao.DaoMaster.DevOpenHelper;
import com.cc.infosur.greendao.DaoSession;
import com.cc.infosur.greendao.Day;
import com.cc.infosur.greendao.DayDao;
import com.cc.infosur.greendao.DbLine;
import com.cc.infosur.greendao.DbPoint;
import com.cc.infosur.greendao.Fauna;
import com.cc.infosur.greendao.Flora;
import com.cc.infosur.greendao.Heritage;
import com.cc.infosur.greendao.Service;
import com.cc.infosur.greendao.ServiceDao;
import com.cc.infosur.greendao.Step;
import com.cc.infosur.greendao.Trip;
import com.cc.infosur.greendao.TripDao;
import com.cc.infosur.main.MainActivity;
import com.cc.infosur.main.MockLocationProvider;
import com.cc.infosur.main.Var;
import com.cc.infosur.mytrip.ServiceFragment;
import com.cc.infosur.polygon.Point;

import org.osmdroid.api.IGeoPoint;
import org.osmdroid.bonuspack.overlays.MapEventsReceiver;
import org.osmdroid.bonuspack.overlays.Marker;
import org.osmdroid.bonuspack.overlays.Marker.OnMarkerClickListener;
import org.osmdroid.bonuspack.overlays.Polygon;
import org.osmdroid.bonuspack.overlays.Polyline;
import org.osmdroid.tileprovider.tilesource.ITileSource;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.tileprovider.tilesource.XYTileSource;
import org.osmdroid.util.BoundingBoxE6;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapController;
import org.osmdroid.views.MapView;
import org.osmdroid.views.MapView.Projection;
import org.osmdroid.views.overlay.Overlay;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import com.cc.infosur.R;
import com.cc.infosur.routing.Network;

/**
 * Class MapFragment
 */
public class MapFragmentCopie extends Fragment implements MapEventsReceiver {

    // Temporal variables to zoom an area
        private double minLat;
        private double maxLat;
        private double minLong;
        private double maxLong;
        private Point point;

    // Some lists of database objects
        private List<Step> steps;
        private List<Day> days;

    // Lists of markers
        private Polyline markersLine;
        private List<CustomMarker> markers;

    public MainActivity mActivity;
    private LayoutInflater layoutInflater;

    // Database variables
        private SQLiteDatabase db;
        private DevOpenHelper helper;
        private DaoSession daoSession;
        private DaoMaster daoMaster;
        private TripDao tripDao;
        private ServiceDao serviceDao;
        private DayDao dayDao;

        private SQLiteDatabase layersDb;
        private DevOpenHelper layersHelper;
        private DaoSession layersDaoSession;
        private DaoMaster layersDaoMaster;

    // Trip object
        Trip trip;

    // Map tiles sources
        private static MapView map;
        private static MapController mc;
        private final String[] mapURL = { "http://10.112.10.134/maps/kgalagadizoom/" };
        private final String[] mapCycleURL = { "http://c.tile.opencyclemap.org/cycle/" };

    // Temporal variables to know which service or object has been selected
        private Service selectedService;
        private Flora selectedFlora;
        private Fauna selectedFauna;
        private Heritage selectedHeritage;
        private Step selectedCity;
        private static Marker positionMarker;

    // Save current state variables
        private IGeoPoint mapState = null;
        private Boolean mapStateLoad1 = false;
        private Boolean mapStateLoad2 = false;
        private int mapStateZoom = 0;

        private Boolean firstTime = true;
        private String provider;

    // Fake location variables
        private Boolean fakeLocation = false;
        ImageButton myFakeLocationButton;
        MapEventsOverlay mapEventsOverlay;

    // Prev day button
        private ImageButton goToPrevDayButton;
        private TextView txtDay;
        private long dayId;
        private int dayLimit; // last day
        private int totalDays;
        private String titleday;
        private TextView txtNameTrip;

    MySpinner itinerarySpinner;
    private View V;
    ArrayAdapter<String> adapter;
    Marker currentLocationMarker;
    LocationManager locationManager;
    Location loc;
    Network network;
    private static Polyline path;
    List<Polyline> servicePath;
    Polygon serviceArea;

    XYTileSource insidePark;
    ITileSource outsidePark;

    // OnMarkerClickListener, shows context menu (in case of service) or info fragment.
    private OnMarkerClickListener markerClickListener = new OnMarkerClickListener() {
        @Override
        public boolean onMarkerClick(Marker marker, MapView map) {
            CustomMarker customMarker = (CustomMarker) marker;

            // MarkerType = 0
            if (customMarker.getMarkerType() == 0){
                selectedCity = (Step) marker.getRelatedObject();
                InfoFragment fg = new InfoFragment();
                fg.setName(selectedCity.getName());
                fg.setDetails(selectedCity.getDetails());
                fg.setDescriptionNo(0);

                //mActivity.pushFragments("MYTRIP_TAB", fg,mActivity.mStacks.get("MYTRIP_TAB").lastElement(), true);

            // MarkerType = 1
            } else if (customMarker.getMarkerType() == 1) {

                selectedService = (Service) marker.getRelatedObject();
                if (!selectedService.getName().equals("My own"))
                    getActivity().openContextMenu(map);

            // MarkerType = 2
            } else if (customMarker.getMarkerType() == 2) {
                if (mActivity.mStacks.get("MAP_TAB").size() < 2) {

                    selectedFlora = (Flora) marker.getRelatedObject();
                    InfoFragment fg = new InfoFragment();

                    fg.setName(selectedFlora.getSpecie());
                    fg.setDetails(selectedFlora.getDetails());
                    Log.i("MAP", "size of details flora: "
                            + selectedFlora.getDetails().size());
                    fg.setDescriptionNo(0);
                    //mActivity.pushFragments("MAP_TAB", fg, mActivity.mStacks.get("MAP_TAB").lastElement(), true);
                }

            // MarkerType = 3
            } else if (customMarker.getMarkerType() == 3) {
                if (mActivity.mStacks.get("MAP_TAB").size() < 2) {
                    selectedFauna = (Fauna) marker.getRelatedObject();
                    InfoFragment fg = new InfoFragment();
                    fg.setName(selectedFauna.getSpecie());
                    fg.setDetails(selectedFauna.getDetails());
                    fg.setDescriptionNo(0);
                    //mActivity.pushFragments("MAP_TAB", fg, mActivity.mStacks.get("MAP_TAB").lastElement(), true);
                }

            // MarkerType = 4
            } else if (customMarker.getMarkerType() == 4) {
                if (mActivity.mStacks.get("MAP_TAB").size() < 2) {
                    selectedHeritage = (Heritage) marker.getRelatedObject();
                    InfoFragment fg = new InfoFragment();
                    fg.setName(selectedHeritage.getName());
                    fg.setDetails(selectedHeritage.getDetails());
                    fg.setDescriptionNo(0);
                    //mActivity.pushFragments("MAP_TAB", fg, mActivity.mStacks.get("MAP_TAB").lastElement(), true);
                }
            }
            return false;
        }
    };


    /**
     * Function onCreateContextMenu()
     * @param menu
     * @param v
     * @param menuInfo
     *
     * Context Menu : Zoom / Route / Description
     */
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);

        MenuInflater inflater = getActivity().getMenuInflater();
        menu.setHeaderTitle(selectedService.getName());
        inflater.inflate(R.menu.map, menu);
    }


    /**
     * Function showTimeFencingDialog()
     *
     * Display a dialog message which warns the traveler that the park is nearly going to close
     */
    public void showTimeFencingDialog() {

        new AlertDialog.Builder(getActivity())
                .setTitle("Time Fencing - Closing Park")
                .setMessage("The park is nearly going to close. Please go to your next accommodation.")
                .setNegativeButton("Dismiss",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,
                                                int which) {
                                dialog.dismiss();
                            }
                        }).show();

    }


    /**
     * Function showGpsDialog()
     *
     * Display a dialog message which warns the traveler that the GPS is required to get his current location
     */
    public void showGpsDialog() {

        new AlertDialog.Builder(getActivity())
                .setTitle("GPS not available")
                .setMessage("The GPS is required to get your current location.")
                .setNegativeButton("Dismiss",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,
                                                int which) {
                                dialog.dismiss();
                            }
                        }).show();

    }


    /**
     * Function onContextItemSelected()
     * @param item
     * @return
     *
     * Executes an action depending on what has been tapped
     */
    @Override
    public boolean onContextItemSelected(MenuItem item) {


        switch (item.getItemId()) {

            // ZOOM
            case R.id.zoom:
                // Case of zoom, zooms to the area, path or point of the service
                clearMap();
                System.out.println(" :: SENSA :: selectedService.getServiceMap() " + selectedService.getServiceMap());

                if (selectedService.getServiceMap() == 0) {

                    BoundingBoxE6 boundingBox = new BoundingBoxE6(
                            selectedService.getLatitude(),
                            selectedService.getLongitude(),
                            selectedService.getLatitude(),
                            selectedService.getLongitude());
                    map.zoomToBoundingBox(boundingBox);

                } else if (selectedService.getServiceMap() == 1) {
                    for (DbLine line : selectedService.getLines()) {
                        Polyline polyline = new Polyline(getActivity());
                        // CHANGE COLOR
                        //polyline.setColor(Color.BLUE);
                        polyline.setColor(getResources().getColor(R.color.green_light));

                        polyline.setWidth(4f);
                        for (DbPoint point : line.getPoints()) {
                            polyline.addPoint(new GeoPoint(point.getLatitude(),
                                    point.getLongitude()));
                        }
                        servicePath.add(polyline);
                    }
                    map.getOverlays().addAll(servicePath);
                    BoundingBoxE6 boundingBox = new BoundingBoxE6(
                            selectedService.getLines().get(0).getPoints().get(0)
                                    .getLatitude(),
                            selectedService.getLines().get(0).getPoints().get(0)
                                    .getLongitude(),
                            selectedService
                                    .getLines()
                                    .get(selectedService.getLines().size() - 1)
                                    .getPoints()
                                    .get(selectedService
                                            .getLines()
                                            .get(selectedService.getLines().size() - 1)
                                            .getPoints().size() - 1).getLatitude(),
                            selectedService
                                    .getLines()
                                    .get(selectedService.getLines().size() - 1)
                                    .getPoints()
                                    .get(selectedService
                                            .getLines()
                                            .get(selectedService.getLines().size() - 1)
                                            .getPoints().size() - 1).getLongitude());
                    map.zoomToBoundingBox(boundingBox);
                    map.getController().zoomOut();
                } else if (selectedService.getServiceMap() == 2) {
                    serviceArea = new Polygon(getActivity());
                    // CHANGE COLOR
                    serviceArea.setFillColor(Color.BLUE);
                    //serviceArea.setFillColor(getResources().getColor(R.color.green_light));
                    serviceArea.setStrokeWidth(4f);
                    double north = selectedService.getPolygon().getPoints().get(0)
                            .getLatitude();
                    double south = selectedService.getPolygon().getPoints().get(0)
                            .getLatitude();
                    double east = selectedService.getPolygon().getPoints().get(0)
                            .getLongitude();
                    double west = selectedService.getPolygon().getPoints().get(0)
                            .getLongitude();
                    List<GeoPoint> pointsList = new ArrayList<GeoPoint>();
                    for (DbPoint point : selectedService.getPolygon().getPoints()) {
                        pointsList.add(new GeoPoint(point.getLatitude(), point
                                .getLongitude()));
                        if (point.getLatitude() > north)
                            north = point.getLatitude();
                        if (point.getLatitude() < south)
                            south = point.getLatitude();
                        if (point.getLongitude() < west)
                            west = point.getLongitude();
                        if (point.getLongitude() > east)
                            east = point.getLongitude();
                    }
                    serviceArea.setPoints(pointsList);
                    map.getOverlays().add(serviceArea);
                    BoundingBoxE6 boundingBox = new BoundingBoxE6(north, east,
                            south, west);
                    map.zoomToBoundingBox(boundingBox);
                    map.getController().zoomOut();
                }
                markers.add(createMarker(selectedService, 1,
                        selectedService.getLatitude(),
                        selectedService.getLongitude(), selectedService.getName(),
                        selectedService.getIcon()));
                map.getOverlays().addAll(markers);
                map.invalidate();
                return true;


            // ROUTE
            case R.id.route:
                // Calls the routing task to calculate the shortest route
                System.out.println(" ++ SENSA :: MapFragment :: R.id.route :: ");
                map.getOverlays().remove(path);
                path.clearPath();
                GeoPoint currentPosition = new GeoPoint(locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER));
                GeoPoint destination = new GeoPoint(selectedService.getLatitude(), selectedService.getLongitude());

                new RoutingAsyncTask(getActivity(), network, currentPosition, destination).execute();

                return true;


            // DESCRIPTION
            case R.id.description:
                // Loads the description fragment with the description of the service
                ServiceFragment fg = new ServiceFragment();
                fg.setDayId(days
                        .get(itinerarySpinner.getSelectedItemPosition())
                        .getId());
                fg.setServiceId(selectedService.getId());
                fg.setDescriptionNo(0);

                //mActivity.pushFragments("MYTRIP_TAB", fg, mActivity.mStacks.get("MYTRIP_TAB").lastElement(), true);

                return true;

            default:
                return super.onContextItemSelected(item);
        }

    }


    /**
     * Function setMapMarker()
     * @param point
     *
     * to set a marker from the geofencing service
     * when the user is out of track, it shows a marker where the user must go
     */
    public static void setMapMarker(GeoPoint point) {
        map.getOverlays().remove(positionMarker);
        positionMarker.setPosition(point);
        map.getOverlays().add(positionMarker);
        map.invalidate();
    }


    /**
     * Function removeMapMarker()
     *
     * Quit the marker
     */
    public static void removeMapMarker() {
        map.getOverlays().remove(positionMarker);
        map.invalidate();
    }


    /**
     * Function updateDayServices()
     * @param day
     * @param serviceId
     * @param alternativeId
     *
     * Called when a alternative activity is activated
     */
    public void updateDayServices(int day, long serviceId, long alternativeId) {
        for (Service s : days.get(day).getServices()){
            if (serviceId == s.getId()){
                s.setAvailable(false);
                for (Service a : s.getAlternativeServices()){
                    if (alternativeId==a.getId())
                        a.setActivated(true);
                    else
                        a.setActivated(false);
                }
                break;
            }
        }
        if (day == itinerarySpinner.getSelectedItemPosition() - 1)
            setMap(day+1);
    }


    /**
     * Function drawPath()
     * @param points
     *
     * to draw the shortest path on the map, called by the routing part
     */
    public static void drawPath(List<IGeoPoint> points) {
        path.addPoints(points);
        map.getOverlays().add(path);
        if (points.size() > 0) {
            map.zoomToBoundingBox(new BoundingBoxE6(
                    points.get(0).getLatitude(), points.get(0).getLongitude(),
                    points.get(points.size() - 1).getLatitude(), points.get(
                    points.size() - 1).getLongitude()));
            map.getController().zoomOut();
        }
        map.invalidate();
    }


    /**
     * Constructor
     * @param savedInstanceState
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Prepare some variables
        // Get the nodes / links of the roads from the .json file generated with OpenStreetMap
        network = new Network(getActivity());
        path = new Polyline(getActivity());
        path.setColor(Color.RED);
        //path.setColor(getResources().getColor(R.color.green_light));
        path.setWidth(4f);

        servicePath = new ArrayList<Polyline>();
        serviceArea = new Polygon(getActivity());

        markersLine = new Polyline(getActivity());
        markersLine.setColor(Color.WHITE);
        markersLine.setWidth(4f);
        markers = new ArrayList<CustomMarker>();

        locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);

        // Prepare db
            helper = new DevOpenHelper(getActivity(), "tripdb", null);
            db = helper.getWritableDatabase();
            daoMaster = new DaoMaster(db);
            daoSession = daoMaster.newSession();
            tripDao = daoSession.getTripDao();
            serviceDao = daoSession.getServiceDao();
            dayDao = daoSession.getDayDao();

        //Get the trip from the database
        trip = tripDao.loadAll().get(0);

        steps = trip.getSteps();
        days = trip.getDays();

        mapEventsOverlay = new MapEventsOverlay(getActivity(), this);
    }


    /**
     * Function onCreateView()
     * @param inflater
     * @param container
     * @param savedInstanceState
     * @return
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        layoutInflater = inflater;

        V = inflater.inflate(R.layout.map, container, false);

        Log.i("MAPSTATE", "view");

        mActivity = (MainActivity) this.getActivity();

        // Get the buttons and textviews
        goToPrevDayButton = (ImageButton) V.findViewById(R.id.goToPrevDayButtonMap);
        goToPrevDayButton.setOnClickListener(prevDayListenerMap);

        txtDay = (TextView) V.findViewById(R.id.textDay);
        txtNameTrip = (TextView) V.findViewById(R.id.textNameTrip);

        Trip trip = tripDao.loadAll().get(0);
        txtNameTrip.setText(trip.getName());

        days = trip.getDays();
        dayLimit = days.size() - 1;

        // Total Days
        totalDays = dayDao.loadAll().size();
        if(totalDays > 1) titleday = totalDays + " DAYS TRIP";
        else titleday = totalDays + " DAY TRIP";

        txtDay.setText(titleday);

        // Mapview
        map = (MapView) V.findViewById(R.id.mapview);
        map.getOverlays().add(mapEventsOverlay);

        registerForContextMenu(map);

        Criteria criteria = new Criteria();
        provider = locationManager.getBestProvider(criteria, true);
        Location loc = locationManager.getLastKnownLocation(provider);

        if(loc != null ) {
            System.out.println(" ********* LOCATION :: getLongitude == " + loc.getLongitude() + " :: latitude == " + loc.getLatitude());
        }

        //Initialization of variables
        positionMarker = new Marker(map);
        positionMarker.setInfoWindow(null);
        currentLocationMarker = new Marker(map);
        currentLocationMarker.setIcon(getResources().getDrawable(R.drawable.ic_menu_mylocation));

        // Disable click on the current location marker
        currentLocationMarker.setOnMarkerClickListener(new OnMarkerClickListener() {
            @Override
            public boolean onMarkerClick(Marker marker, MapView map) {
                return false;
            }
        });

        //if(loc.getLongitude() != 0 && loc.getLatitude() != 0)
        map.getOverlays().add(currentLocationMarker);

        ImageButton myLocationButton = (ImageButton) V.findViewById(R.id.my_locatoin_button);
        myLocationButton.setOnClickListener(myLocationButtonListener);

        // Fake location button, just for testing
        myFakeLocationButton = (ImageButton) V.findViewById(R.id.fake_location_button);
        myFakeLocationButton.setOnClickListener(myFakeLocationButtonListener);

        outsidePark = TileSourceFactory.MAPNIK;

        // map.setBuiltInZoomControls(true);
        map.setMultiTouchControls(true);
        map.invalidate();

        SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE");

		/* Itinerary and habitat spinner */
        List<String> itineraryList = new ArrayList<String>();
        itineraryList.add("ITINERARY");
        for (int i = 0; i < days.size(); i++) {
            itineraryList.add("DAY " + (i + 1) + ": "
                    + dateFormat.format(days.get(i).getDay()));
        }

        itinerarySpinner = (MySpinner) V.findViewById(R.id.itinerary_spinner);
        adapter = new ItinerarySpinnerAdapter(getActivity(), itineraryList);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        itinerarySpinner.setAdapter(adapter);
        System.out.println("*************************Var.position=" + Var.position);
        setMap(Var.position);

        // Custom spinner listener that selects even if unchanged
        itinerarySpinner.setOnItemSelectedEvenIfUnchangedListener(new OnItemSelectedListener() {
            public void onItemSelected(AdapterView<?> parentView,
                                       View selectedItemView, int position, long id) {
                mapStateLoad1 = false;
                mapStateLoad2 = false;
                setMap(position);
            }

            public void onNothingSelected(AdapterView<?> parentView) {}

         });

        // Default itinerary spinner listener
        itinerarySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
            public void onItemSelected(AdapterView<?> parentView,
                                       View selectedItemView, int position, long id) {
                if (firstTime || mapStateLoad1 || mapStateLoad2) {
                    firstTime = false;
                    setMap(position);
                }
            }

            public void onNothingSelected(AdapterView<?> parentView) {}

        });

        return V;
    }


    /**
     * Function onPause()
     */
    @Override
    public void onPause() {
        super.onPause();
        locationManager.removeUpdates(myLocationListener);
    }


    /**
     * Function onResume()
     */
    @Override
    public void onResume() {
        super.onResume();

        // DO NOT UPDATE THE MINTIME 60000 : in order to preserve the battery of the mobile
        // String msg = "";
       locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
       if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
           // msg += "GPS Provider";
           locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 0, myLocationListener);
       } else {
           // msg += "Network Provider";
           locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 60000, 0, myLocationListener);
       }
    }


    /**
     * Function setMap()
     * @param position
     *
     * Shows the markers of the steps or activites and focus the area
     */
    public void setMap(int position) {

        List<Double> latitude = new ArrayList<Double>();
        List<Double> longitude = new ArrayList<Double>();
        List<Service> services = null;

        try {
            if (position == 0) {
                for (Step step : steps) {
                    latitude.add(step.getLatitude());
                    longitude.add(step.getLongitude());
                }
            }else{
                if (days.get(position - 1).getServices().size() > 0)
                    services = new ArrayList<Service>();

                Service service = days.get(position-1).getServices().get(0);
                latitude.add(service.getLatitude());
                longitude.add(service.getLongitude());
                services.add(service);

                /*for (Service service : days.get(position - 1).getServices()) {
                    if (!service.getAvailable()) {
                        for (Service serv : service.getAlternativeServices()) {
                            if (serv.getActivated()) {
                                service = serv;
                                break;
                            }
                        }
                    }
                    latitude.add(service.getLatitude());
                    longitude.add(service.getLongitude());
                    services.add(service);
                    System.out.println("################# Services = " + service.getName());
                    System.out.println("################# Days = " + days.get(position-1).getDay());
                }*/

            }
        }catch(Exception e) {
            e.printStackTrace();
        }

        clearMap();

        if ((position == 0 && steps != null) || services != null) {
            try {
                ArrayList<DbPoint> listPoint = new ArrayList<DbPoint>();
                maxLat = -300;
                maxLong = -300;
                minLat = 300;
                minLong = 300;

                // Overview of steps
                if (position == 0) {
                    for (Step step : steps) {
                        markersLine.addPoint(new GeoPoint(step.getLatitude(), step
                                .getLongitude()));
                        markers.add(createMarker(step, 0, step.getLatitude(),
                                step.getLongitude(), step.getName(), step.getIcon()));
                    }
                    map.setTileSource(outsidePark);
                }
                // View of day
                else {
                    for (Service service : services){
                        markers.add(createMarker(service, 1, service.getLatitude(),
                                service.getLongitude(), service.getName(),
                                service.getIcon()));
                        DbPoint p = new DbPoint();
                        p.setLatitude(service.getLatitude());
                        p.setLongitude(service.getLongitude());
                        listPoint.add(p);

                        if (service.getLatitude() > maxLat) {
                            maxLat = service.getLatitude();
                        }
                        if (service.getLongitude() > maxLong) {
                            maxLong = service.getLongitude();
                        }
                        if (service.getLatitude() < minLat) {
                            minLat= service.getLatitude();
                        }
                        if (service.getLongitude() < minLong) {
                            minLong = service.getLongitude();
                        }
                    }
                    map.setTileSource(outsidePark);
                }

                map.getOverlays().add(markersLine);
                map.getOverlays().addAll(markers);

                if (!mapStateLoad1 && !mapStateLoad2) {
                    Log.i("MAPSTATE", "markers");
                    BoundingBoxE6 boundingBox = new BoundingBoxE6(
                            minLat,
                            minLong,
                            maxLat,
                            maxLong);
                    point = centerPoint(listPoint);
                    map.zoomToBoundingBox(boundingBox);
                    map.getController().zoomToSpan((int) point.x, (int) point.y);
                    map.getController().setZoom(8);
                    map.invalidate();
                }
            }
            catch (Exception e){
                e.printStackTrace();
            }
        }

        // Restore map state
        if (mapStateLoad1 || mapStateLoad2) {
            Log.i("MAPSTATE", "restoring: " + mapState + " " + mapStateZoom);
            // map.zoomToBoundingBox(mapState);
            map.getController().setCenter(mapState);
            map.getController().setZoom(mapStateZoom);
            if (mapStateLoad1)
                mapStateLoad1 = false;
            else
                mapStateLoad2 = false;
        }

        map.invalidate();
    }

    /**
     * Function createMarker()
     * @param object
     * @param type
     * @param latitude
     * @param longitude
     * @param label
     * @param picture
     * @return
     *
     * Create a new custom marker method
     */
    private CustomMarker createMarker(Object object, int type, double latitude, double longitude, String label, byte[] picture) {
        GeoPoint markerPosition = new GeoPoint(latitude, longitude);
        Bitmap icon = null;
        if (picture!=null)
            icon = BitmapFactory.decodeByteArray(picture, 0, picture.length);
        CustomMarker marker = new CustomMarker(map, type, label, icon);
        marker.setPosition(markerPosition);
        marker.setIcon(getResources().getDrawable(R.drawable.mapmarker_136x110));
        marker.setRelatedObject(object);
        marker.setOnMarkerClickListener(markerClickListener);
        marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM - 0.1f);
        return marker;
    }


    /**
     * Function clearMap()
     *
     * Clear all the services, steps or path markers above the map
     */
    private void clearMap() {
        map.getOverlays().removeAll(markers);
        map.getOverlays().remove(markersLine);
        map.getOverlays().remove(path);
        map.getOverlays().removeAll(servicePath);
        map.getOverlays().remove(serviceArea);
        path.clearPath();
        markersLine.clearPath();
        markers.clear();
    }

    /**
     * Onclick myLocationButtonListener
     *
     * Method to focus on the current location
     */
    private OnClickListener myLocationButtonListener = new OnClickListener() {
        @Override
        public void onClick(View v) {

            InfoTabFragment infoTabFragment = new InfoTabFragment();
            infoTabFragment.setFakeLocation(false);

            Location location = locationManager.getLastKnownLocation(provider);

            if(location == null) showGpsDialog();
            else {
                Toast.makeText(getActivity(), "" +
                        " Current location request",Toast.LENGTH_SHORT).show();
                BoundingBoxE6 boundingBox = new BoundingBoxE6(
                        location.getLatitude(),
                        location.getLongitude(),
                        location.getLatitude(),
                        location.getLongitude());
                map.zoomToBoundingBox(boundingBox);
                //map.invalidate();
                map.getOverlays().remove(currentLocationMarker);
                currentLocationMarker.setPosition(new GeoPoint(location.getLatitude(), location.getLongitude()));
                map.getOverlays().add(currentLocationMarker);
            }

        }
    };


    /**
     * OnClick myFakeLocationButtonListener
     *
     * To focus on fake location (put/pressed by the traveler with his mobile)
     */
    private OnClickListener myFakeLocationButtonListener = new OnClickListener() {
        @Override
        public void onClick(View v) {

            InfoTabFragment infoTabFragment = new InfoTabFragment();
            if (fakeLocation) {
                infoTabFragment.setFakeLocation(false);
                Toast.makeText(getActivity(), "Fake location mode deactivated",
                        Toast.LENGTH_SHORT).show();
            } else {
                infoTabFragment.setFakeLocation(true);
                Toast.makeText(getActivity(), "Fake location mode activated",
                        Toast.LENGTH_SHORT).show();
            }
            fakeLocation = !fakeLocation;

        }
    };


    /**
     * Listener prevDayListernerMap
     *
     * Previous day listener allows you to navigate through the days
     */
    private OnClickListener prevDayListenerMap = new OnClickListener() {
        @Override
        public void onClick(View v) {
            getFragmentManager().popBackStack();
        }
    };


    /**
     * Listener myLocationListener
     *
     * Show current location listener
     */
    private LocationListener myLocationListener = new LocationListener() {

        @Override
        public void onLocationChanged(Location location) {
            // TODO Auto-generated method stub

            // Toast.makeText(getActivity(), "Location changed :: Longitude = " + location.getLongitude() + " :: Latitude = " + location.getLatitude(),Toast.LENGTH_SHORT).show();
            // System.out.println(" SENSA :: MapFragment :: LocationListener :: Longitude :: " + location.getLongitude() + " || Latitude :: " + location.getLatitude() );
            map.getOverlays().remove(currentLocationMarker);
            currentLocationMarker.setPosition(new GeoPoint(location.getLatitude(), location.getLongitude()));
            map.getOverlays().add(currentLocationMarker);
            map.invalidate();


            // Double latitude = location.getLatitude();
            // Double longitude = location.getLongitude();
            // Double altitude = location.getAltitude();
            // Float accuracy = location.getAccuracy();

            // String msg = String.format("New Location :: ", latitude, longitude, altitude, accuracy);
        }

        @Override
        public void onProviderDisabled(String provider) {
            // TODO Auto-generated method stub

            String msg = String.format("GPS disabled", provider);
            //Toast.makeText(getActivity(), msg ,Toast.LENGTH_SHORT).show();

        }

        @Override
        public void onProviderEnabled(String provider) {
            // TODO Auto-generated method stub

            String msg = String.format("GPS enabled", provider);
            //Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT).show();

        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            // TODO Auto-generated method stub

            /*
            String newStatus = "";
            switch(status) {
                case LocationProvider.OUT_OF_SERVICE:
                    newStatus = "OUT_OF_SERVICE";
                    break;
                case LocationProvider.TEMPORARILY_UNAVAILABLE:
                    newStatus = "TEMPORARILY_UNAVAILABLE";
                    break;
                case LocationProvider.AVAILABLE:
                    newStatus = "AVAILABLE";
                    break;
            }

            String msg = String.format(" PROVIDER ON STATUS CHANGED :: ", provider, newStatus);
            Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT).show();
            */

        }

     };


    /**
     * Class MapEventsOverlay
     *
     * Fake location method, used to tap where you want to be
     */
    public class MapEventsOverlay extends Overlay {

        private MapEventsReceiver mReceiver;

        /**
         * Constructor
         *
         * @param ctx
         *            the context
         * @param receiver
         *            the object that will receive/handle the events. It must
         *            implement MapEventsReceiver interface.
         */
        public MapEventsOverlay(Context ctx, MapEventsReceiver receiver) {
            super(ctx);
            mReceiver = receiver;
        }


        /**
         * Function Draw()
         * @param c
         * @param osmv
         * @param shadow
         */
        @Override
        protected void draw(Canvas c, MapView osmv, boolean shadow) {
            // Nothing to draw
        }


        /**
         * Function onSingleTapConfirmed()
         * @param e
         * @param mapView
         * @return
         */
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e, MapView mapView) {
            Projection proj = mapView.getProjection();
            GeoPoint p = (GeoPoint) proj.fromPixels((int) e.getX(),
                    (int) e.getY());
            if (fakeLocation) {

                Log.i("MAP", p.toDoubleString());
                map.getOverlays().remove(currentLocationMarker);
                currentLocationMarker.setPosition(new GeoPoint(p.getLatitude(), p.getLongitude()));
                map.getOverlays().add(currentLocationMarker);
                map.invalidate();
                MockLocationProvider.setLatitude(p.getLatitude());
                MockLocationProvider.setLongitude(p.getLongitude());
                fakeLocation = false;
            } else
                ;
            return mReceiver.singleTapUpHelper(p);
        }


        /**
         * Function onLongPress()
         * @param e
         * @param mapView
         * @return
         */
        @Override
        public boolean onLongPress(MotionEvent e, MapView mapView) {
            Projection proj = mapView.getProjection();
            GeoPoint p = (GeoPoint) proj.fromPixels((int) e.getX(),
                    (int) e.getY());
            // throw event to the receiver:
            return mReceiver.longPressHelper(p);
        }

    }


    /**
     * Function longPressHelper()
     * @param arg0
     * @return
     */
    @Override
    public boolean longPressHelper(IGeoPoint arg0) {
        // TODO Auto-generated method stub
        return false;
    }


    /**
     * Function singleTapUpHelper()
     * @param arg0
     * @return
     */
    @Override
    public boolean singleTapUpHelper(IGeoPoint arg0) {
        // TODO Auto-generated method stub
        return false;
    }
    private Point centerPoint(List<DbPoint> listDbPoint){
        double centroidX = 0;
        double centroidY = 0;
        for (DbPoint knot : listDbPoint) {
            centroidX += knot.getLatitude();
            centroidY += knot.getLongitude();
        }
        Point center = new Point(centroidX / listDbPoint.size(), centroidY / listDbPoint.size());
        return center;
    }
}