package com.cc.infosur.map;

import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
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.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.NotificationCompat;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.MenuInflater;
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.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.DbPoint;
import com.cc.infosur.greendao.DbPolygon;
import com.cc.infosur.greendao.Fauna;
import com.cc.infosur.greendao.FaunaDao;
import com.cc.infosur.greendao.Flora;
import com.cc.infosur.greendao.FloraDao;
import com.cc.infosur.greendao.Heritage;
import com.cc.infosur.greendao.HeritageDao;
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.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.util.ArrayList;
import java.util.Collections;
import java.util.List;

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

public class InfoTabFragment extends Fragment implements MapEventsReceiver {

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

    // Some lists of database objects
        private List<Step> steps;
        private List<Day> days;
        private List<Flora> flora;
        private List<Fauna> fauna;
        private List<Heritage> heritage;

    // Lists of markers
        private Polyline markersLine;
        private List<CustomMarker> markers;
        private List<Polygon> floraMap;
        private List<Polygon> faunaMap;
        private List<Polygon> heritageMap;
        private List<CustomMarker> floraMapMarkers;
        private List<CustomMarker> faunaMapMarkers;
        private List<CustomMarker> heritageMapMarkers;
        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 FloraDao floraDao;
        private FaunaDao faunaDao;
        private HeritageDao heritageDao;

    // Trip object
        Trip trip;

    // Some variables for the drop-down menu
        int positionFlora = -1;
        int positionFauna = -1;
        int positionHeritage = -1;
        boolean showingFlora = false;
        boolean showingFauna = false;
        boolean showingHeritage = false;

    // 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;
        private static boolean myFakePositionAsked = false;
        ImageButton myFakeLocationButton;
        MapEventsOverlay mapEventsOverlay;

    // Spinners
        MySpinner faunaSpinner;
        MySpinner floraSpinner;
        MySpinner heritageSpinner;

    // ArrayAdapters
        ArrayAdapter<String> adapterFauna;
        ArrayAdapter<String> adapterFlora;
        ArrayAdapter<String> adapterHeritage;
        ArrayAdapter<String> adapter;


    private View V;

    Marker currentLocationMarker;
    LocationManager locationManager;
    Location loc;

    Network network;
    private static Polyline path;
    List<Polyline> servicePath;
    Polygon serviceArea;

    XYTileSource insidePark;
    ITileSource outsidePark;

    private Context context;///

