/*
 This file is part of Subsonic.

 Subsonic 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.

 Subsonic 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 Subsonic.  If not, see <http://www.gnu.org/licenses/>.

 Copyright 2009 (C) Sindre Mehus
 */
package github.popeen.dsub.activity;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Dialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.provider.MediaStore;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.sothree.slidinguppanel.SlidingUpPanelLayout;

import java.io.File;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.List;
import java.util.Random;

import github.popeen.dsub.R;
import github.popeen.dsub.domain.MusicDirectory;
import github.popeen.dsub.domain.PlayerQueue;
import github.popeen.dsub.domain.PlayerState;
import github.popeen.dsub.domain.ServerInfo;
import github.popeen.dsub.fragments.AdminFragment;
import github.popeen.dsub.fragments.ChatFragment;
import github.popeen.dsub.fragments.DownloadFragment;
import github.popeen.dsub.fragments.MainFragment;
import github.popeen.dsub.fragments.NowPlayingFragment;
import github.popeen.dsub.fragments.SearchFragment;
import github.popeen.dsub.fragments.SelectArtistFragment;
import github.popeen.dsub.fragments.SelectBookmarkFragment;
import github.popeen.dsub.fragments.SelectDirectoryFragment;
import github.popeen.dsub.fragments.SelectInternetRadioStationFragment;
import github.popeen.dsub.fragments.SelectPlaylistFragment;
import github.popeen.dsub.fragments.SelectPodcastsFragment;
import github.popeen.dsub.fragments.SelectShareFragment;
import github.popeen.dsub.fragments.SubsonicFragment;
import github.popeen.dsub.service.DownloadFile;
import github.popeen.dsub.service.DownloadService;
import github.popeen.dsub.service.MusicService;
import github.popeen.dsub.service.MusicServiceFactory;
import github.popeen.dsub.updates.Updater;
import github.popeen.dsub.util.Constants;
import github.popeen.dsub.util.DrawableTint;
import github.popeen.dsub.util.FileUtil;
import github.popeen.dsub.util.SilentBackgroundTask;
import github.popeen.dsub.util.UserUtil;
import github.popeen.dsub.util.Util;
import github.popeen.dsub.view.ChangeLog;

/**
 * Created by Scott on 10/14/13.
 */
public class SubsonicFragmentActivity extends SubsonicActivity implements DownloadService.OnSongChangedListener {
	private static String TAG = SubsonicFragmentActivity.class.getSimpleName();
	private static boolean infoDialogDisplayed;
	private static boolean sessionInitialized = false;
	private static long ALLOWED_SKEW = 30000L;

	private SlidingUpPanelLayout slideUpPanel;
	private SlidingUpPanelLayout.PanelSlideListener panelSlideListener;
	private boolean isPanelClosing = false;
	private NowPlayingFragment nowPlayingFragment;
	private SubsonicFragment secondaryFragment;
	private Toolbar mainToolbar;
	private Toolbar nowPlayingToolbar;

	private View bottomBar;
	private LinearLayout bottomBarControls;
	private ImageView coverArtView;
	private TextView trackView;
	private TextView artistView;
	private ImageButton startButton;
	private long lastBackPressTime = 0;
	private DownloadFile currentPlaying;
	private PlayerState currentState;
	private ImageButton previousButton;
	private ImageButton nextButton;
	private ImageButton rewindButton;
	private ImageButton fastforwardButton;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		if(savedInstanceState == null) {
			String fragmentType = getIntent().getStringExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE);
			boolean firstRun = false;
			if (fragmentType == null) {
				fragmentType = Util.openToTab(this);
				if (fragmentType != null) {
					firstRun = true;
				}
			}

