/*
 * ************************************************************************
 *
 * ADOBE SYSTEMS INCORPORATED
 * Copyright 2013 Adobe Systems Incorporated
 * All Rights Reserved.
 * NOTICE:  Adobe permits you to use, modify, and distribute this file in accordance with the 
 * terms of the Adobe license agreement accompanying it.  If you have received this file from a 
 * source other than Adobe, then your use, modification, or distribution of it requires the prior 
 * written permission of Adobe.
 *
 **************************************************************************
 */

/*
 *  PlayerFragment class contains all the UI components such as the playerFrame,
 *  ControlBar,playerClickableAdFragment,adOverlay and audioProfile.
 *  It handles the initialization of all these components as well as creating the player,setting up the views, creating feature managers for the media player,
 *  handling media events such as resume,play,pause and handling the event listeners for QoSManager,DRMManager,CCManager,AAManager,
 *  AdsManager and PlaybackManager.
 */

package com.adobe.primetime.reference.ui.player;

import android.app.ActionBar.LayoutParams;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.adobe.mediacore.MediaPlayer;
import com.adobe.mediacore.MediaPlayerStatus;
import com.adobe.mediacore.MediaPlayerException;
import com.adobe.mediacore.PSDKErrorCode;
import com.adobe.mediacore.timeline.Timeline;
import com.adobe.mediacore.timeline.advertising.Ad;
import com.adobe.mediacore.timeline.advertising.NetworkAdInfo;
import com.adobe.mediacore.timeline.advertising.AdBreak;
import com.adobe.mediacore.utils.TimeRange;
import com.adobe.primetime.reference.PrimetimeReference;
import com.adobe.primetime.reference.R;
import com.adobe.primetime.reference.config.ConfigProvider;
import com.adobe.primetime.reference.drm.DRMErrorDialog;
import com.adobe.primetime.reference.manager.AAManager;
import com.adobe.primetime.reference.manager.AAManagerOn;
import com.adobe.primetime.reference.manager.AdsManager;
import com.adobe.primetime.reference.manager.AdsManagerOn;
import com.adobe.primetime.reference.manager.CCManager;
import com.adobe.primetime.reference.manager.DrmManager;
import com.adobe.primetime.reference.manager.ManagerFactory;
import com.adobe.primetime.reference.manager.PlaybackManager;
import com.adobe.primetime.reference.manager.PlaybackManager.PlaybackManagerEventListener;
import com.adobe.primetime.reference.manager.QosManager;
import com.adobe.primetime.reference.ui.catalog.VideoItem;
import com.adobe.primetime.reference.ui.player.CustomFrameLayout.OnSizeChangeListener;
import com.adobe.primetime.reference.utils.Clock;
import com.adobe.primetime.reference.utils.PreferencesUtils;
import com.adobe.mediacore.drm.DRMManager;

import com.npaw.youbora.lib6.YouboraLog;
import com.npaw.youbora.lib6.adobe.AdobeAdapter;
import com.npaw.youbora.lib6.adobe.AdobeAdsAdapter;
import com.npaw.youbora.lib6.plugin.Options;
import com.npaw.youbora.lib6.plugin.Plugin;
import com.npaw.youbora.lib6.utils.youboraconfigutils.YouboraConfigManager;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static android.content.Intent.ACTION_VIEW;

public class PlayerFragment extends Fragment {
	private final String LOG_TAG = PrimetimeReference.LOG_APP_NAME
			+ PlayerFragment.class.getSimpleName();
	private final String CURRENT_PLAYER_POSITION = "current_player_position",
			CURRENT_PLAYER_STATE = "current_player_state";
	private final String PLAYBACK_CLOCK = "PlaybackClock";
	private final static float CONTROL_BAR_RATIO = 0.6f,
			ACTION_BAR_RATIO = 0.2f;

	private MediaPlayer mediaPlayer;

	private VideoItem videoItem;

	// lifecycle tracking variables
	private long lastKnownTime;
	private MediaPlayerStatus lastKnownStatus = MediaPlayerStatus.IDLE;
	private boolean isRestored;
	private PlayerControlBar.ControlBarEvent lastIgnoredEvent;

	// UI components
	private FrameLayout playerFrame;
	private PlayerControlBar controlBar;
	private PlayerClickableAdFragment playerClickableAdFragment;
	private ProgressBar spinner;
	private AdOverlay adOverlay;
	private TextView audioProfile;
	private ViewGroup playerFragmentView;
	private ImageButton _ccButton,_rewindButton,btnTouchPause;
	float savedMovieWidth;
	private float savedMovieHeight;

	private Handler handler = new Handler();

	private MediaPlayerStatus savedPlayerState;

	private Clock playbackClock;
	private Clock.ClockEventListener playbackClockEventListener;

	// feature managers
	private PlaybackManager playbackManager;
	private AdsManager adsManager;
	private CCManager ccManager;
	private AAManager aaManager;
	private QosManager qosManager;
	private DrmManager drmManager;

	private Plugin youboraPlugin;

