content: /*
   * Androzic - android navigation client that uses OziExplorer maps (ozf2, ozfx3).
   * Copyright (C) 2010-2014 Andrey Novikov <http://andreynovikov.info/>
   * 
   * This file is part of Androzic application.
   * 
   * Androzic is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   * 
   * Androzic is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   * GNU General Public License for more details.
   * 
   * You should have received a copy of the GNU General Public License
   * along with Androzic. If not, see <http://www.gnu.org/licenses/>.
   */
  
  package com.androzic;
  
  import java.io.Serializable;
  import java.util.ArrayList;
  import java.util.Stack;
  
  import android.annotation.SuppressLint;
  import android.content.Context;
  import android.content.DialogInterface;
  import android.content.Intent;
  import android.content.SharedPreferences;
  import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
  import android.content.res.Configuration;
  import android.content.res.Resources;
  import android.graphics.drawable.Drawable;
  import android.location.Location;
  import android.os.Build;
  import android.os.Bundle;
  import android.os.Handler;
  import android.os.StrictMode;
  import android.preference.PreferenceManager;
  import android.support.annotation.NonNull;
  import android.support.design.widget.CoordinatorLayout;
  import android.support.design.widget.FloatingActionButton;
  import android.support.design.widget.Snackbar;
  import android.support.v4.app.DialogFragment;
  import android.support.v4.app.Fragment;
  import android.support.v4.app.FragmentManager;
  import android.support.v4.app.FragmentTransaction;
  import android.support.v4.view.GravityCompat;
  import android.support.v4.widget.DrawerLayout;
  import android.support.v7.app.ActionBarDrawerToggle;
  import android.support.v7.app.AlertDialog;
  import android.support.v7.app.AppCompatActivity;
  import android.support.v7.widget.Toolbar;
  import android.util.Log;
  import android.util.Pair;
  import android.view.MenuItem;
  import android.view.View;
  import android.view.ViewGroup;
  import android.view.WindowManager;
  import android.view.inputmethod.InputMethodManager;
  import android.widget.AdapterView;
  import android.widget.FrameLayout;
  import android.widget.ListView;
  import android.widget.Toast;
  
  import com.androzic.data.MapObject;
  import com.androzic.data.Route;
  import com.androzic.data.Track;
  import com.androzic.data.Waypoint;
  import com.androzic.map.BaseMap;
  import com.androzic.map.MapInformation;
  import com.androzic.map.OnMapActionListener;
  import com.androzic.route.OnRouteActionListener;
  import com.androzic.route.RouteDetails;
  import com.androzic.route.RouteList;
  import com.androzic.route.RouteProperties;
  import com.androzic.route.RouteSave;
  import com.androzic.route.RouteStart;
  import com.androzic.track.OnTrackActionListener;
  import com.androzic.track.TrackDetails;
  import com.androzic.track.TrackList;
  import com.androzic.track.TrackProperties;
  import com.androzic.track.TrackSave;
  import com.androzic.track.TrackToRoute;
  import com.androzic.ui.DrawerAdapter;
  import com.androzic.ui.DrawerItem;
  import com.androzic.util.StringFormatter;
  import com.androzic.waypoint.OnWaypointActionListener;
  import com.androzic.waypoint.WaypointDetails;
  import com.androzic.waypoint.WaypointInfo;
  import com.androzic.waypoint.WaypointList;
  import com.androzic.waypoint.WaypointProperties;
  
  public class MainActivity extends AppCompatActivity implements FragmentHolder, OnWaypointActionListener, OnMapActionListener, OnRouteActionListener, OnTrackActionListener, OnSharedPreferenceChangeListener
  {
  	private static final String TAG = "MainActivity";
  
  	public static final String SHOW_FRAGMENT = "show";
  	public static final String LAUNCH_ACTIVITY = "launch";
  
  	private DrawerLayout mDrawerLayout;
  	private ListView mDrawerList;
  	private CoordinatorLayout mCoordinatorLayout;
  	private DrawerAdapter mDrawerAdapter;
  	private ActionBarDrawerToggle mDrawerToggle;
  	private Drawable mHomeDrawable;
  	private Toolbar mToolbar;
  	private int mToolbarHeight;
  	private FloatingActionButton mActionButton;
  
  	private CharSequence mDrawerTitle;
  	private CharSequence mTitle;
  	private ArrayList<DrawerItem> mDrawerItems;
  
  	private int exitConfirmation;
  	private boolean secondBack;
  	private Toast backToast;
  
  	protected Androzic application;
  	private boolean restarting = false;
  
  	@SuppressLint({"ShowToast", "NewApi"})
  	@Override
  	protected void onCreate(Bundle savedInstanceState)
  	{
  		super.onCreate(savedInstanceState);
  		Log.e(TAG, "onCreate()");
  
  		if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD)
  			StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
  
  		application = Androzic.getApplication();
  
  		// check if called after crash
  		if (!application.mapsInited)
  		{
  			restarting = true;
  			startActivity(new Intent(this, Splash.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK).putExtras(getIntent()));
  			finish();
  			return;
  		}
  
  		setContentView(R.layout.activity_main);
  
  	    mToolbar = (Toolbar) findViewById(R.id.action_toolbar);
  	    setSupportActionBar(mToolbar);
  
  	    mActionButton = (FloatingActionButton) findViewById(R.id.toolbar_action_button);
  	    
  		backToast = Toast.makeText(this, R.string.backQuit, Toast.LENGTH_SHORT);
  
  		SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
  		onSharedPreferenceChanged(settings, getString(R.string.pref_exit));
  		onSharedPreferenceChanged(settings, getString(R.string.pref_hidestatusbar));
  		onSharedPreferenceChanged(settings, getString(R.string.pref_orientation));
  		settings.registerOnSharedPreferenceChangeListener(this);
  
  		mTitle = mDrawerTitle = getTitle();
  		mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
  		// set a custom shadow that overlays the main content when the drawer opens
  		mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
  		// set up the drawer's list view with items and click listener
  		mDrawerItems = new ArrayList<>();
  		mDrawerList = (ListView) findViewById(R.id.left_drawer);
  		mDrawerAdapter = new DrawerAdapter(this, mDrawerItems);
  		mDrawerList.setAdapter(mDrawerAdapter);
  		mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
  		initializeDrawerItems();
  
  		mCoordinatorLayout = (CoordinatorLayout) findViewById(R.id.main_content);
  
  		getSupportActionBar().setDisplayHomeAsUpEnabled(true);
  		getSupportActionBar().setHomeButtonEnabled(true);
  
  		mHomeDrawable = getDrawerToggleDelegate().getThemeUpIndicator();
  		
  		mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar, R.string.drawer_open, R.string.drawer_close) {
  			public void onDrawerClosed(View drawerView)
  			{
  				if (drawerView == mDrawerList)
  				{
  					getSupportActionBar().setTitle(mTitle);
  					supportInvalidateOptionsMenu();
  				}
  			}
  
  			public void onDrawerOpened(View drawerView)
  			{
  				if (drawerView == mDrawerList)
  				{
  					getSupportActionBar().setTitle(mDrawerTitle);
  					supportInvalidateOptionsMenu();
  				}
  			}
  		};
  		mDrawerLayout.setDrawerListener(mDrawerToggle);
  
  		getSupportFragmentManager().addOnBackStackChangedListener(mBackStackChangedListener);
  
  		if (savedInstanceState == null)
  		{
  			mDrawerAdapter.setSelectedItem(-1);
  			selectItem(0);
  		}
  	}
  
  	@Override
  	protected void onNewIntent(Intent intent)
  	{
  		super.onNewIntent(intent);
  		Log.e(TAG, "onNewIntent()");
  		if (intent.hasExtra(LAUNCH_ACTIVITY))
  		{
  			Serializable object = intent.getExtras().getSerializable(LAUNCH_ACTIVITY);
  			if (Class.class.isInstance(object))
  			{
  				Intent launch = new Intent(this, (Class<?>) object);
  				launch.putExtras(intent);
  				launch.removeExtra(LAUNCH_ACTIVITY);
  				startActivity(launch);
  			}
  		}
  		else if (intent.hasExtra(SHOW_FRAGMENT))
  		{
  			Serializable object = intent.getExtras().getSerializable(SHOW_FRAGMENT);
  			if (Class.class.isInstance(object))
  			{
  				@SuppressWarnings("rawtypes")
  				String name = ((Class) object).getName();
  				Fragment f = Fragment.instantiate(this, name);
  				intent.removeExtra(SHOW_FRAGMENT);
  				f.setArguments(intent.getExtras());
  				if (DialogFragment.class.isInstance(f))
  					((DialogFragment)f).show(getSupportFragmentManager(), "show");
  				else
  					addFragment(f, name);
  			}
  		}
  		else if (intent.hasExtra("lat") && intent.hasExtra("lon"))
  		{
  			application.ensureVisible(intent.getExtras().getDouble("lat"), intent.getExtras().getDouble("lon"));
  			selectItem(0);
  		}
  	}
  
  	@Override
  	protected void onResume()
  	{
  		super.onResume();
  		Log.e(TAG, "onResume()");
  	}
  
  	@Override
  	protected void onPause()
  	{
  		super.onPause();
  		Log.e(TAG, "onPause()");
  	}
  
  	@Override
  	protected void onDestroy()
  	{
  		super.onDestroy();
  		Log.e(TAG, "onDestroy()");
  
  		getSupportFragmentManager().removeOnBackStackChangedListener(mBackStackChangedListener);
  		PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this);
  
  		if (isFinishing() && !restarting)
  			application.clear();
  
  		restarting = false;
  
  		application = null;
  	}
  
  	@Override
  	public boolean onOptionsItemSelected(MenuItem item)
  	{
  		// Handle action buttons
  		switch (item.getItemId())
  		{
  			case android.R.id.home:
  				FragmentManager fm = getSupportFragmentManager();
  				if (fm.getBackStackEntryCount() > 0)
  				{
  					View v = getCurrentFocus();
  					if (v != null)
  					{
  						// Hide keyboard
  						final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
  						imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
  					}
  					fm.popBackStack();
  					return true;
  				}
  				else
  				{
  					if (mDrawerToggle.onOptionsItemSelected(item))
  					{
  						return true;
  					}
  				}
  			default:
  				return super.onOptionsItemSelected(item);
  		}
  	}
  
  	/* The click listener for ListView in the navigation drawer */
  	private class DrawerItemClickListener implements ListView.OnItemClickListener
  	{
  		@Override
  		public void onItemClick(AdapterView<?> parent, View view, int position, long id)
  		{
  			selectItem(position);
  		}
  	}
  
  	private void selectItem(int position)
  	{
  		if (mDrawerAdapter.getSelectedItem() == position)
  			return;
  		
  		DrawerItem item = mDrawerItems.get(position);
  		// Actions
  		if (item.type == DrawerItem.ItemType.INTENT)
  		{
  			if (position > 0)
  				startActivity(item.intent);
  		}
  		// Fragments
  		else if (item.type == DrawerItem.ItemType.FRAGMENT)
  		{
  			FragmentManager fm = getSupportFragmentManager();
  			if (fm.getBackStackEntryCount() > 0)
  			{
  				fm.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);
  			}
  			FragmentTransaction ft = fm.beginTransaction();
  			Fragment parent = fm.findFragmentById(R.id.content_frame);
  			if (parent != null)
  			{
  				ft.detach(parent);
  			}
  			Fragment fragment = fm.findFragmentByTag(item.name);
  			if (fragment != null)
  			{
  				ft.attach(fragment);
  			}
  			else
  			{
  				ft.add(R.id.content_frame, item.fragment, item.name);
  			}
  			ft.commit();
  			// update selected item and title, then close the drawer
  			updateDrawerUI(item, position);
  		}
  		else if (item.type == DrawerItem.ItemType.ACTION)
  		{
  			Log.e(TAG, "ACTION");
  			runOnUiThread(item.action);
  		}
  		mDrawerLayout.closeDrawer(mDrawerList);
  	}
  
  	@Override
  	public void setTitle(CharSequence title)
  	{
  		mTitle = title;
  		getSupportActionBar().setTitle(mTitle);
  	}
  
  	/**
  	 * When using the ActionBarDrawerToggle, you must call it during
  	 * onPostCreate() and onConfigurationChanged()...
  	 */
  
  	@Override
  	protected void onPostCreate(Bundle savedInstanceState)
  	{
  		super.onPostCreate(savedInstanceState);
  		// Sync the toggle state after onRestoreInstanceState has occurred.
  		mDrawerToggle.syncState();
  	}
  
  	@Override
  	public void onConfigurationChanged(Configuration newConfig)
  	{
  		super.onConfigurationChanged(newConfig);
  		// Pass any configuration change to the drawer toggles
  		mDrawerToggle.onConfigurationChanged(newConfig);
  	}
  	
  	@Override
  	public void onSaveInstanceState(Bundle savedInstanceState)
  	{
  		savedInstanceState.putInt("drawerPosition", mDrawerAdapter.getSelectedItem());
  		savedInstanceState.putString("title", (String) getSupportActionBar().getTitle());
  		super.onSaveInstanceState(savedInstanceState);
  	}
  
  	@Override
  	public void onRestoreInstanceState(@NonNull Bundle savedInstanceState)
  	{
  		super.onRestoreInstanceState(savedInstanceState);
  		int pos = savedInstanceState.getInt("drawerPosition");
  		DrawerItem item = mDrawerItems.get(pos);
  		updateDrawerUI(item, pos);
  		restoreDrawerUI();
  		getSupportActionBar().setTitle(savedInstanceState.getString("title"));
  	}
  
  	@Override
  	public void onWaypointView(Waypoint waypoint)
  	{
  		application.ensureVisible(waypoint);
  		selectItem(0);
  	}
  
  	@Override
  	public void onWaypointShow(Waypoint waypoint)
  	{
  		Location loc = application.getLocationAsLocation();
          FragmentManager fm = getSupportFragmentManager();
          WaypointInfo waypointInfo = (WaypointInfo) fm.findFragmentByTag("waypoint_info");
          if (waypointInfo == null)
          	waypointInfo = new WaypointInfo();
          waypointInfo.setWaypoint(waypoint);
  		Bundle args = new Bundle();
  		args.putDouble("lat", loc.getLatitude());
  		args.putDouble("lon", loc.getLongitude());
  		waypointInfo.setArguments(args);
  		waypointInfo.show(fm, "waypoint_info");
  	}
  
  	@Override
  	public void onWaypointDetails(Waypoint waypoint)
  	{
  		Location loc = application.getLocationAsLocation();
          FragmentManager fm = getSupportFragmentManager();
          WaypointDetails waypointDetails = (WaypointDetails) fm.findFragmentByTag("waypoint_details");
          if (waypointDetails == null)
          	waypointDetails = new WaypointDetails();
          waypointDetails.setWaypoint(waypoint);
  		Bundle args = new Bundle();
  		args.putDouble("lat", loc.getLatitude());
  		args.putDouble("lon", loc.getLongitude());
  		waypointDetails.setArguments(args);
  		addFragment(waypointDetails, "waypoint_details");
  	}
  
  	@Override
  	public void onWaypointNavigate(Waypoint waypoint)
  	{
  		application.startNavigation(waypoint);
  		selectItem(0);
  	}
  
  	@Override
  	public void onWaypointEdit(Waypoint waypoint)
  	{
  		FragmentManager fm = getSupportFragmentManager();
  		WaypointProperties waypointProperties = (WaypointProperties) fm.findFragmentByTag("waypoint_properties");
  		if (waypointProperties == null)
  			waypointProperties = (WaypointProperties) Fragment.instantiate(this, WaypointProperties.class.getName());
  		waypointProperties.setWaypoint(waypoint);
  		addFragment(waypointProperties, "waypoint_properties");
  	}
  
  	@Override
  	public void onWaypointShare(Waypoint waypoint)
  	{
  		Intent i = new Intent(android.content.Intent.ACTION_SEND);
  		i.setType("text/plain");
  		i.putExtra(Intent.EXTRA_SUBJECT, R.string.currentloc);
  		String coords = StringFormatter.coordinates(" ", waypoint.latitude, waypoint.longitude);
  		i.putExtra(Intent.EXTRA_TEXT, waypoint.name + " @ " + coords);
  		startActivity(Intent.createChooser(i, getString(R.string.menu_share)));
  	}
  
  	@Override
  	public void onWaypointRemove(final Waypoint waypoint)
  	{
  		application.undoWaypoint = waypoint;
  		application.removeWaypoint(waypoint);
  		application.saveWaypoints(waypoint.set);
  		application.getMapHolder().refreshMap();
  
  		Snackbar
  				.make(mCoordinatorLayout, R.string.waypoint_deleted, Snackbar.LENGTH_LONG)
  				.setAction(R.string.undo, new View.OnClickListener() {
  					@Override
  					public void onClick(View v)
  					{
  						if (application.undoWaypoint == null)
  							return;
  						application.addWaypoint(application.undoWaypoint);
  						application.saveWaypoints(waypoint.set);
  						application.getMapHolder().refreshMap();
  						application.undoWaypoint = null;
  					}
  				})
  				.show();
  	}
  
  	@Override
  	public void onOpenMap()
  	{
          MapList mapList = (MapList) Fragment.instantiate(this, MapList.class.getName());
  		addFragment(mapList, "map_list");
  	}
  
  	@Override
  	public void onMapDetails(BaseMap map)
  	{
  		//TODO Should show any map information, not only current
          MapInformation mapInformation = (MapInformation) Fragment.instantiate(this, MapInformation.class.getName());
  		addFragment(mapInformation, "map_information");
  	}
  
  	@Override
  	public void onMapSelectedAtPosition(BaseMap map)
  	{
  		application.setMap(map, true);
  	}
  
  	@Override
  	public void onMapSelected(BaseMap map)
  	{
  		application.loadMap(map);
  	}
  
  	@Override
  	public void onRouteDetails(Route route)
  	{
  		FragmentManager fm = getSupportFragmentManager();
  		RouteDetails routeDetails = (RouteDetails) fm.findFragmentByTag("route_details");
  		if (routeDetails == null)
  			routeDetails = (RouteDetails) Fragment.instantiate(this, RouteDetails.class.getName());
  		routeDetails.setRoute(route);
  		addFragment(routeDetails, "route_details");
  	}
  
  	@Override
  	public void onRouteNavigate(Route route)
  	{
          FragmentManager fm = getSupportFragmentManager();
          RouteStart routeStartDialog = new RouteStart(route);
          routeStartDialog.show(fm, "route_start");
  	}
  	
  	@Override
  	public void onRouteNavigate(Route route, int direction, int waypointIndex)
  	{
  		application.startNavigation(route, direction, waypointIndex);
  		selectItem(0);
  	}
  
  	@Override
  	public void onRouteEdit(Route route)
  	{
  		FragmentManager fm = getSupportFragmentManager();
  		RouteProperties routeProperties = (RouteProperties) fm.findFragmentByTag("route_properties");
  		if (routeProperties == null)
  			routeProperties = (RouteProperties) Fragment.instantiate(this, RouteProperties.class.getName());
  		routeProperties.setRoute(route);
  		addFragment(routeProperties, "route_properties");
  	}
  
  	@Override
  	public void onRouteEditPath(Route route)
  	{
  		application.editingRoute = route;
  		application.editingRoute.show = true;
  		application.editingRoute.editing = true;
  		application.routeEditingWaypoints = new Stack<>();
  		application.dispatchRoutePropertiesChanged(route);
  		selectItem(0);
  	}
  
  	@Override
  	public void onRouteSave(Route route)
  	{
          FragmentManager fm = getSupportFragmentManager();
          RouteSave routeSaveDialog = new RouteSave(route);
          routeSaveDialog.show(fm, "route_save");
  	}
  
  	@Override
  	public void onRouteWaypointEdit(Route route, Waypoint waypoint)
  	{
  		FragmentManager fm = getSupportFragmentManager();
  		WaypointProperties waypointProperties = (WaypointProperties) fm.findFragmentByTag("waypoint_properties");
  		if (waypointProperties == null)
  			waypointProperties = (WaypointProperties) Fragment.instantiate(this, WaypointProperties.class.getName());
  		waypointProperties.setWaypoint(waypoint, route);
  		addFragment(waypointProperties, "waypoint_properties");
  	}
  
  	@Override
  	public void onTrackView(Track track)
  	{
  		Track.TrackPoint tp = track.getPoint(0);
  		MapObject mo = new MapObject(tp.latitude, tp.longitude);
  		application.ensureVisible(mo);
  		selectItem(0);
  	}
  
  	@Override
  	public void onTrackDetails(Track track)
  	{
          FragmentManager fm = getSupportFragmentManager();
          TrackDetails trackDetails = (TrackDetails) fm.findFragmentByTag("track_details");
          if (trackDetails == null)
          	trackDetails = new TrackDetails();
          trackDetails.setTrack(track);
  		addFragment(trackDetails, "track_details");
  	}
  
  	@Override
  	public void onTrackEdit(Track track)
  	{
  		FragmentManager fm = getSupportFragmentManager();
  		TrackProperties trackProperties = (TrackProperties) fm.findFragmentByTag("track_properties");
  		if (trackProperties == null)
  			trackProperties = (TrackProperties) Fragment.instantiate(this, TrackProperties.class.getName());
  		trackProperties.setTrack(track);
  		addFragment(trackProperties, "track_properties");
  	}
  
  	@Override
  	public void onTrackEditPath(Track track)
  	{
  		Toast.makeText(this, R.string.msg_notimplemented, Toast.LENGTH_LONG).show();
  //		setResult(RESULT_OK, new Intent().putExtra("index", application.getTrackIndex(track)));
  	}
  
  	@Override
  	public void onTrackToRoute(Track track)
  	{
  		FragmentManager fm = getSupportFragmentManager();
  		TrackToRoute trackToRouteDialog = new TrackToRoute(track);
  		trackToRouteDialog.show(fm, "track_to_route");
  	}
  
  	@Override
  	public void onTrackSave(Track track)
  	{
          FragmentManager fm = getSupportFragmentManager();
          TrackSave trackSaveDialog = new TrackSave(track);
          trackSaveDialog.show(fm, "track_save");
  	}
  
  	@Override
  	public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
  	{
  		Resources resources = getResources();
  
  		if (getString(R.string.pref_exit).equals(key))
  		{
  			exitConfirmation = Integer.parseInt(sharedPreferences.getString(key, "0"));
  			initializeDrawerItems();
  			secondBack = false;
  		}
  		else if (getString(R.string.pref_hidestatusbar).equals(key))
  		{
  			if (sharedPreferences.getBoolean(key, resources.getBoolean(R.bool.def_hidestatusbar)))
  				getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
  			else
  				getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
  		}
  		else if (getString(R.string.pref_orientation).equals(key))
  		{
              //noinspection ResourceType
              setRequestedOrientation(Integer.parseInt(sharedPreferences.getString(key, "-1")));
  		}
  	}
  
  	private void initializeDrawerItems()
  	{
  		if (mDrawerItems == null)
  			return;
  
  		mDrawerItems.clear();
  
  		Resources resources = getResources();
  
  		Drawable icon;
  		Intent action;
  		Fragment fragment;
  		FragmentManager fm = getSupportFragmentManager();		
  
  		// add main items to drawer list
  		icon = resources.getDrawable(R.drawable.ic_map_white_24dp);
  		fragment = fm.findFragmentByTag(getString(R.string.menu_map));
  		if (fragment == null)
  			fragment = Fragment.instantiate(this, MapFragment.class.getName());
  		mDrawerItems.add(new DrawerItem(icon, getString(R.string.menu_map), fragment));
  
  		icon = resources.getDrawable(R.drawable.ic_place_white_24dp);
  		fragment = fm.findFragmentByTag(getString(R.string.menu_waypoints));
  		if (fragment == null)
  			fragment = Fragment.instantiate(this, WaypointList.class.getName());
  		mDrawerItems.add(new DrawerItem(icon, getString(R.string.menu_waypoints), fragment));
  
  		icon = resources.getDrawable(R.drawable.ic_directions_white_24dp);
  		fragment = fm.findFragmentByTag(getString(R.string.menu_routes));
  		if (fragment == null)
  			fragment = Fragment.instantiate(this, RouteList.class.getName());
  		mDrawerItems.add(new DrawerItem(icon, getString(R.string.menu_routes), fragment));
  
  		icon = resources.getDrawable(R.drawable.ic_gesture_white_24dp);
  		fragment = fm.findFragmentByTag(getString(R.string.menu_tracks));
  		if (fragment == null)
  			fragment = Fragment.instantiate(this, TrackList.class.getName());
  		mDrawerItems.add(new DrawerItem(icon, getString(R.string.menu_tracks), fragment));
  
  		// add plugins to drawer list
  		mDrawerItems.add(new DrawerItem());
  		icon = resources.getDrawable(R.drawable.ic_my_location_white_24dp);
  		action = new Intent(this, HSIActivity.class);
  		mDrawerItems.add(new DrawerItem(icon, getString(R.string.menu_hsi), action).makeMinor());
  
  		java.util.Map<String, Pair<Drawable, Intent>> plugins = application.getPluginsViews();
  		for (String plugin : plugins.keySet())
  		{
  			mDrawerItems.add(new DrawerItem(plugins.get(plugin).first, plugin, plugins.get(plugin).second).makeMinor());
  		}
  
  		// add supplementary items to drawer list
  		mDrawerItems.add(new DrawerItem());
  		icon = resources.getDrawable(R.drawable.ic_settings_white_24dp);
  		fragment = fm.findFragmentByTag(getString(R.string.menu_preferences));
  		if (fragment == null)
  			fragment = Fragment.instantiate(this, Preferences.class.getName());
  		mDrawerItems.add(new DrawerItem(icon, getString(R.string.menu_preferences), fragment).makeMinor().makeSupplementary());
  
  		icon = resources.getDrawable(R.drawable.ic_info_white_24dp);
  		fragment = fm.findFragmentByTag(getString(R.string.menu_about));
  		if (fragment == null)
  			fragment = Fragment.instantiate(this, About.class.getName());
  		mDrawerItems.add(new DrawerItem(icon, getString(R.string.menu_about), fragment).makeMinor().makeSupplementary());
  
  		if (exitConfirmation == 3)
  		{
  			icon = resources.getDrawable(R.drawable.ic_open_in_new_white_24dp);
  			Runnable exit = new Runnable() {
  				@Override
  				public void run()
  				{
  					Log.e(TAG, "Exit");
  					MainActivity.this.finish();
  				}
  			};
  			mDrawerItems.add(new DrawerItem(icon, getString(R.string.menu_exit), exit).makeMinor().makeSupplementary());
  		}
  
  		mDrawerAdapter.notifyDataSetChanged();
  	}
  
  	private void updateDrawerUI(DrawerItem item, int position)
  	{
  		mDrawerList.setItemChecked(position, true);
  		mDrawerAdapter.setSelectedItem(position);
  		setTitle(item.name);
  	}
  
  	private void restoreDrawerUI()
  	{
  		FragmentManager fm = getSupportFragmentManager();
  		if (fm.getBackStackEntryCount() > 0)
  		{
  			mDrawerToggle.setDrawerIndicatorEnabled(false);
  			
  			// FIXME This is the uggliest hack I have ever seen!
  			getDrawerToggleDelegate().setActionBarUpIndicator(mHomeDrawable, R.string.cancel);
  		    setSupportActionBar(mToolbar);
  		    // End of hack
  			
  			mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, mDrawerList);
  		}
  		else
  		{
  			mDrawerToggle.setDrawerIndicatorEnabled(true);
  			mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, mDrawerList);
  
  			int pos = mDrawerAdapter.getSelectedItem();
  			DrawerItem item = mDrawerItems.get(pos);
  			if (item.type == DrawerItem.ItemType.FRAGMENT)
  				updateDrawerUI(item, pos);
  		}
  	}
  	
  	private FragmentManager.OnBackStackChangedListener mBackStackChangedListener = new FragmentManager.OnBackStackChangedListener()
  	{
  		@Override
          public void onBackStackChanged()
          {
  			restoreDrawerUI();
          }
      };
  
  	final Handler backHandler = new Handler();
  
  	@Override
  	public void onBackPressed()
  	{
  		if (getSupportFragmentManager().getBackStackEntryCount() > 0)
  		{
  			super.onBackPressed();
  			return;
  		}
  		else if (mDrawerAdapter.getSelectedItem() != 0)
  		{
  			selectItem(0);
  			return;
  		}
  		
  		switch (exitConfirmation)
  		{
  			case 0:
  				// wait for second back
  				if (secondBack)
  				{
  					backToast.cancel();
  					MainActivity.this.finish();
  				}
  				else
  				{
  					secondBack = true;
  					backToast.show();
  					backHandler.postDelayed(new Runnable() {
  						@Override
  						public void run()
  						{
  							secondBack = false;
  						}
  					}, 2000);
  				}
  				return;
  			case 1:
  				// Ask the user if they want to quit
  				new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert).setTitle(R.string.quitQuestion).setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
  					@Override
  					public void onClick(DialogInterface dialog, int which)
  					{
  						MainActivity.this.finish();
  					}
  				}).setNegativeButton(R.string.no, null).show();
  				return;
  			case 3:
  				// Quit is performed from menu
  				return;
  			default:
  				super.onBackPressed();
  		}
  	}
  
  	@Override
  	public void addFragment(Fragment fragment, String tag)
  	{
  		FragmentManager fm = getSupportFragmentManager();
  		// Get topmost fragment
  		Fragment parent;
  		if (fm.getBackStackEntryCount() > 0)
  		{
  			FragmentManager.BackStackEntry bse = fm.getBackStackEntryAt(fm.getBackStackEntryCount() - 1);
  			parent = fm.findFragmentByTag(bse.getName());
  		}
  		else
  		{
  			parent = fm.findFragmentById(R.id.content_frame);
  		}
  		FragmentTransaction ft = fm.beginTransaction();
  		// Detach parent
  		ft.detach(parent);
  		// Add new fragment to back stack
  		ft.add(R.id.content_frame, fragment, tag);
  		ft.addToBackStack(tag);
  		ft.commit();
  	}
  
  	@Override
  	public FloatingActionButton enableActionButton()
  	{
  		ViewGroup.LayoutParams params = mToolbar.getLayoutParams();
  		mToolbarHeight = params.height;
  		params.height = getResources().getDimensionPixelSize(R.dimen.floating_action_button_toolbar_height);
  		mActionButton.setVisibility(View.VISIBLE);
  		return mActionButton;
  	}
  
  	@Override
  	public void disableActionButton()
  	{
  		ViewGroup.LayoutParams params = mToolbar.getLayoutParams();
  		params.height = mToolbarHeight;
  		mActionButton.setOnClickListener(null);
  		mActionButton.setVisibility(View.GONE);
  	}
  
  }
  