			if ("".equals(fragmentType) || fragmentType == null || firstRun) {
				// Initial startup stuff
				if (!sessionInitialized) {
					loadSession();
				}
			}
		}

		super.onCreate(savedInstanceState);
		if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_EXIT)) {
			stopService(new Intent(this, DownloadService.class));
			finish();
			getImageLoader().clearCache();
			DrawableTint.clearCache();
		} else if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW)) {
			getIntent().putExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE, "Download");
			lastSelectedPosition = R.id.drawer_downloading;
		}
		setContentView(R.layout.abstract_fragment_activity);

		if (findViewById(R.id.fragment_container) != null && savedInstanceState == null) {
			String fragmentType = getIntent().getStringExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE);
			if(fragmentType == null) {
				fragmentType = Util.openToTab(this);
				if(fragmentType != null) {
					getIntent().putExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE, fragmentType);
					lastSelectedPosition = getDrawerItemId(fragmentType);
				} else {
					lastSelectedPosition = R.id.drawer_home;
				}

				MenuItem item = drawerList.getMenu().findItem(lastSelectedPosition);
				if(item != null) {
					item.setChecked(true);
				}
			} else {
				lastSelectedPosition = getDrawerItemId(fragmentType);
			}

			currentFragment = getNewFragment(fragmentType);
			if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_ID)) {
				Bundle currentArguments = currentFragment.getArguments();
				if(currentArguments == null) {
					currentArguments = new Bundle();
				}
				currentArguments.putString(Constants.INTENT_EXTRA_NAME_ID, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ID));
				currentFragment.setArguments(currentArguments);
			}
			currentFragment.setPrimaryFragment(true);
			getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, currentFragment, currentFragment.getSupportTag() + "").commit();

			if(getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY) != null) {
				SearchFragment fragment = new SearchFragment();
				replaceFragment(fragment, fragment.getSupportTag());
			}

			// If a album type is set, switch to that album type view
			String albumType = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE);
			if(albumType != null) {
				SubsonicFragment fragment = new SelectDirectoryFragment();

				Bundle args = new Bundle();
				args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, albumType);
				args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20);
				args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);

				fragment.setArguments(args);
				replaceFragment(fragment, fragment.getSupportTag());
			}
		}

		slideUpPanel = (SlidingUpPanelLayout) findViewById(R.id.slide_up_panel);
		panelSlideListener = new SlidingUpPanelLayout.PanelSlideListener() {
			@Override
			public void onPanelSlide(View panel, float slideOffset) {

			}

			@Override
			public void onPanelCollapsed(View panel) {
				isPanelClosing = false;
				if(bottomBar.getVisibility() == View.GONE) {
					bottomBar.setVisibility(View.VISIBLE);
					nowPlayingToolbar.setVisibility(View.GONE);
					nowPlayingFragment.setPrimaryFragment(false);
					setSupportActionBar(mainToolbar);
					recreateSpinner();
				}
			}

			@Override
			public void onPanelExpanded(View panel) {
				isPanelClosing = false;
				currentFragment.stopActionMode();

				// Disable custom view before switching
				getSupportActionBar().setDisplayShowCustomEnabled(false);
				getSupportActionBar().setDisplayShowTitleEnabled(true);

				bottomBar.setVisibility(View.GONE);
				nowPlayingToolbar.setVisibility(View.VISIBLE);
				setSupportActionBar(nowPlayingToolbar);

				if(secondaryFragment == null) {
					nowPlayingFragment.setPrimaryFragment(true);
				} else {
					secondaryFragment.setPrimaryFragment(true);
				}

				drawerToggle.setDrawerIndicatorEnabled(false);
				getSupportActionBar().setDisplayHomeAsUpEnabled(true);
			}

			@Override
			public void onPanelAnchored(View panel) {

			}

			@Override
			public void onPanelHidden(View panel) {
			}
		};
		slideUpPanel.setPanelSlideListener(panelSlideListener);

		if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD)) {
			// Post this later so it actually runs
			handler.postDelayed(new Runnable() {
				@Override
				public void run() {
					openNowPlaying();
				}
			}, 200);

			getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD);
		}

		bottomBar = findViewById(R.id.bottom_bar);
		bottomBarControls = findViewById(R.id.bottom_bar_controls);
		mainToolbar = (Toolbar) findViewById(R.id.main_toolbar);
		nowPlayingToolbar = (Toolbar) findViewById(R.id.now_playing_toolbar);
		coverArtView = (ImageView) bottomBar.findViewById(R.id.album_art);
		trackView = (TextView) bottomBar.findViewById(R.id.track_name);
		artistView = (TextView) bottomBar.findViewById(R.id.artist_name);

		bottomBarControls = findViewById(R.id.bottom_bar_controls);
		if(Util.getPreferences(this).getBoolean(Constants.PREFERENCES_KEY_BOTTOM_BAR_CONTROLS_ENABLED, false)){
			bottomBarControls.setVisibility(View.VISIBLE);
		}else{
			bottomBarControls.setVisibility(View.GONE);
		}

		setSupportActionBar(mainToolbar);

		if (findViewById(R.id.fragment_container) != null && savedInstanceState == null) {
			nowPlayingFragment = new NowPlayingFragment();
			FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
			trans.add(R.id.now_playing_fragment_container, nowPlayingFragment, nowPlayingFragment.getTag() + "");
			trans.commit();
		}

		rewindButton = (ImageButton) findViewById(R.id.download_rewind);
		rewindButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
					@Override
					protected Void doInBackground() throws Throwable {
						if (getDownloadService() == null) {
							return null;
						}

						getDownloadService().rewind();
						return null;
					}
				}.execute();
			}
		});

		previousButton = (ImageButton) findViewById(R.id.download_previous);
		previousButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
					@Override
					protected Void doInBackground() throws Throwable {
						if(getDownloadService() == null) {
							return null;
						}

						getDownloadService().previous();
						return null;
					}
				}.execute();
			}
		});

		startButton = (ImageButton) findViewById(R.id.download_start);
		startButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
					@Override
					protected Void doInBackground() throws Throwable {
						PlayerState state = getDownloadService().getPlayerState();
						if(state == PlayerState.STARTED) {
							getDownloadService().pause();
						} else if(state == PlayerState.IDLE) {
							getDownloadService().play();
						} else {
							getDownloadService().start();
						}

						return null;
					}
				}.execute();
			}
		});

		nextButton = (ImageButton) findViewById(R.id.download_next);
		nextButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
					@Override
					protected Void doInBackground() throws Throwable {
						if(getDownloadService() == null) {
							return null;
						}

						getDownloadService().next();
						return null;
					}
				}.execute();
			}
		});

		fastforwardButton = (ImageButton) findViewById(R.id.download_fastforward);
		fastforwardButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
					@Override
					protected Void doInBackground() throws Throwable {
						if (getDownloadService() == null) {
							return null;
						}

						getDownloadService().fastForward();
						return null;
					}
				}.execute();
			}
		});
	}

	@Override
	protected void onPostCreate(Bundle bundle) {
		super.onPostCreate(bundle);

		showInfoDialog();
		checkUpdates();

		ChangeLog changeLog = new ChangeLog(this, Util.getPreferences(this));
		if(changeLog.isFirstRun()) {
			if(changeLog.isFirstRunEver()) {
				changeLog.updateVersionInPreferences();
			} else {
				Dialog log = changeLog.getLogDialog();
				if (log != null) {
					//log.show(); //For now we don't want to show changelog on first start after update, most users don't care about this. If they want to see it they can do that from the top right menu. Might change it back later depending on feedback.
				}
			}
		}
	}

	@Override
	public void onNewIntent(Intent intent) {
		super.onNewIntent(intent);

		if(currentFragment != null && intent.getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY) != null) {
			if(slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) {
				closeNowPlaying();
			}

			if(currentFragment instanceof SearchFragment) {
				String query = intent.getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY);
				boolean autoplay = intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false);
				String artist = intent.getStringExtra(MediaStore.EXTRA_MEDIA_ARTIST);
				String album = intent.getStringExtra(MediaStore.EXTRA_MEDIA_ALBUM);
				String title = intent.getStringExtra(MediaStore.EXTRA_MEDIA_TITLE);

				if (query != null) {
					((SearchFragment)currentFragment).search(query, autoplay, artist, album, title);
				}
				getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_QUERY);
			} else {
				setIntent(intent);

				SearchFragment fragment = new SearchFragment();
				replaceFragment(fragment, fragment.getSupportTag());
			}
		} else if(intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, false)) {
			if(slideUpPanel.getPanelState() != SlidingUpPanelLayout.PanelState.EXPANDED) {
				openNowPlaying();
			}
		} else {
			if(slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) {
				closeNowPlaying();
			}
			setIntent(intent);
		}
		if(drawer != null) {
			drawer.closeDrawers();
		}
	}



	@Override
	public void onResume() {
		super.onResume();

		if(!Util.installedFromPlayStore(this) && Util.isSignedByPopeen(this)){
			Util.toast(this, "You are using a sideloaded app and will only be able to use it in demo mode.", false);
		}

		bottomBarControls = findViewById(R.id.bottom_bar_controls);
		if(Util.getPreferences(this).getBoolean(Constants.PREFERENCES_KEY_BOTTOM_BAR_CONTROLS_ENABLED, false)){
			bottomBarControls.setVisibility(View.VISIBLE);
		}else{
			bottomBarControls.setVisibility(View.GONE);
		}

		if(getIntent().hasExtra(Constants.INTENT_EXTRA_VIEW_ALBUM)) {
			SubsonicFragment fragment = new SelectDirectoryFragment();
			Bundle args = new Bundle();
			args.putString(Constants.INTENT_EXTRA_NAME_ID, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ID));
			args.putString(Constants.INTENT_EXTRA_NAME_NAME, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_NAME));
			args.putString(Constants.INTENT_EXTRA_SEARCH_SONG, getIntent().getStringExtra(Constants.INTENT_EXTRA_SEARCH_SONG));
			if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_ARTIST)) {
				args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true);
			}
			if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_CHILD_ID)) {
				args.putString(Constants.INTENT_EXTRA_NAME_CHILD_ID, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_CHILD_ID));
			}
			fragment.setArguments(args);

			replaceFragment(fragment, fragment.getSupportTag());
			getIntent().removeExtra(Constants.INTENT_EXTRA_VIEW_ALBUM);
		}

		UserUtil.seedCurrentUser(this);
		createAccount();
		runWhenServiceAvailable(new Runnable() {
			@Override
			public void run() {
				getDownloadService().addOnSongChangedListener(SubsonicFragmentActivity.this, true);
			}
		});
	}

	@Override
	public void onPause() {
		super.onPause();
		DownloadService downloadService = getDownloadService();
		if(downloadService != null) {
			downloadService.removeOnSongChangeListener(this);
		}
	}

	@Override
	public void onSaveInstanceState(Bundle savedInstanceState) {
		super.onSaveInstanceState(savedInstanceState);
		savedInstanceState.putString(Constants.MAIN_NOW_PLAYING, nowPlayingFragment.getTag());
		if(secondaryFragment != null) {
			savedInstanceState.putString(Constants.MAIN_NOW_PLAYING_SECONDARY, secondaryFragment.getTag());
		}
		savedInstanceState.putInt(Constants.MAIN_SLIDE_PANEL_STATE, slideUpPanel.getPanelState().hashCode());
	}
	@Override
	public void onRestoreInstanceState(Bundle savedInstanceState) {
		super.onRestoreInstanceState(savedInstanceState);

		String id = savedInstanceState.getString(Constants.MAIN_NOW_PLAYING);
		FragmentManager fm = getSupportFragmentManager();
		nowPlayingFragment = (NowPlayingFragment) fm.findFragmentByTag(id);

		String secondaryId = savedInstanceState.getString(Constants.MAIN_NOW_PLAYING_SECONDARY);
		if(secondaryId != null) {
			secondaryFragment = (SubsonicFragment) fm.findFragmentByTag(secondaryId);

			nowPlayingFragment.setPrimaryFragment(false);
			secondaryFragment.setPrimaryFragment(true);

			FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
			trans.hide(nowPlayingFragment);
			trans.commit();
		}

		if(drawerToggle != null && backStack.size() > 0) {
			drawerToggle.setDrawerIndicatorEnabled(false);
		}

		if(savedInstanceState.getInt(Constants.MAIN_SLIDE_PANEL_STATE, -1) == SlidingUpPanelLayout.PanelState.EXPANDED.hashCode()) {
			panelSlideListener.onPanelExpanded(null);
		}
	}

	@Override
	public void setContentView(int viewId) {
		super.setContentView(viewId);
		if(drawerToggle != null){
			drawerToggle.setDrawerIndicatorEnabled(true);
		}
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		return super.onOptionsItemSelected(item);
	}

	@Override
	public void onBackPressed() {
		if(slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED && secondaryFragment == null) {
			slideUpPanel.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
		} else if(onBackPressedSupport()) {
			if(!Util.disableExitPrompt(this) && lastBackPressTime < (System.currentTimeMillis() - 4000)) {
				lastBackPressTime = System.currentTimeMillis();
				Util.toast(this, R.string.main_back_confirm);
			} else {
				finish();
			}
		}
	}

	@Override
	public boolean onBackPressedSupport() {
		if(slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) {
			removeCurrent();
			return false;
		} else {
			return super.onBackPressedSupport();
		}
	}

	@Override
	public SubsonicFragment getCurrentFragment() {
		if(slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) {
			if(secondaryFragment == null) {
				return nowPlayingFragment;
			} else {
				return secondaryFragment;
			}
		} else {
			return super.getCurrentFragment();
		}
	}

	@Override
	public void replaceFragment(SubsonicFragment fragment, int tag, boolean replaceCurrent) {
		if(slideUpPanel != null && slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED && !isPanelClosing) {
			secondaryFragment = fragment;
			nowPlayingFragment.setPrimaryFragment(false);
			secondaryFragment.setPrimaryFragment(true);
			supportInvalidateOptionsMenu();

			FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
			trans.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right);
			trans.hide(nowPlayingFragment);
			trans.add(R.id.now_playing_fragment_container, secondaryFragment, tag + "");
			trans.commit();
		} else {
			super.replaceFragment(fragment, tag, replaceCurrent);
		}
	}
	@Override
	public void removeCurrent() {
		if(slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED && secondaryFragment != null) {
			FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
			trans.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left);
			trans.remove(secondaryFragment);
			trans.show(nowPlayingFragment);
			trans.commit();

			secondaryFragment = null;
			nowPlayingFragment.setPrimaryFragment(true);
			supportInvalidateOptionsMenu();
		} else {
			super.removeCurrent();
		}
	}

	@Override
	public void setTitle(CharSequence title) {
		if(slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) {
			getSupportActionBar().setTitle(title);
		} else {
			super.setTitle(title);
		}
	}

	@Override
	protected void drawerItemSelected(String fragmentType) {
		super.drawerItemSelected(fragmentType);

		if(slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) {
			slideUpPanel.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
		}
	}

	@Override
	public void startFragmentActivity(String fragmentType) {
		// Create a transaction that does all of this
		FragmentTransaction trans = getSupportFragmentManager().beginTransaction();

		// Clear existing stack
		for(int i = backStack.size() - 1; i >= 0; i--) {
			trans.remove(backStack.get(i));
		}
		trans.remove(currentFragment);
		backStack.clear();

		// Create new stack
		currentFragment = getNewFragment(fragmentType);
		currentFragment.setPrimaryFragment(true);
		trans.add(R.id.fragment_container, currentFragment, currentFragment.getSupportTag() + "");

		// Done, cleanup
		trans.commit();
		supportInvalidateOptionsMenu();
		recreateSpinner();
		if(drawer != null) {
			drawer.closeDrawers();
		}

		if(secondaryContainer != null) {
			secondaryContainer.setVisibility(View.GONE);
		}
		if(drawerToggle != null) {
			drawerToggle.setDrawerIndicatorEnabled(true);
		}
	}

	@Override
	public void openNowPlaying() {
		slideUpPanel.setPanelState(SlidingUpPanelLayout.PanelState.EXPANDED);
	}
	@Override
	public void closeNowPlaying() {
		slideUpPanel.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
		isPanelClosing = true;
	}

	private SubsonicFragment getNewFragment(String fragmentType) {
		if("Artist".equals(fragmentType)) {
			return new SelectArtistFragment();
		} else if("Playlist".equals(fragmentType)) {
			return new SelectPlaylistFragment();
		} else if("Chat".equals(fragmentType)) {
			return new ChatFragment();
		} else if("Podcast".equals(fragmentType)) {
			return new SelectPodcastsFragment();
		} else if("Bookmark".equals(fragmentType)) {
			return new SelectBookmarkFragment();
		} else if("Internet Radio".equals(fragmentType)) {
			return new SelectInternetRadioStationFragment();
		} else if("Share".equals(fragmentType)) {
			return new SelectShareFragment();
		} else if("Admin".equals(fragmentType)) {
			return new AdminFragment();
		} else if("Download".equals(fragmentType)) {
			return new DownloadFragment();
		} else {
			return new MainFragment();
		}
	}

	public void checkUpdates() {
		try {
			String version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
			int ver = Integer.parseInt(version.replace(".", ""));
			Updater updater = new Updater(ver);
			updater.checkUpdates(this);
		}
		catch(Exception e) {}
	}

	private void loadSession() {
		loadSettings();
		if(!Util.isOffline(this) && ServerInfo.canBookmark(this)) {
			loadBookmarks();
		}
		// If we are on Subsonic 5.2+, save play queue
		if(ServerInfo.canSavePlayQueue(this) && !Util.isOffline(this)) {
			loadRemotePlayQueue();
		}

		sessionInitialized = true;
	}
	private void loadSettings() {
		PreferenceManager.setDefaultValues(this, R.xml.settings_appearance, false);
		PreferenceManager.setDefaultValues(this, R.xml.settings_cache, false);
		PreferenceManager.setDefaultValues(this, R.xml.settings_drawer, false);
		PreferenceManager.setDefaultValues(this, R.xml.settings_sync, false);
		PreferenceManager.setDefaultValues(this, R.xml.settings_playback, false);

		SharedPreferences prefs = Util.getPreferences(this);
		if (!prefs.contains(Constants.PREFERENCES_KEY_CACHE_LOCATION) || prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null) == null) {
			resetCacheLocation(prefs);
		} else {
			String path = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
			File cacheLocation = new File(path);
			if(!FileUtil.verifyCanWrite(cacheLocation)) {
				// Only warn user if there is a difference saved
				if(resetCacheLocation(prefs)) {
					Util.info(this, R.string.common_warning, R.string.settings_cache_location_reset);
				}
			}
		}

		if (!prefs.contains(Constants.PREFERENCES_KEY_OFFLINE)) {
			SharedPreferences.Editor editor = prefs.edit();
			editor.putBoolean(Constants.PREFERENCES_KEY_OFFLINE, false);

			editor.putString(Constants.PREFERENCES_KEY_SERVER_NAME + 1, "Demo Server");
			editor.putString(Constants.PREFERENCES_KEY_SERVER_URL + 1, "http://demo.booksonic.org/booksonic");
			editor.putString(Constants.PREFERENCES_KEY_USERNAME + 1, "guest");
			editor.putString(Constants.PREFERENCES_KEY_PASSWORD + 1, "guest");
			editor.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
			editor.commit();
		}
		if(!prefs.contains(Constants.PREFERENCES_KEY_SERVER_COUNT)) {
			SharedPreferences.Editor editor = prefs.edit();
			editor.putInt(Constants.PREFERENCES_KEY_SERVER_COUNT, 1);
			editor.commit();
		}
	}

	private boolean resetCacheLocation(SharedPreferences prefs) {
		String newDirectory = FileUtil.getDefaultMusicDirectory(this).getPath();
		String oldDirectory = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
		if(newDirectory == null || (oldDirectory != null && newDirectory.equals(oldDirectory))) {
			return false;
		} else {
			SharedPreferences.Editor editor = prefs.edit();
			editor.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, newDirectory);
			editor.commit();
			return true;
		}
	}

	private void loadBookmarks() {
		final Context context = this;
		new SilentBackgroundTask<Void>(context) {
			@Override
			public Void doInBackground() throws Throwable {
				MusicService musicService = MusicServiceFactory.getMusicService(context);
				musicService.getBookmarks(true, context, null);

				return null;
			}

			@Override
			public void error(Throwable error) {
				Log.e(TAG, "Failed to get bookmarks", error);
			}
		}.execute();
	}
	private void loadRemotePlayQueue() {
		if(Util.getPreferences(this).getBoolean(Constants.PREFERENCES_KEY_RESUME_PLAY_QUEUE_NEVER, false)) {
			return;
		}

		final SubsonicActivity context = this;
		new SilentBackgroundTask<Void>(this) {
			private PlayerQueue playerQueue;

			@Override
			protected Void doInBackground() throws Throwable {
				try {
					MusicService musicService = MusicServiceFactory.getMusicService(context);
					PlayerQueue remoteState = musicService.getPlayQueue(context, null);

					// Make sure we wait until download service is ready
					DownloadService downloadService = getDownloadService();
					while(downloadService == null || !downloadService.isInitialized()) {
						Util.sleepQuietly(100L);
						downloadService = getDownloadService();
					}

					// If we had a remote state and it's changed is more recent than our existing state
					if(remoteState != null && remoteState.changed != null) {
						// Check if changed + 30 seconds since some servers have slight skew
						Date remoteChange = new Date(remoteState.changed.getTime() - ALLOWED_SKEW);
						Date localChange = downloadService.getLastStateChanged();
						if(localChange == null || localChange.before(remoteChange)) {
							playerQueue = remoteState;
						}
					}
				} catch (Exception e) {
					Log.e(TAG, "Failed to get playing queue to server", e);
				}

				return null;
			}

			@Override
			protected void done(Void arg) {
				if(!context.isDestroyedCompat() && playerQueue != null) {
					promptRestoreFromRemoteQueue(playerQueue);
				}
			}
		}.execute();
	}
	private void promptRestoreFromRemoteQueue(final PlayerQueue remoteState) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		String message = getResources().getString(R.string.common_confirm_message, getResources().getString(R.string.download_restore_play_queue).toLowerCase(), Util.formatDate(remoteState.changed));
		builder.setIcon(android.R.drawable.ic_dialog_alert)
				.setTitle(R.string.common_confirm)
				.setMessage(message)
				.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialogInterface, int i) {
						new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
							@Override
							protected Void doInBackground() throws Throwable {
								DownloadService downloadService = getDownloadService();
								downloadService.clear();
								downloadService.download(remoteState.songs, false, false, false, false, remoteState.currentPlayingIndex, remoteState.currentPlayingPosition);
								return null;
							}
						}.execute();
					}
				})
				.setNeutralButton(R.string.common_cancel, new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialogInterface, int i) {
						new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
							@Override
							protected Void doInBackground() throws Throwable {
								DownloadService downloadService = getDownloadService();
								downloadService.serializeQueue(false);
								return null;
							}
						}.execute();
					}
				})
				.setNegativeButton(R.string.common_never, new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialogInterface, int i) {
						new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
							@Override
							protected Void doInBackground() throws Throwable {
								DownloadService downloadService = getDownloadService();
								downloadService.serializeQueue(false);

								SharedPreferences.Editor editor = Util.getPreferences(SubsonicFragmentActivity.this).edit();
								editor.putBoolean(Constants.PREFERENCES_KEY_RESUME_PLAY_QUEUE_NEVER, true);
								editor.commit();
								return null;
							}
						}.execute();
					}
				});

		builder.create().show();
	}

	private void createAccount() {
		final Context context = this;

		new SilentBackgroundTask<Void>(this) {
			@Override
			protected Void doInBackground() throws Throwable {
				AccountManager accountManager = (AccountManager) context.getSystemService(ACCOUNT_SERVICE);
				Account account = new Account(Constants.SYNC_ACCOUNT_NAME, Constants.SYNC_ACCOUNT_TYPE);
				accountManager.addAccountExplicitly(account, null, null);

				SharedPreferences prefs = Util.getPreferences(context);
				boolean syncEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_SYNC_ENABLED, true);
				int syncInterval = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_SYNC_INTERVAL, "60"));

				// Add enabled/frequency to playlist/podcasts syncing
				ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, syncEnabled);
				ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, new Bundle(), 60L * syncInterval);
				ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_PODCAST_AUTHORITY, syncEnabled);
				ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_PODCAST_AUTHORITY, new Bundle(), 60L * syncInterval);

				// Add for starred/recently added
				ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_STARRED_AUTHORITY, (syncEnabled && prefs.getBoolean(Constants.PREFERENCES_KEY_SYNC_STARRED, false)));
				ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_STARRED_AUTHORITY, new Bundle(), 60L * syncInterval);
				ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_MOST_RECENT_AUTHORITY, (syncEnabled && prefs.getBoolean(Constants.PREFERENCES_KEY_SYNC_MOST_RECENT, false)));
				ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_MOST_RECENT_AUTHORITY, new Bundle(), 60L * syncInterval);
				return null;
			}

			@Override
			protected void done(Void result) {

			}
		}.execute();
	}

	private void showInfoDialog() {
		infoDialogDisplayed = true;
		if(Util.getRestUrl(this, null).contains("demo.booksonic.org")) {
			startActivity(new Intent(this, LoginActivity.class));
		}
	}

	public Toolbar getActiveToolbar() {
		return slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED ? nowPlayingToolbar : mainToolbar;
	}

	@Override
	public void onSongChanged(DownloadFile currentPlaying, int currentPlayingIndex, boolean shouldFastForward) {
		this.currentPlaying = currentPlaying;

		MusicDirectory.Entry song = null;
		if (currentPlaying != null) {
			song = currentPlaying.getSong();
			trackView.setText(song.getTitle());

			if(song.getArtist() != null) {
				artistView.setVisibility(View.VISIBLE);
				artistView.setText(song.getArtist());
			} else {
				artistView.setVisibility(View.GONE);
			}
		} else {
			trackView.setText(R.string.main_title);
			artistView.setText(R.string.main_artist);
		}

		if (coverArtView != null) {
			int height = coverArtView.getHeight();
			if (height <= 0) {
				int[] attrs = new int[]{R.attr.actionBarSize};
				TypedArray typedArray = this.obtainStyledAttributes(attrs);
				height = typedArray.getDimensionPixelSize(0, 0);
				typedArray.recycle();
			}
			getImageLoader().loadImage(coverArtView, song, false, height, false);
		}

		updateMediaButtons(true);
	}

	private void updateMediaButtons(boolean shouldFastForward) {
		DownloadService downloadService = getDownloadService();
		if(downloadService.isCurrentPlayingSingle()) {
			previousButton.setVisibility(View.GONE);
			nextButton.setVisibility(View.GONE);

			rewindButton.setVisibility(View.GONE);
			fastforwardButton.setVisibility(View.GONE);
		} else {
			if (shouldFastForward) {
				previousButton.setVisibility(View.GONE);
				nextButton.setVisibility(View.GONE);

				rewindButton.setVisibility(View.VISIBLE);
				fastforwardButton.setVisibility(View.VISIBLE);
			} else {
				previousButton.setVisibility(View.VISIBLE);
				nextButton.setVisibility(View.VISIBLE);

				rewindButton.setVisibility(View.GONE);
				fastforwardButton.setVisibility(View.GONE);
			}
		}
	}

	@Override
	public void onSongsChanged(List<DownloadFile> songs, DownloadFile currentPlaying, int currentPlayingIndex, boolean shouldFastForward) {
		if(this.currentPlaying != currentPlaying || this.currentPlaying == null) {
			onSongChanged(currentPlaying, currentPlayingIndex, shouldFastForward);
		} else {
			updateMediaButtons(true);
		}
	}

	@Override
	public void onSongProgress(DownloadFile currentPlaying, int millisPlayed, Integer duration, boolean isSeekable) {

	}

	@Override
	public void onStateUpdate(DownloadFile downloadFile, PlayerState playerState) {
		int[] attrs = new int[]{(playerState == PlayerState.STARTED) ? R.attr.actionbar_pause : R.attr.actionbar_start};
		TypedArray typedArray = this.obtainStyledAttributes(attrs);
		startButton.setImageResource(typedArray.getResourceId(0, 0));
		typedArray.recycle();
	}

	@Override
	public void onMetadataUpdate(MusicDirectory.Entry song, int fieldChange) {
		if(song != null && coverArtView != null && fieldChange == DownloadService.METADATA_UPDATED_COVER_ART) {
			int height = coverArtView.getHeight();
			if (height <= 0) {
				int[] attrs = new int[]{R.attr.actionBarSize};
				TypedArray typedArray = this.obtainStyledAttributes(attrs);
				height = typedArray.getDimensionPixelSize(0, 0);
				typedArray.recycle();
			}
			getImageLoader().loadImage(coverArtView, song, false, height, false);

			// We need to update it immediately since it won't update if updater is not running for it
			if(nowPlayingFragment != null && slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
				nowPlayingFragment.onMetadataUpdate(song, fieldChange);
			}
		}
	}
}