	// Track the state of fragment to determine if its PAUSED or RESUMED
	private boolean isActivityPaused;
	/**
	 *  Register the broadcast reciever to track power on/power off functions triggered from device.
	 */
	private BroadcastReceiver mReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			// Call suspend when screen is turned off and mediaPlayer is not null and mediaplayer status is not suspended/Error/Released state.
			if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
				try {
					if (mediaPlayer != null &&
							lastKnownStatus != MediaPlayerStatus.ERROR &&
							lastKnownStatus != MediaPlayerStatus.RELEASED &&
							lastKnownStatus != MediaPlayerStatus.SUSPENDED) {
						PrimetimeReference.logger.i(LOG_TAG+"#screenOff:","Suspending mediaplayer as screen is turned off and mediaPlayer status is " + lastKnownStatus.toString());
						mediaPlayer.suspend();
					}
					else{
						PrimetimeReference.logger.i(LOG_TAG+"#screenOff:","Not suspending mediaplayer since mediaplayer status is " + lastKnownStatus.toString());
					}
				}catch(MediaPlayerException e){
					PrimetimeReference.logger.e(LOG_TAG+"#screenOff:","MediaPlayer Exception for suspend() call");
				}
			}
			else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
				// Call restore when screen is turned on and mediaplayer status is not suspended state.
				// This is for screen on condition when the device does not have a lock and turning on the screen immediately brings the fragment on foreground.
				try {

					if(lastKnownStatus == MediaPlayerStatus.SUSPENDED && !isActivityPaused) {
						PrimetimeReference.logger.i(LOG_TAG+"#screenOn:","Restoring mediaplayer since screen is turned on and mediaPlayer status is " + lastKnownStatus.toString());
						mediaPlayer.restore();
					}
					else{
						PrimetimeReference.logger.i(LOG_TAG+"#screenOn:","Not restoring mediaplayer since mediaPlayer status is " + lastKnownStatus.toString());
					}
				}catch(MediaPlayerException e){
					PrimetimeReference.logger.e(LOG_TAG+"#screenOn:","MediaPlayer Exception for restore() call");
				}
			}
		}
	};


	@Override
	public ViewGroup onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		playerFragmentView = (ViewGroup) inflater.inflate(
				R.layout.fragment_player, container, false);
		return playerFragmentView;
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		initialize(getActivity().getIntent());
		super.onActivityCreated(savedInstanceState);
	}

	/**
	 * Initialize the player fragment by setting up views, media player and
	 * feature managers
	 * 
	 * @param intent
	 *            the intent that contains the video item
	 */
	private void initialize(Intent intent) {
		videoItem = (VideoItem) intent.getExtras().getSerializable(
				"CONTENT_INFO");
		PrimetimeReference.logger.i(
				LOG_TAG + "#initialize",
				"Initializing the media player with item ["
						+ videoItem.getTitle() + "].");

		// Register screen receiver to see when the screen gets turned off and on.
		IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
		filter.addAction(Intent.ACTION_SCREEN_OFF);

		getActivity().getApplicationContext().registerReceiver(mReceiver, filter);
		// When video playback is started app is not in background.
		isActivityPaused = false;

		playerFrame = (FrameLayout) playerFragmentView.findViewById(R.id.playerFrame);
		ViewGroup controlBarView = (ViewGroup) playerFragmentView.findViewById(R.id.ControlBarItem);
		controlBar = new PlayerControlBar(getActivity(), controlBarView);
		playerClickableAdFragment = (PlayerClickableAdFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.playerClickInfo);
		spinner = (ProgressBar) playerFragmentView.findViewById(R.id.pbBufferingSpinner);
		audioProfile = (TextView) playerFragmentView.findViewById(R.id.audioTextView);
		audioProfile.setText(R.string.qosAudioProfile);
		audioProfile.setVisibility(View.INVISIBLE);
		_ccButton = (ImageButton) playerFragmentView.findViewById(R.id.sbPlayerControlCC);
		_rewindButton = (ImageButton) playerFragmentView.findViewById(R.id.playerRewind);
		((CustomFrameLayout) playerFrame).addOnSizeChangeListener(new OnSizeChangeListener() {

			@Override
			public void onSizeChanged() {
				// Scale player, since container size has changed.
				handler.post(new Runnable() {

					@Override
					public void run() {
						setPlayerViewSize(savedMovieWidth,
								savedMovieHeight);
					}
				});
			}
		});

		playerFrame.setOnTouchListener(userActionEventListener);
		playerFrame.setOnClickListener(userActionEventListener);

		createPlayer();
		
        if (videoItem.getDrmType() != null)
        {
            PrimetimeReference.logger.i(LOG_TAG + "#ProtectionData", "calling DRMManager.setProtectionData(): " + videoItem.getDrmType() + " :" + videoItem.getLicenseServerUrl());
            
            DRMManager.setProtectionData(videoItem.getDrmType(), videoItem.getLicenseServerUrl(), null);
            
        }
		
		setupViews();
		createManagers();
		prepareMedia();
	}

	/**
	 * Notify AdsManager to handle a clickable ad on click event
	 */
	public void notifyAdClick() {
		adsManager.adClick();
	}

	/**
	 * Create the PSDK media player and set up the views and listeners
	 * associated with it
	 */
	private void createPlayer() {
		PrimetimeReference.logger.i(LOG_TAG + "#createPlayer", "Creating player.");
		mediaPlayer = createMediaPlayer();
		initializeYoubora();
		installListeners();
	}

	private void initializeYoubora() {
		YouboraLog.setDebugLevel(YouboraLog.Level.VERBOSE);
		youboraPlugin = new Plugin(new Options(), new AdobeAdapter(mediaPlayer), getActivity());
		youboraPlugin.setAdsAdapter(new AdobeAdsAdapter(mediaPlayer));
	}

	/**
	 * Install clock event listener and user action event listener to monitor
	 * time progression and user actions.
	 */
	private void installListeners() {
		playbackClock = new Clock(PLAYBACK_CLOCK, 1000);
		playbackClockEventListener = new Clock.ClockEventListener() {
			@Override
			public void onTick(String name) {
				getActivity().runOnUiThread(new Runnable() {
					@Override
					public void run() {
						if (controlBar != null && mediaPlayer != null) {
							if (playbackManager.isPlaying()) {
								controlBar.setSeekabledRange(playbackManager
										.getLocalSeekRange());
								controlBar.setPosition(playbackManager
										.getLocalTime());
							}

							if (!playbackManager.isCompleted()) {
								if (playbackManager.isLive()) {
									controlBar.update();
								}
							}
						}

						qosManager.updateQosInformation();
					}
				});
			}
		};

		playbackClock.addClockEventListener(playbackClockEventListener);

		if (controlBar != null) {
			controlBar.addEventListener(controlBarEventListener);
		}
	}

	/**
	 * Create sub views for this fragment
	 */
	private void setupViews() {
		ViewGroup adsView = (ViewGroup) playerFragmentView
				.findViewById(R.id.adsOverlay);
		adOverlay = new AdOverlay(adsView);

		ImageButton ccView = (ImageButton) playerFragmentView
				.findViewById(R.id.sbPlayerControlCC);

		ccView.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View view) {
				displayClosedCaptioningDialog();
			}
		});

		ImageButton aaView = (ImageButton) playerFragmentView
				.findViewById(R.id.sbPlayerControlAA);
		aaView.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				displayAlternateAudioDialog();
			}
		});
		
		ImageButton trickPlayView = (ImageButton) playerFragmentView
				.findViewById(R.id.playerTrick);
		trickPlayView.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				displayTrickPlayDialog();
			}
		});
		
		
		// Setup pause on touch button
		btnTouchPause = (ImageButton) playerFragmentView.findViewById(R.id.btnTouchPause);
		btnTouchPause.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				controlBar.togglePlayPause();
			}
		});

	}

	/**
	 * Create feature managers for the media player
	 */
	private void createManagers() {
		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this.getActivity());
		ConfigProvider config = new ConfigProvider(sharedPreferences, videoItem);

		playbackManager = ManagerFactory.getPlaybackManager(config, mediaPlayer, getActivity().getApplicationContext());
		playbackManager.addEventListener(playbackManagerEventListener);
		playbackManager.setBillingManager(ManagerFactory.getBillingManager(config, getActivity().getApplicationContext()));
        playbackManager.setVAManager(ManagerFactory.getVAManager(config.isVAEnabled(), config, getActivity().getApplicationContext()));
		playbackManager.setViewGroup(playerFrame);

		qosManager = ManagerFactory.getQosManager(true, config, mediaPlayer);
		qosManager.addEventListener(qosManagerEventListener);
		qosManager.createQOSProvider(getActivity());

		adsManager = ManagerFactory.getAdsManager(true, config, mediaPlayer);
		adsManager.addEventListener(adsManagerEventListener);

		ccManager = ManagerFactory.getCCManager(true, config, mediaPlayer);
		aaManager = ManagerFactory.getAAManager(true, config, mediaPlayer);

		drmManager = ManagerFactory.getDrmManager(config, mediaPlayer);
		drmManager.addEventListener(drmEventListener);

	}

	/**
	 * Prepare media resource in the player through playback manager
	 */
	private void prepareMedia() {
		PrimetimeReference.logger.i(
				LOG_TAG + "#prepareMedia",
				"Local time before media resource is set: "
						+ playbackManager.getLocalTime() + ".");
		try {
			playbackManager.setupVideo(videoItem, adsManager);
		} catch (IllegalArgumentException e) {
			finishActivity(e.getMessage());
		} catch (IllegalStateException e) {
			finishActivity(e.getMessage());
		}
	}

	/*
	 * Request audio focus from the Android device.
	 */
	private void requestAudioFocus() {
		AudioManager am = (AudioManager) getActivity().getSystemService(
				Context.AUDIO_SERVICE);

		// Request audio focus for playback
		int result = am.requestAudioFocus(null,
		// Use the music stream.
				AudioManager.STREAM_MUSIC,
				// Request permanent focus.
				AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);

		if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
			PrimetimeReference.logger.i(LOG_TAG + "#requestAudioFocus()",
					"Gained audio focus.");
		}
	}

	/*
	 * Abandon audio focus from the Android device.
	 */
	private void abandonAudioFocus() {
		AudioManager am = (AudioManager) getActivity().getSystemService(
				Context.AUDIO_SERVICE);
		am.abandonAudioFocus(null);
		PrimetimeReference.logger.i(LOG_TAG + "#abandonAudioFocus()",
				"Abandoned audio focus.");
	}

	/**
	 * Create a PSDK media player instance from the current context
	 * 
	 * @return a PSDK media player instance
	 */
	private MediaPlayer createMediaPlayer() {
		MediaPlayer mediaPlayer = new MediaPlayer(getActivity().getApplicationContext());
		return mediaPlayer;
	}

	// Save/Restore state for the current fragment

	/**
	 * Called from main activity.
	 */
	protected void onFragmentRestoreInstanceState(Bundle savedInstanceState) {

		PrimetimeReference.logger.i(LOG_TAG + "#onRestoreInstanceState",
				"Restoring activity state.");

		lastKnownTime = savedInstanceState.getLong(CURRENT_PLAYER_POSITION, -1);
		PrimetimeReference.logger.i(LOG_TAG + "#onRestoreInstanceState",
				"Restored saved current player time: " + lastKnownTime);

		savedPlayerState = (MediaPlayerStatus) savedInstanceState
				.getSerializable(CURRENT_PLAYER_STATE);
		PrimetimeReference.logger.d(LOG_TAG + "#onRestoreInstanceState",
				"Retrieved saved player state: " + savedPlayerState);

		isRestored = true;
	}

	/**
	 * Called from main activity.
	 */
	protected void onFragmentSaveInstanceState(Bundle outState) {
		PrimetimeReference.logger.i(LOG_TAG + "#onSaveInstanceState",
				"Saving activity state.");

		outState.putLong(CURRENT_PLAYER_POSITION, lastKnownTime);
		PrimetimeReference.logger.i(LOG_TAG + "#onSaveInstanceState",
				"Current player time [" + lastKnownTime + "] saved.");

		outState.putSerializable(CURRENT_PLAYER_STATE, savedPlayerState);
		PrimetimeReference.logger.i(LOG_TAG + "#onSaveInstanceState",
				"Current player state [" + savedPlayerState + "] saved.");
	}

	// Fragment life cycle functions implementation

	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		// Ignore orientation/keyboard change.
		super.onConfigurationChanged(newConfig);
	}

	/**
	 * Resume player fragment by requesting audio focus and (re)starting
	 * playback clocking
	 */
	@Override
	public void onResume() {
		super.onResume();
		/**
		 *  When the device has a lock/pin the on resume will be called only after the device is unlocked.
		 *  Screen on does not call the onResume() method so we need to handle restore here explicitly.
		 */
		if(lastKnownStatus == MediaPlayerStatus.SUSPENDED && isActivityPaused){
			try {
				PrimetimeReference.logger.i(LOG_TAG + "#onResume",
						"Player restored as activity operations are resumed");
				mediaPlayer.restore();
			}
			catch(MediaPlayerException e){
				PrimetimeReference.logger.i(LOG_TAG + "#onResume", "Exception occured while restoring mediaPlayer");
			}
		}
		// Set the fragment paused status to false when app comes in foreground.
		isActivityPaused = false;
		requestAudioFocus();
		updateClosedCaptionsVisilibty();
		playbackClock.start();
	}

	/**
	 * Pause player fragment by pausing the playback, stopping the player clock,
	 * memorizing the current playback status and abandon audio focus
	 */
	@Override
	public void onPause() {
		PrimetimeReference.logger.i(LOG_TAG + "#onPause", "Player activity paused.");
		controlBar.hide();
		playbackClock.stop();

		if (mediaPlayer != null) {
			savedPlayerState = playbackManager.getStatus();
			lastKnownTime = playbackManager.getCurrentTime();

			if (playbackManager.isPlaying()) {
				controlBar.pressPause();
				lastKnownStatus = savedPlayerState = playbackManager.getStatus();
			}

        }
		// Set the fragment paused status to true when app goes in background.
		isActivityPaused = true;
		abandonAudioFocus();
		super.onPause();
	}
	private void updateClosedCaptionsVisilibty() {
		if (mediaPlayer != null && lastKnownStatus != MediaPlayerStatus.RELEASED)
			mediaPlayer.setCCVisibility(getClosedCaptionVisibilityPref());     
	}
	private MediaPlayer.Visibility getClosedCaptionVisibilityPref() {
		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());

		boolean closedCaptionVisibilityPreference = sharedPreferences.getBoolean(CCManager.SETTINGS_CC_VISIBILITY, CCManager.DEFAULT_CC_VISIBILITY);
		return closedCaptionVisibilityPreference ? MediaPlayer.Visibility.VISIBLE : MediaPlayer.Visibility.INVISIBLE;
	}

	/**
	 * Destroy player fragment and the media player
	 */
	@Override
	public void onDestroy() {
		PrimetimeReference.logger.i(LOG_TAG + "#onDestroy()", "Releasing resources.");
		super.onDestroy();

		 if (mReceiver != null) {
            try {
                getActivity().getApplicationContext().unregisterReceiver(mReceiver);
                mReceiver = null;
            }
            catch (IllegalArgumentException e) {
                // receiver already unregistered.
            }
        }
		destroyPlayer();
	}

	// Private functions for cleaning up resources
	/**
	 * Close player activity and display the error message
	 * 
	 * @param message
	 *            the error message
	 */
	private void finishActivity(String message) {
		Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
		getActivity().finish();
	}

	/**
	 * Destroy the media player object. This includes removing all listeners,
	 * destroying QOS provider if used, and removing all views the media player
	 * object is attached to
	 */
	private void destroyPlayer() {
		uninstallListeners();
		qosManager.destroyQOSProvider();

		playerFrame.removeAllViews();

		if (mediaPlayer != null) {
			destroyMediaPlayer(mediaPlayer);
			mediaPlayer = null;
		}
		lastKnownStatus = MediaPlayerStatus.RELEASED;
	}

	/**
	 * Uninstall all listeners the player fragment listens to
	 * 
	 */
	private void uninstallListeners() {
		if (controlBar != null) {
			controlBar.removeEventListener(controlBarEventListener);
			controlBar = null;
		}

		if (playbackClock != null) {
			playbackClock.removeClockEventListener(playbackClockEventListener);
			playbackClock = null;
			playbackClockEventListener = null;
		}
	}

	/**
	 * Release the media player
	 * 
	 * @param mediaPlayer
	 *            the media player object to be destroyed
	 */
	private void destroyMediaPlayer(MediaPlayer mediaPlayer) {
		destroyManagers();
		mediaPlayer.release();
	}

	/**
	 * Destroy all feature managers
	 */
	private void destroyManagers() {
		playbackManager.destroy();
		adsManager.destroy();
		ccManager.destroy();
		aaManager.destroy();
		drmManager.destroy();
		qosManager.destroy();
	}

	// UI manipulation

	/**
	 * Specifies whether the user can perform a seek on the seek bar anymore.
	 * 
	 * @param enabled
	 */
	private void setControlBarEnabled(boolean enabled) {
		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
		boolean canSeekInAd = sharedPreferences.getBoolean(
				AdsManagerOn.SETTINGS_SEEK_IN_AD,
				AdsManagerOn.DEFAULT_SEEK_IN_AD);
		if (enabled) {
			// Enable the control bar thumb.
			controlBar.enable();
			_rewindButton.setEnabled(true);
			
		} else {
			// Disable the control bar thumb, only if the user is restricted to
			// perform any further seeks.
			if (canSeekInAd == false){
				controlBar.disable();
				_rewindButton.setEnabled(false);
			}
		}
	}

	/**
	 * Specifies whether the user can click on CC while ad is in progress.
	 * 
	 * @param enabled
	 */
	private void setCCEnabled(boolean enabled) {
		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
		boolean canSeekInAd = sharedPreferences.getBoolean(
				AdsManagerOn.SETTINGS_SEEK_IN_AD,
				AdsManagerOn.DEFAULT_SEEK_IN_AD);
		if (enabled) {
			// Enable the control bar thumb.
			_ccButton.setEnabled(true);
		} else {
			// Disable the control bar thumb, only if the user is restricted to
			// perform any further seeks.
			if (!canSeekInAd) {
				_ccButton.setEnabled(false);
			}
		}
	}

	/**
	 * Show a given message in toast with short duration
	 * 
	 * @param message
	 *            the message to be shown in toast
	 */
	private void showToast(String message) {
		if (!PreferencesUtils.getShowToastWarningsPref(getActivity())) {
			return;
		}

		Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
	}

	/**
	 * Show buffering spinner to indicate the buffering process
	 */
	private void showBufferingSpinner() {
		handler.post(new Runnable() {
			@Override
			public void run() {
				spinner.setVisibility(View.VISIBLE);
			}
		});
	}

	/**
	 * Hide buffering spinner to indicate buffering is over
	 */
	private void hideBufferingSpinner() {
		handler.post(new Runnable() {
			@Override
			public void run() {
				spinner.setVisibility(View.INVISIBLE);
			}
		});
	}

	/**
	 * Show play button again by simulating a user pressing the stop button. We do
	 * this because the stop event can be driven by the playback reaches its
	 * end.
	 */
	private void showPlayButton() {
		handler.post(new Runnable() {

			@Override
			public void run() {
				controlBar.pressStop();
			}
		});
	}

	/**
	 * Display playback and seekable range. Move the play head to the current
	 * time.
	 */
	private void displayRanges() {
		controlBar.setSeekabledRange(playbackManager.getLocalSeekRange());
		controlBar.setPosition(playbackManager.getLocalTime());
		controlBar.setStreamType(playbackManager.isLive());
	}

	/**
	 * Set the player view size with givent width and height
	 * 
	 * @param savedMovieWidth2
	 *            the width of the player view to be set to
	 * @param savedMovieHeight2
	 *            the height of the player view to be set to
	 */
	private void setPlayerViewSize(float savedMovieWidth2, float savedMovieHeight2) {
		if (mediaPlayer == null || mediaPlayer.getView() == null) {
			PrimetimeReference.logger.w(LOG_TAG + "#setPlayerViewSize",
					"Unable to find player view.");
			return;
		}
		PrimetimeReference.logger.i(LOG_TAG + "#setPlayerViewSize", "Original movie size: "
				+ savedMovieWidth2 + "x" + savedMovieHeight2);

		FrameLayout layout = (FrameLayout) playerFragmentView.findViewById(R.id.playerFrame);
		int layoutWidth = layout.getWidth();
		int layoutHeight = layout.getHeight();
		float screenAspectRatio = (float) layoutWidth / layoutHeight;
		if (savedMovieWidth2 == 0 || savedMovieHeight2 == 0) {
			// If movie size is not available, fill the screen.
			savedMovieWidth2 = layoutWidth;
			savedMovieHeight2 = layoutHeight;
		}
		float movieAspectRatio = savedMovieWidth2 / savedMovieHeight2;
		int width, height;

		if (movieAspectRatio <= screenAspectRatio) {
			// Resize to fill height.
			width = (int) (layoutHeight * movieAspectRatio);
			height = layoutHeight;
		} else {
			// Resize to fill width.
			width = layoutWidth;
			height = (int) (layoutWidth * (1 / movieAspectRatio));
		}
		PrimetimeReference.logger.i(LOG_TAG + "#setPlayerViewSize",
				"Setting player view size to: " + width + "x" + height);
		mediaPlayer.getView().setLayoutParams(
				new FrameLayout.LayoutParams(width, height,
						Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL));
	}

	/**
	 * Run the last ignored command if there is any. This is used when users
	 * attempt to press the play or pause button too early before the player is
	 * ready.
	 */
	private synchronized void runLastIgnoredCommand() {
		if (lastIgnoredEvent == null) {
			return;
		}

		// Perform last ignored event.
		PrimetimeReference.logger.i(LOG_TAG + "#runLastIgnoredCommand()",
				"Performing last ignored event: "
						+ lastIgnoredEvent.getEventType().getName());
		switch (lastIgnoredEvent.getEventType()) {
		case PAUSE:
			if (playbackManager.isPlaying()) {
				controlBar.pressPause();
			}
			break;
		case PLAY:
			controlBar.pressPlay();
			break;
		case SEEK:
			long position = (Long) lastIgnoredEvent.getEventInfo();
			controlBar.seek(position);
			break;
		case SEEK_CLP:
			break;
		case STOP:
			break;
		}

		lastIgnoredEvent = null;
	}

	/**
	 * Displays a chooser dialog, allowing the user to select the desired closed
	 * captions.
	 */
	private void displayClosedCaptioningDialog() {
		PrimetimeReference.logger.i(LOG_TAG + "#selectClosedCaptions",
				"Displaying closed captions chooser dialog.");
		final List<String> items = ccManager
				.getClosedCaptionTracks(getActivity()
						.getString(R.string.active));

		// Adding the option of having "none" for user convenience

		items.add(0, "None");

		final String[] charItems = items.toArray(new String[items.size()]);

		final AlertDialog.Builder ab = new AlertDialog.Builder(getActivity());
		ab.setTitle(R.string.PlayerControlCCDialogTitle);
		ab.setSingleChoiceItems(charItems,
				ccManager.getSelectedClosedCaptionsIndex() + 1,
				new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int index) {

						ImageButton ccButtonView = (ImageButton) playerFragmentView
								.findViewById(R.id.sbPlayerControlCC);
						// Select the new closed captioning track.
						ccManager.selectClosedCaptionTrack(index - 1);
						// Dismiss dialog.

						if (index != 0) {

							ccButtonView
									.setImageResource(R.drawable.closecaptionon);

						}

						else {

							ccButtonView
									.setImageResource(R.drawable.closecaptionoff);

						}
						dialog.cancel();
					}
				}).setNegativeButton(R.string.PlayerControlCCDialogCancel,
				new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int whichButton) {
						// Just cancel the dialog.
					}
				});
		ab.show();
	}

	//Set visibility of pause button
	
	private void setPlayPauseButtonVisibility(boolean visible) {
	    if (btnTouchPause != null) {
	    	btnTouchPause.setVisibility(visible ? View.VISIBLE : View.GONE);
	    }
		 }
	
	/**
	 * Displays a chooser dialog, allowing the user to select the desired
	 * alternate audio track.
	 */
	private void displayAlternateAudioDialog() {
		PrimetimeReference.logger.i(LOG_TAG + "#selectAlternateAudio", "Displaying alternate audio chooser dialog.");

		final int selectedAlternateAudio = aaManager.getSelectedAudioTrackIndex();

		if (selectedAlternateAudio != AAManagerOn.INVALID_AUDIO_TRACK)
		{
			final String items[] = aaManager.getAudioTracks();
			new AlertDialog.Builder(getActivity())
					.setTitle(R.string.PlayerControlAADialogTitle)
					.setSingleChoiceItems(items, selectedAlternateAudio,
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog,
										int whichButton) {
									boolean result = aaManager
											.selectAlternateAudioTrack(whichButton);
									if (result) {
										PrimetimeReference.logger
												.i(LOG_TAG
														+ "#selectAlternateAudio",
														"Audio track selection successful");
									} else {
										PrimetimeReference.logger.i(LOG_TAG
												+ "#selectAlternateAudio",
												"Audio track selection failed");
									}
									// Dismiss dialog.
									dialog.cancel();
								}
							})
					.setNegativeButton(R.string.PlayerControlCCDialogCancel,
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog,
										int whichButton) {
									// Just cancel the dialog.
								}
							}).show();

		} else {
			PrimetimeReference.logger.i(LOG_TAG + "#selectAlternateAudioFailed",
					"Unable to detect the currently selected audio track.");
			Toast.makeText(getActivity(),
					"Unable to detect the currently selected audio track",
					Toast.LENGTH_SHORT).show();
		}
	}
	
	/**
	 * Displays a chooser dialog, allowing the user to select the desired
	 * play rate.
	 */
	private void displayTrickPlayDialog() {
		PrimetimeReference.logger.i(LOG_TAG + "#selectPlayRate", "Displaying play rate chooser dialog.");

		if(!playbackManager.isTrickPlaySupported())
		{
			PrimetimeReference.logger.i(LOG_TAG + "#selectPlayRateFailed", "Trick play not supported for this item.");
			Toast.makeText(getActivity(), "Trick play not supported for this item.", Toast.LENGTH_SHORT).show();
		}
		else
		{
			final float currentRate = playbackManager.getPlayRate();
			final String[] items = playbackManager.getAvailablePlaybackRates();
			new AlertDialog.Builder(getActivity())
					.setTitle(R.string.PlayerControlTPDialogTitle)
					.setSingleChoiceItems(items, Arrays.asList(items).indexOf(String.valueOf(currentRate)),
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog,
										int whichButton) {
									try {
										playbackManager.setPlayRate(Float.valueOf(items[whichButton]));
									}
									catch (MediaPlayerException e) {
										PrimetimeReference.logger.e(LOG_TAG+"#selectPlayRate","MediaPlayer Exception for setRate() call");
									}
									setPlayPauseButtonVisibility(false); // if previously paused, remove image
									if (playbackManager.getPlayRate() != Float.valueOf(items[whichButton])) {
										PrimetimeReference.logger.i(LOG_TAG + "#selectPlayRate", "Play rate selection successful");
									} else {
										PrimetimeReference.logger.i(LOG_TAG + "#selectPlayRate", "Play rate selection failed");
									}
									// Dismiss dialog.
									dialog.cancel();
								}
							})
					.setNegativeButton(R.string.PlayerControlCCDialogCancel,
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog, int whichButton) {
									// Just cancel the dialog.
								}
							}).show();

		}
	}	
	

	// Setup listeners

	private final PlayerControlBar.ControlBarEventListener controlBarEventListener = new PlayerControlBar.ControlBarEventListener() {
		@Override
		public void handleEvent(PlayerControlBar.ControlBarEvent controlBarEvent) {
			PrimetimeReference.logger
					.i(LOG_TAG
							+ "::PlayerControlBar.ControlBarEventListener#handleEvent()",
							"Player control bar event: "
									+ controlBarEvent.getEventType().getName());
			if (!playbackManager.isPrepared()) {
				// The player is not prepared. We will not run commands on it.
				PrimetimeReference.logger
						.i(LOG_TAG
								+ "::PlayerControlBar.ControlBarEventListener#handleEvent()",
								"Player is not prepapred. Ignoring and saving last command: "
										+ controlBarEvent.getEventType()
												.getName());
				lastIgnoredEvent = controlBarEvent;
				return;
			}

			switch (controlBarEvent.getEventType()) {
			case PLAY:
				playbackManager.play();
				if (!playbackManager.isCustomAdViewActive()) {
					setPlayPauseButtonVisibility(false);
				}
				break;

			case PAUSE:
				handler.post(new Runnable() {

					@Override
					public void run() {
						playbackManager.pause();
						if (!playbackManager.isCustomAdViewActive()) {
							setPlayPauseButtonVisibility(true);
						}
					}
				});
				break;

			case SEEK:
				long localSeekPosition = (Long) controlBarEvent.getEventInfo();
				playbackManager.seekToLocal(localSeekPosition);
				if (playbackManager.isCompleted()) 
				{
					controlBar.setStatusToPlay();
				}
				break;

			case SEEK_CLP:
				//playbackManager.seek(MediaPlayer.LIVE_POINT);
				setPlayPauseButtonVisibility(false);
				break;

			case STOP:
				setPlayPauseButtonVisibility(false);
				break;

			default:
				PrimetimeReference.logger.w(LOG_TAG + "#handleEvent()", "Unknown event: "
						+ controlBarEvent.getEventType().getName());
			}
		}
	};

	private interface UserActionEventListener extends View.OnTouchListener,
			View.OnClickListener {
	}

	private final UserActionEventListener userActionEventListener = new UserActionEventListener() {
		@Override
		public boolean onTouch(View v, MotionEvent event) {
			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				break;

			case MotionEvent.ACTION_UP:
				float ratio = event.getY() / v.getHeight();
				PrimetimeReference.logger.i(LOG_TAG + "::UserActionEventListener#onTouch",
						"Handling onTouch user action: ratio=" + ratio + ".");

				// Check if user clicked above the control bar
				if (ratio > ACTION_BAR_RATIO && ratio < CONTROL_BAR_RATIO) {
					controlBar.togglePlayPause();
				}

				// Show the action bar and the control bar
				controlBar.show();
				break;
			}

			return false;
		}

		@Override
		public void onClick(View v) {
		}
	};

	/**
	 * Set up feature manager listeners
	 */
	private final QosManager.QosManagerEventListener qosManagerEventListener = new QosManager.QosManagerEventListener() {
		@Override
		public void onQosUpdate(ArrayList<QosManager.QosItem> qosItems) {
			ViewGroup qosView = (ViewGroup) playerFragmentView
					.findViewById(R.id.qosTopLayout);
			for (QosManager.QosItem item : qosItems) {
				// Check if item view is already inflated.
				View tv = qosView.findViewById(item.getId());
				if (tv == null) {
					// Inflate the text view.
					tv = LayoutInflater.from(getActivity())
							.inflate(R.layout.fragment_player_qos, null)
							.findViewById(R.id.qosTextView);
					tv.setId(item.getId());
				}
				// Set the new text value.
				
				((TextView) tv)
						.setText(item.getName() + ": " + item.getValue());

				if (tv.getParent() != null) {
					((ViewGroup) tv.getParent()).removeView(tv);
				}
				if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
					qosView.addView(tv, new ViewGroup.LayoutParams(
							LayoutParams.WRAP_CONTENT,
							LayoutParams.WRAP_CONTENT));
				} else {
					qosView.addView(tv, new ViewGroup.LayoutParams(
							LinearLayout.LayoutParams.WRAP_CONTENT,
							LinearLayout.LayoutParams.WRAP_CONTENT));
				}
			}
			qosView.setVisibility(View.VISIBLE);
		}
	};

	private final PlaybackManager.PlaybackManagerEventListener playbackManagerEventListener = new PlaybackManagerEventListener() {

		/**
		 * Show buffering spinner when buffering starts
		 */
		@Override
		public void onBufferStart() {
			// don't display buffering spinner if custom ad is active
			// this may occur when seeking past an ad break containing a custom ad.
			if (!playbackManager.isCustomAdViewActive()) {
				showBufferingSpinner();
			}
		}

		/**
		 * Hide buffering spinner when buffering completes
		 */
		@Override
		public void onBufferComplete() {
			hideBufferingSpinner();
		}

		/**
		 * Move the playhead to the post seek position after seeking completes
		 * If the playback is over, show a replay button. If users paused the
		 * video before seeking, pause the video again.
		 */
		@Override
		public void onSeekCompleted(long localAdjustedTime) {
			final long adjustedTime = localAdjustedTime;
			handler.post(new Runnable() {

				@Override
				public void run() {
					controlBar.setPosition(adjustedTime);
				}
			});

			if (localAdjustedTime == playbackManager.getLocalSeekRangeEnd()
					&& playbackManager.isCompleted()) {
				showPlayButton();
			}
		}

		/**
		 * Run last ignored command if the users tried to perform
		 * play/pause/seek operation before player was prepared. Start the
		 * playback if autoplay is set to true. If the player was restored from
		 * a crash, seek to the position where the player was crashed. Hide the
		 * CC or AA button if closed captioning or late binding audio are not
		 * available.
		 */
		@Override
		public void onPrepared() {

			hideBufferingSpinner();
			controlBar.show();
			displayRanges();

			runLastIgnoredCommand();
			
			//Set Closed Captions visibility.
			mediaPlayer.setCCVisibility(getClosedCaptionVisibilityPref());

			boolean playbackShouldStart = !isRestored;
			if (isRestored) {
				PrimetimeReference.logger
				.d(LOG_TAG
						+ "MediaPlayer.PlayerStateEventListener#onStateChanged",
						"Initial seek to location: "
								+ lastKnownTime);
				if (lastKnownTime >= 0) {
					playbackManager.seek(lastKnownTime);
				}

				playbackShouldStart = (savedPlayerState == MediaPlayerStatus.PLAYING);
			}

			if (playbackShouldStart) {
				controlBar.pressPlay();
			}			

		}

		/**
		 * Update control bar when the playback timeline updates
		 */
		@Override
		public void onUpdate(TimeRange localSeekRange, Timeline<?> timeline) {
			controlBar.setSeekabledRange(localSeekRange);
			controlBar.setTimeline(timeline);
		}

		@Override
		public void onPlaying() {
			if (playbackClock != null && lastKnownStatus == MediaPlayerStatus.COMPLETE) {
				playbackClock.start();
			}
		}

		@Override
		public void onRateChange(float rate) {
			if (rate == 1)
			{
				// playback has already resumed so update display to 'play'
				controlBar.setStatusToPlay();
			}
			else if (rate == 0)
			{
				// Don't do anything if playback is paused
			}
			else
			{
				// display 'play' button such that clicking it causes play rate of 1 instead of pausing
				controlBar.setStatusToPause();
			}
		}

		/**
		 * When the playback completes, goes back to the catalog screen if users
		 * chooses to do this from the setting.
		 */
		@Override
		public void onComplete() {
			if (PreferencesUtils
					.shouldReturnToCatalogOnPlaybackComplete(getActivity())) {
				getActivity().finish();
			} else {
                lastKnownStatus = MediaPlayerStatus.COMPLETE;

				// Show the replay button.
				showPlayButton();
				// Cancel clock thread.
				playbackClock.stop();
				// Update the position time.
				controlBar.setPosition(playbackManager.getLocalSeekRangeEnd());
				// Update QoS manually, since we've stopped the timer.
				qosManager.updateQosInformation();
			}
		}

		/**
		 * Update player view when the player receives a new width and height
		 */
		@Override
		public void onDimensionsChange(float height, float width) {
			if (width != savedMovieWidth || height != savedMovieHeight) {
				// Should resize the player.
				savedMovieWidth = width;
				savedMovieHeight = height;
				setPlayerViewSize(savedMovieWidth, savedMovieHeight);
			}
		}

		/**
		 * Update the UI based on playback state changes
		 */
		@Override
		public void onStateChange(MediaPlayerStatus status) {
			PrimetimeReference.logger
					.i(LOG_TAG
							+ "::MediaPlayer.PlayerStateEventListener#onStateChanged()",
							"Player state changed to [" + status + "].");

			if (lastKnownStatus == MediaPlayerStatus.COMPLETE) {
				// Start the clock thread.
				playbackClock.start();
			}

			lastKnownStatus = status;

			switch (lastKnownStatus) {
			case PREPARING:
				showBufferingSpinner();
				controlBar.hide();
				break;

			default:
				// do nothing
			}
		}

		/**
		 * Destroy the player activity when the player encounters an error. This
		 * is an irrecoverable error from a playback session.
		 * @param error
		 */
		@Override
		public void onError(PSDKErrorCode error) {
			finishActivity(error.toString());
		}

        @Override
        public void onNativeError(int errorCode, int subErrorCode, String drmErrorString)
        {
            String message = "Native error: " + Integer.toString(errorCode) + ", "+ Integer.toString(subErrorCode);
            if (drmErrorString != null)
                message += " error string: " + drmErrorString;

            finishActivity(message);
        }

		@Override
		public void onSeeking() {
		}
	};

	private final AdsManager.AdsManagerEventListener adsManagerEventListener = new AdsManager.AdsManagerEventListener() {

		/**
		 * Display the ad overlay and disable control bar when the ad break
		 * starts
		 */
		@Override
		public void onAdBreakStarted(AdBreak adBreak) {
			adOverlay.startAdBreak(adBreak);
			setControlBarEnabled(false);
			setCCEnabled(false);
			
		}

		/**
		 * Hide the ad overlay and re-enable the control bar when the ad berak
		 * is over
		 */
		@Override
		public void onAdBreakCompleted(AdBreak adBreak) {
			adOverlay.stopAdBreak(adBreak);
			setControlBarEnabled(true);
			setCCEnabled(true);
		}

		@Override
		public void onAdBreakSkipped(AdBreak adBreak) {

		}

		/**
		 * Show ad break progress when each ad creative starts If this is a
		 * clickable ad, show the clickable ad fragment
		 */
		@Override
		public void onAdStarted(AdBreak adBreak, Ad ad) {
			PrimetimeReference.logger.i(LOG_TAG + "#onAdStarted","NetworkAdInfo details");
			DisplayNetworkAdInfo(ad.getPrimaryAsset().getNetworkAdInfo());

			adOverlay.startAd(adBreak, ad);
			if (adsManager.isClickableAdsEnabled() && ad.isClickable()) {
				playerClickableAdFragment.show();
			}
		}

		/**
		 * Hide ad break progress when each ad ends Hide the clickable ad
		 * fragment
		 */
		@Override
		public void onAdCompleted(AdBreak adBreak, Ad ad) {
			adOverlay.stopAd(adBreak, ad);
			playerClickableAdFragment.hide();
		}

		@Override
		public void onAdProgress(AdBreak adBreak, Ad ad, double percentage) {
			if (adOverlay != null) {
				adOverlay.notifyAdProgress(adBreak, ad, percentage);
			}
		}

		/**
		 * Open an external browser to redirect to the clickable ad URL
		 */
		@Override
		public void onAdClick(String url) {
			Uri uri = Uri.parse(url);
			Intent intent = new Intent(ACTION_VIEW, uri);
			try {
				startActivity(intent);
			} catch (Exception e) {
				PrimetimeReference.logger.w(LOG_TAG
								+ "::MediaPlayer.AdsManagerEventListener#handleAdClick()",
						"An error occurred while opening the native browser");
			}
		}

		/**
		 * Update control bar with new timeline markers
		 */
		@Override
		public void onTimelineUpdated(Timeline<?> timeline) {
			controlBar.setTimeline(timeline);
		}
	};

	private final DrmManager.DrmManagerEventListener drmEventListener = new DrmManager.DrmManagerEventListener() {


		@Override
		public void onError(long majorCode, long minorCode, String error) {
			try {
				DRMErrorDialog dialog = new DRMErrorDialog(getActivity());
				Bundle args = new Bundle();

				if (error.isEmpty()) {
					// if custom message is not given

					String message = DrmManager.buildMessage(majorCode,
							minorCode, getActivity().getPackageName(),
							getActivity().getResources());
					args.putString("message", message);
				} else {
					// if custom message is given
					args.putString("message", error);
				}

				dialog.setArguments(args);
				dialog.show();

			} catch (Exception e) {
				PrimetimeReference.logger.d(LOG_TAG, e.getMessage());
			}
		}


		@Override
		public void onRetry() {
			PrimetimeReference.logger.e(LOG_TAG, "Reset player.");
			mediaPlayer.reset();
			prepareMedia();
		}

	};

	private void DisplayNetworkAdInfo(NetworkAdInfo networkAdInfo) {
		if( networkAdInfo == null ) {
			PrimetimeReference.logger.i(LOG_TAG + "#DisplayNetworkAdInfo","NetworkAdInfo is null");
		}
		else {
			PrimetimeReference.logger.i(LOG_TAG + "#DisplayNetworkAdInfo","NetworkAdInfo.adId = " + networkAdInfo.getAdId());
			PrimetimeReference.logger.i(LOG_TAG + "#DisplayNetworkAdInfo","NetworkAdInfo.getAdSystem = " + networkAdInfo.getAdSystem());
			PrimetimeReference.logger.i(LOG_TAG + "#DisplayNetworkAdInfo","NetworkAdInfo.getAdExtension = " + networkAdInfo.getExtensions());
			DisplayNetworkAdInfo(networkAdInfo.getChildAdInfo());
		}
	}
}