    /**
     * Listener markerClickListener
     *
     * Show context menu (in case of service) or InfoFragment
     */
    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("MAP_TAB", fg, mActivity.mStacks.get("MAP_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 showGpsDialog()
     *
     * Warns the traveler that the GPS is required
     */
    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 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 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 onCreate()
     * @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.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>();
        faunaMap = new ArrayList<Polygon>();
        faunaMapMarkers = new ArrayList<CustomMarker>();
        heritageMapMarkers = new ArrayList<CustomMarker>();
        heritageMap = new ArrayList<Polygon>();
        floraMap = new ArrayList<Polygon>();
        floraMapMarkers = 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();
            floraDao = daoSession.getFloraDao();
            faunaDao = daoSession.getFaunaDao();
            heritageDao = daoSession.getHeritageDao();

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

        steps = trip.getSteps();
        days = trip.getDays();
        List<Flora> allFlora = floraDao.loadAll();
        List<Fauna> allFauna = faunaDao.loadAll();
        List<Heritage> allHeritage = heritageDao.loadAll();

        //Just take the layers with geodata
        flora = new ArrayList<Flora>();
        for (Flora f : allFlora){
            if (f.getPoints().size()>0 || f.getPolygons().size()>0)
                flora.add(f);
        }

        fauna = new ArrayList<Fauna>();
        for (Fauna f : allFauna){
            if (f.getPolygons().size()>0)
                fauna.add(f);
        }

        heritage = new ArrayList<Heritage>();
        for (Heritage h : allHeritage){
            if (h.getPolygons().size()>0)
                heritage.add(h);
        }


        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.infotab, container, false);
        // Log.i("MAPSTATE", "view");

        mActivity = (MainActivity) this.getActivity();

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

        registerForContextMenu(map);

        // Current location
        // mCompassOverlay = new CompassOverlay(getActivity(), new InternalCompassOrientationProvider(getActivity()), map);
        // mLocationOverlay = new MyLocationNewOverlay(getActivity(), map);
        //
        // map.getOverlays().add(mLocationOverlay);
        // map.getOverlays().add(mCompassOverlay);
        // mLocationOverlay.enableMyLocation(new GpsMyLocationProvider(getActivity()));
        // mCompassOverlay.enableCompass();


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

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

        currentLocationMarker.setOnMarkerClickListener(new OnMarkerClickListener() {
            @Override
            public boolean onMarkerClick(Marker marker, MapView map) {
                return false;
            }
        });

        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");

		/* Fauna, flora and heritage spinner */

        int count = 1;

        final List<String> faunaList = new ArrayList<String>();
        final List<byte[]> faunaImageList = new ArrayList<byte[]>();
        faunaList.add("FAUNA");
        byte[] b = new byte[0];
        faunaImageList.add(b);


        if (fauna.size() > 0)
            positionFauna = count++;


        for (Fauna faunaElement : fauna) {
            faunaList.add(faunaElement.getSpecie());
            faunaImageList.add(faunaElement.getIcon());
        }


        final List<String> floraList = new ArrayList<String>();
        final List<byte[]> floraImageList = new ArrayList<byte[]>();
        floraList.add("FLORA");
        floraImageList.add(b);


        if (flora.size() > 0)
            positionFlora = count++;


        for (Flora floraElement : flora) {
            floraList.add(floraElement.getSpecie());
            floraImageList.add(floraElement.getIcon());
        }


        final List<String> heritageList = new ArrayList<String>();
        heritageList.add("HERITAGE");


        if (heritage.size() > 0)
            positionHeritage = count++;


        for (Heritage heritageElement : heritage) {
            heritageList.add(heritageElement.getName());


        }


        faunaSpinner = (MySpinner) V.findViewById(R.id.fauna_spinner);
        adapterFauna = new FaunaSpinnerAdapter(getActivity(), faunaList, faunaImageList);
        adapterFauna.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        faunaSpinner.setAdapter(adapterFauna);


        floraSpinner = (MySpinner) V.findViewById(R.id.flora_spinner);
        adapterFlora = new FloraSpinnerAdapter(getActivity(), floraList, floraImageList);
        adapterFlora.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        floraSpinner.setAdapter(adapterFlora);


        heritageSpinner = (MySpinner) V.findViewById(R.id.heritage_spinner);
        adapterHeritage = new HeritageSpinnerAdapter(getActivity(), heritageList);
        adapterHeritage.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        heritageSpinner.setAdapter(adapterHeritage);




        try {
        setMap(0);
        map.getController().setZoom(7);

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

        // Create an ArrayAdapter using the string array and a default spinner
        // layout
        // ArrayAdapter.createFromResource(getActivity(),
        // days.toArray(new String[days.size()]),
        // android.R.layout.simple_spinner_item);
        // Specify the layout to use when the list of choices appears
        // Apply the adapter to the spinner

        // Fauna Spinner
        faunaSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
            public void onItemSelected(AdapterView<?> parentView,
                                       View selectedItemView, int position, long id) {
                // Log.i("POSITION :::::" +position,"IDDDDDD"+id);
                clearMapLayers();
                // if (position == 0) { }

                if (!showingFauna) {
                    showingFauna = !showingFauna;
                    faunaSpinner.setSelection(0);
                    adapterFauna.notifyDataSetChanged();
                } else if (showingFauna) {

                    ///showFauna(positionFauna-1);
                    showFauna(position-1);
                }
            }

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

        });

        // Flora Spinner
        floraSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
            public void onItemSelected(AdapterView<?> parentView,
                                       View selectedItemView, int position, long id) {


                System.out.println("******************  position="+position);

                System.out.println("******************  positionFlora="+positionFlora);

                // Log.i("POSITION :::::" +position,"IDDDDDD"+id);
                clearMapLayers();
                // if (position <= 0) { }

                if (!showingFlora) {
                    showingFlora = !showingFlora;
                    floraSpinner.setSelection(0);
                    adapterFlora.notifyDataSetChanged();
                } else if (showingFlora) {
                    ///showFlora(position + positionFlora-3);

                    showFlora(position-1);
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) { }

        });

        // Heritage Spinner
        heritageSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
            public void onItemSelected(AdapterView<?> parentView,
                                       View selectedItemView, int position, long id) {
                // Log.i("POSITION :::::" +position,"IDDDDDD"+id);
                clearMapLayers();
                // if (position == 0) { }

                if (!showingHeritage){
                    showingHeritage = !showingHeritage;
                    heritageSpinner.setSelection(0);
                    adapterHeritage.notifyDataSetChanged();
                } else if (showingHeritage) {
                    showHeritage(position -1);
                }
            }

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

        });

        return V;
    }


    /**
     * Function clearMapLayers()
     *
     * Clear all the habitat layers above the map
     */
    private void clearMapLayers() {
        map.getOverlays().removeAll(floraMap);
        map.getOverlays().removeAll(floraMapMarkers);
        floraMapMarkers.clear();
        map.getOverlays().removeAll(faunaMap);
        map.getOverlays().removeAll(faunaMapMarkers);
        faunaMapMarkers.clear();
        faunaMap.clear();
        map.getOverlays().removeAll(heritageMap);
        map.getOverlays().removeAll(heritageMapMarkers);
        heritageMap.clear();
        heritageMapMarkers.clear();
        map.invalidate();
    }


    /**
     * Function onPause()
     */
    @Override
    public void onPause() {
        super.onPause();
        // map.invalidate();
        // mapState = map.getMapCenter();
        // mapState = map.getBoundingBox();
        // mapStateZoom = map.getZoomLevel();
        // mLocationOverlay.disableMyLocation();
        // mCompassOverlay.disableCompass();
        // mapStateLoad1 = true;
        // mapStateLoad2 = true;
        // Log.i("MAPSTATE", "" + mapState + " " + mapStateZoom);
        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);
        }
        // Toast.makeText(getActivity(), msg ,Toast.LENGTH_SHORT).show();

        // mLocationOverlay.enableMyLocation();
        // mCompassOverlay.enableCompass();


        // locationManager.requestLocationUpdates(provider, 60000, 0, myLocationListener);


    }


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

        List<Double> latitude = new ArrayList<Double>();
        List<Double> longitude = new ArrayList<Double>();
        List<Service> services = null;
        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>();
            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);
            }
        }

        clearMap();

        if ((position == 0 && steps != null) || services != null) {
            try {
                minLat = latitude.get(latitude.indexOf(Collections.min(latitude)));
                maxLat = latitude.get(latitude.indexOf(Collections.max(latitude)));
                minLong = longitude.get(longitude.indexOf(Collections
                        .min(longitude)));
                maxLong = longitude.get(longitude.indexOf(Collections
                        .max(longitude)));

                BoundingBoxE6 boundingBox = new BoundingBoxE6(maxLat, maxLong,
                        minLat, minLong);

                // 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()));
                    // test
                    // if (days.get(position - 1).getPark() > 0)
                    // map.setTileSource(insidePark);
                    // else
                    map.setTileSource(outsidePark);
                }

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

                if (!mapStateLoad1 && !mapStateLoad2) {
                    // Log.i("MAPSTATE", "markers");
                    map.zoomToBoundingBox(boundingBox);
                    map.getController().zoomOut();
                }
            }
            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
     *
     * To focus on the current location
     */
    private OnClickListener myLocationButtonListener = new OnClickListener() {
        @Override
        public void onClick(View v) {

            // Set Fake location false
            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);
            }
        }
    };




    /**
     * Function setFakeLocation()
     * @return
     */
    public void setFakeLocation(boolean thebool) {

        System.out.println(" ===== setFakeLocation :: " + thebool);

        myFakePositionAsked = thebool;

    }


    /**
     * Function getFakeLocation()
     * @return
     */
    public static boolean getFakeLocation() {

        System.out.println(" ----- getFakeLocation :: " + myFakePositionAsked);

        return myFakePositionAsked;

    }



    /**
     * 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) {


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


        }
    };



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

        /**
         * Function onLocationChanged()
         * @param location
         */
        @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);
        }




        /**
         * Function onProviderDisabled()
         * @param provider
         */
        @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();
        }


        /**
         * Function onProviderEnabled()
         * @param provider
         */
        @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();
        }


        /**
         * Function onStatusChanged()
         * @param provider
         * @param status
         * @param extras
         */
        @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();
            */
        }

    };


    /**
     * Function showFlora()
     * @param position
     *
     * Method to show the flora markers or polygons
     */
    private void showFlora(int position) {

        //System.out.println(" SENSA :: MapFragment :: showFlora :: ");

        // Show all the flora
        if (position < 0) {
            // System.out.println(" SENSA :: MapFragment :: showFlora :: position < 0 ");
            for (int i = 0; i < flora.size(); i++) {
                showFlora(i);
            }
        } else {

            // System.out.println(" SENSA :: MapFragment :: showFlora :: position < 0 :: else ");
            if (flora.get(position).getPoints().size()==0){
                // System.out.println(" SENSA :: MapFragment :: showFlora :: position < 0 :: else :: size() == 0 :: ");

            try {
                showPolygons(0, flora.get(position).getPolygons(), floraMap, position);

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

                List<DbPoint> floraPoints = flora.get(position).getPoints();

                // Progress Dialog in case if there are too much points
                if(floraPoints.size() > 5) {

                    new LoadDisplayPointsTask(mActivity, position).execute();

                } else {

                    double latitudezoom = 0;
                    double longitudezoom = 0;
                    for (DbPoint point : floraPoints) {
                        floraMapMarkers.add(createMarker(flora.get(position), 2, point.getLatitude(), point.getLongitude(),
                        flora.get(position).getSpecie(), flora.get(position).getIcon()));
                        ///map.getOverlays().addAll(floraMapMarkers);
                        latitudezoom = point.getLatitude();
                        longitudezoom = point.getLongitude();
                    }

                    BoundingBoxE6 boundingBox = new BoundingBoxE6(
                            latitudezoom,
                            longitudezoom,
                            latitudezoom,
                            longitudezoom);
                    map.zoomToBoundingBox(boundingBox);
                    map.getController().setZoom(10);
                }
            }
        }

    }


    /**
     * Function showFauna()
     * @param position
     *
     * Show the fauna polygons
     */
    private void showFauna(int position) {
        // System.out.println(" SENSA :: MapFragment :: showFauna :: ");
        try {
        showPolygons(1, fauna.get(position).getPolygons(), faunaMap, position);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * Function showHeritage()
     * @param position
     *
     * Show the heritage polygons
     */
    private void showHeritage(int position) {
        // System.out.println(" SENSA :: MapFragment :: showHeritage :: ");
        try {
        showPolygons(2, heritage.get(position).getPolygons(), heritageMap, position);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Function showPolygons()
     * @param category
     * @param polygons
     * @param categoryMap
     * @param position
     *
     * Draw the polygons above the map
     */
    private void showPolygons(int category, List<DbPolygon> polygons, List<Polygon> categoryMap, int position) {

        // System.out.println(" SENSA :: MapFragment :: showPolygons :: ");

        List<GeoPoint> points = null;
        double latitudezoom = 0;
        double longitudezoom = 0;
        double maxLatitude = -300;
        double maxLongitude = -300;
        double minLatitude = 300;
        double minLongitude = 300;
        DbPolygon biggestPoly = polygons.get(0);

        // System.out.println(" SENSA :: MapFragment :: showPolygons :: category == 2 :: ");
        for(DbPolygon poly : polygons) {
            points = new ArrayList<GeoPoint>();
            if(poly.getPoints().size() > biggestPoly.getPoints().size()) {
                biggestPoly = poly;
            }
            for (int i = 0; i < poly.getPoints().size(); i++) {
                if (poly.getPoints().get(i).getLatitude() > maxLatitude) {
                    maxLatitude = poly.getPoints().get(i).getLatitude();
                }
                if (poly.getPoints().get(i).getLongitude() > maxLongitude) {
                    maxLongitude = poly.getPoints().get(i).getLongitude();
                }
                if (poly.getPoints().get(i).getLatitude() < minLatitude) {
                    minLatitude = poly.getPoints().get(i).getLatitude();
                }
                if (poly.getPoints().get(i).getLongitude() < minLongitude) {
                    minLongitude = poly.getPoints().get(i).getLongitude();
                }
                points.add(new GeoPoint(poly.getPoints().get(i)
                        .getLatitude(), poly.getPoints().get(i)
                        .getLongitude()));
            }
            addPolygon(categoryMap, points, getResources().getColor(R.color.green_light));
        }

        Point p = centerPolygons(polygons);
        Point centerBiggestPoly = centerPoint(biggestPoly.getPoints());

        // Category = 0
        if (category == 0) {
            floraMapMarkers.add(createMarker(flora.get(position), 2, centerBiggestPoly
                    .getX(), centerBiggestPoly.getY(), flora
                    .get(position).getSpecie(), flora.get(position)
                    .getIcon()));
            map.getOverlays().addAll(floraMapMarkers);
            BoundingBoxE6 boundingBox = new BoundingBoxE6(
                    minLatitude,
                    minLongitude,
                    maxLatitude,
                    maxLongitude);
            map.zoomToBoundingBox(boundingBox);
            map.getController().zoomToSpan((int) p.getX(), (int) p.getY());
            // map.getController().setZoom(8);

            // Category = 1
        } else if (category == 1) {
            faunaMapMarkers.add(createMarker(fauna.get(position), 3, centerBiggestPoly
                    .getX(), centerBiggestPoly.getY(), fauna
                    .get(position).getSpecie(), fauna.get(position)
                    .getIcon()));
            map.getOverlays().addAll(faunaMapMarkers);
            BoundingBoxE6 boundingBox = new BoundingBoxE6(
                    minLatitude,
                    minLongitude,
                    maxLatitude,
                    maxLongitude);
            map.zoomToBoundingBox(boundingBox);
            map.getController().zoomToSpan((int) p.getX(), (int) p.getY());
            // map.getController().setZoom(12);

            // Category = 2
        } else if (category == 2) {
            heritageMapMarkers.add(createMarker(heritage.get(position), 4,
                    centerBiggestPoly.getX(), centerBiggestPoly.getY(),
                    heritage.get(position).getName(), heritage.get(position)
                            .getIcon()));
            map.getOverlays().addAll(heritageMapMarkers);
            BoundingBoxE6 boundingBox = new BoundingBoxE6(
                    minLatitude,
                    minLongitude,
                    maxLatitude,
                    maxLongitude);
            map.zoomToBoundingBox(boundingBox);
            map.getController().zoomToSpan((int) p.getX(), (int) p.getY());
            // map.getController().setZoom(8);

        }
    }


    /**
     * Function addPolygon()
     * @param polygons
     * @param points
     * @param color
     */
    private void addPolygon(List<Polygon> polygons, List<GeoPoint> points, int color) {

        // System.out.println(" SENSA :: MapFragment :: addPolygon :: ");
        Polygon polygon = new Polygon(getActivity());
        polygon.setPoints(points);
        ///polygon.setFillColor(color);
        polygon.setFillColor(0x1E00FF00);
        polygon.setStrokeColor(color);
        polygon.setStrokeWidth(0);
        polygons.add(polygon);
        map.getOverlays().add(polygon);
        map.invalidate();
    }


    /**
     * 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);
        }

    } // __ END Class MapEventsOverlay


    /**
     * 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;
    }


    /**
     * Class LoadDisplayPointsTask
     */
    public class LoadDisplayPointsTask extends AsyncTask<Void, Void, Boolean> {

        private Context context;
        private Integer pos;
        private Integer increment = 1;

        private Double latitudezoom;
        private Double longitudezoom;

        /**
         * Constructor
         *
         * @param mActivity
         * @param position
         */
        public LoadDisplayPointsTask(MainActivity mActivity, Integer position) {
            super();
            context = mActivity;
            pos = position;
        }


        /**
         * Function onPreExecute (AsyncTask 1 / 3)
         */
        ProgressDialog pDialog;

        protected void onPreExecute() {
            pDialog = new ProgressDialog(context);
            pDialog.setTitle("Display points");
            pDialog.setProgressStyle(pDialog.STYLE_HORIZONTAL);
            pDialog.setCancelable(false);
            pDialog.setCanceledOnTouchOutside(false);
            pDialog.show();
        }



        /**
         * Function doInBackground (AsyncTask 2 / 3)
         */
        protected Boolean doInBackground(Void... params) {

            try {

                List<DbPoint> floraPoints = flora.get(pos).getPoints();

                pDialog.setMax(floraPoints.size());

                for (DbPoint point : floraPoints) {
                    floraMapMarkers.add(createMarker(flora.get(pos), 2, point
                                    .getLatitude(), point.getLongitude(),
                            flora.get(pos).getSpecie(), flora.get(pos)
                                    .getIcon()));

                    ///map.getOverlays().addAll(floraMapMarkers);

                    pDialog.setProgress(increment++);
                    latitudezoom = point.getLatitude();
                    longitudezoom = point.getLongitude();

                    if(floraPoints.size() == increment) return true;

                }

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

            return true;
        }


        /**
         * Function onPostExecute() : (AsyncTask 3 / 3)
         * @param result
         */
        protected void onPostExecute(Boolean result) {
            pDialog.dismiss();
            if(result) {

                BoundingBoxE6 boundingBox = new BoundingBoxE6(
                        latitudezoom,
                        longitudezoom,
                        latitudezoom,
                        longitudezoom);
                map.zoomToBoundingBox(boundingBox);
                map.getController().setZoom(10);

                Toast.makeText(getActivity(), "Points successfully loaded." ,Toast.LENGTH_SHORT).show();
            }
        }

    }


    //notification method
    private void showNotification(String type, String title, String message) {

        Intent intent = new Intent(context, MainActivity.class);
        intent.putExtra("type", type);

        PendingIntent contentIntent = PendingIntent.getActivity(context, 5,
                intent, PendingIntent.FLAG_UPDATE_CURRENT
                        | PendingIntent.FLAG_ONE_SHOT);

        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
                context).setSmallIcon(R.drawable.sensa_logo)
                .setContentTitle(title).setContentText(message);
        mBuilder.setContentIntent(contentIntent);
        mBuilder.setDefaults(Notification.DEFAULT_SOUND);
        mBuilder.setAutoCancel(true);
        NotificationManager mNotificationManager = (NotificationManager) context
                .getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.notify(1, mBuilder.build());
    }


    private Point centerPolygons(List<DbPolygon> polygons){
        double centroidX = 0;
        double centroidY = 0;
        List<Point> listPoint = new ArrayList<Point>();
        for (DbPolygon poly: polygons){
            centroidX =0;
            centroidY =0;
            for (DbPoint knot : poly.getPoints()) {
                centroidX += knot.getLatitude();
                centroidY += knot.getLongitude();
            }
            Point p = new Point(centroidX / poly.getPoints().size(), centroidY / poly.getPoints().size());
            listPoint.add(p);
        }
        centroidX =0;
        centroidY =0;
        for (Point knot : listPoint) {
            centroidX += knot.getX();
            centroidY += knot.getY();
        }
        Point center = new Point(centroidX / listPoint.size(), centroidY / listPoint.size());
        return center;
    }
    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;
    }


}