package com.viaccessorca.voplayerdemo.activities;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
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.NameNotFoundException;
import android.graphics.Color;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.cast.framework.CastButtonFactory;
import com.google.android.gms.cast.framework.CastContext;
import com.google.android.gms.cast.framework.Session;
import com.google.android.gms.cast.framework.SessionManager;
import com.google.android.gms.cast.framework.SessionManagerListener;
import com.npaw.youbora.lib6.utils.youboraconfigutils.YouboraConfigManager;
import com.viaccessorca.common.VOUtils;
import com.viaccessorca.drm.VOVerimatrixAgent;
import com.viaccessorca.exceptions.VOException;
import com.viaccessorca.exceptions.VOMissingPermissionException;
import com.viaccessorca.voplayer.VOPlayer;
import com.viaccessorca.voplayer.VOSystemInfo;
import com.viaccessorca.voplayer.VOSystemInfoRetriever;
import com.viaccessorca.voplayerdemo.Constants;
import com.viaccessorca.voplayerdemo.R;
import com.viaccessorca.voplayerdemo.Utils;
import com.viaccessorca.voplayerdemo.adapters.MediaListAdapter;
import com.viaccessorca.voplayerdemo.adapters.MediaListAdapter.onResumeButtonListener;
import com.viaccessorca.voplayerdemo.database.DatabaseInfo;
import com.viaccessorca.voplayerdemo.database.MediaMetaInfoDB;
import com.viaccessorca.voplayerdemo.downloader.DownloadManager;
import com.viaccessorca.voplayerdemo.downloader.DownloadService;
import com.viaccessorca.voplayerdemo.downloader.DownloaderWrapper;
import com.viaccessorca.voplayerdemo.downloader.DownloaderWrapper.OnErrorListener;
import com.viaccessorca.voplayerdemo.downloader.DownloaderWrapper.OnInfoListener;
import com.viaccessorca.voplayerdemo.downloader.DownloaderWrapper.OnPreparedListener;
import com.viaccessorca.voplayerdemo.downloader.DownloaderWrapper.State;
import com.viaccessorca.voplayerdemo.mediamgt.LocalMediasFinder;
import com.viaccessorca.voplayerdemo.mediamgt.MediaCustomListMapper;
import com.viaccessorca.voplayerdemo.mediamgt.MediaItem;
import com.viaccessorca.voplayerdemo.mediamgt.MediaItem.MediaType;
import com.viaccessorca.voplayerdemo.mediamgt.MediaTypeMapper;
import com.viaccessorca.voplayerdemo.mediamgt.MediasMapperInterface;
import com.viaccessorca.voplayerdemo.mediamgt.StreamingMediaItem;

import java.io.File;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;


//AGAMA_ANALYTICS: import com.viaccessorca.voplayerdemo.analytics.LVAgamaPlugin;

public class MediaListActivity extends AppCompatActivity implements
        OnChildClickListener, onResumeButtonListener, OnPreparedListener,
        OnInfoListener, OnErrorListener {

    private static final String TAG = "MediaListActivity";

    private ExpandableListView mediaListView;
    private MediaListAdapter listAdapter = null;

    private ArrayList<String> mediaGroups;
    private ArrayList<List<MediaItem>> mediaItems;

    private int targetedGroup = -1;
    private int targetedPosition = -1;

    private DownloadManager DLMgr;
    private Intent DownloaderServiceIntent;

    private static final int CONTEXT_MENU_ACTION_INFO = 1;
    private static final int CONTEXT_MENU_ACTION_DELETE = 2;
    private static final int CONTEXT_MENU_ACTION_START_DL = 3;
    private static final int CONTEXT_MENU_ACTION_PAUSE_DL = 4;
    private static final int CONTEXT_MENU_ACTION_RESUME_DL = 5;
    private static final int CONTEXT_MENU_ACTION_DELETE_DL = 6;
    private static final int CONTEXT_MENU_ACTION_GET_KEY_EXPIRATION = 7;
    private static final int CONTEXT_MENU_ACTION_RENEW_KEY = 8;
    private static final int CONTEXT_MENU_ACTION_DRM_MANAGER = 9;
    private static final int CONTEXT_MENU_ACTION_CLIENT_VMX = 10;

    private static final int REMOVE_ITEM_DIALOG = 1;
    private static final int ABOUT_DIALOG = 2;

    private static final int PROCESSING_DL_DIALOG = 4;
    private static final int RIGHT_ACQUISITION_DIALOG = 5;

    private enum OngoingDLActionType {
        NONE, RESUME, DELETE, RENEW_KEY, GET_EXPIRATION
    }

    private OngoingDLActionType ongoingDownloadAction = OngoingDLActionType.NONE;

    private int resumeDlBitrate = 0;
    private ProgressDialog processingDialog = null;

    //verimatrix static client
    private static boolean bClientVerimatrixInitialized = false;
    private String mStaticClientBootAddress = null;
    private String mStaticClientCompanyName = null;
    private VOPlayer mPlayerForVmxInit = null;

    /* GoogleCast custom receiver */
    private SessionManager mSessionManager;
    private final SessionManagerListener mSessionManagerListener = new SessionManagerListenerImpl();
    private class SessionManagerListenerImpl implements SessionManagerListener {
        @Override
        public void onSessionStarting(Session session) {
            Toast.makeText(getApplicationContext(), "ChromeCast Session starting", Toast.LENGTH_SHORT).show();
        }
        @Override
        public void onSessionStarted(Session session, String sessionId) {
            Toast.makeText(getApplicationContext(), "ChromeCast Session started", Toast.LENGTH_SHORT).show();
        }
        @Override
        public void onSessionStartFailed(Session session, int error) {
            Toast.makeText(getApplicationContext(), "ChromeCast Session start failed ! Error = " + error, Toast.LENGTH_SHORT).show();
        }
        @Override
        public void onSessionSuspended(Session session, int error) {
            Toast.makeText(getApplicationContext(), "ChromeCast Session suspended", Toast.LENGTH_SHORT).show();
        }
        @Override
        public void onSessionResuming(Session session, String sessionId) {
            Toast.makeText(getApplicationContext(), "ChromeCast Session resuming", Toast.LENGTH_SHORT).show();
        }
        @Override
        public void onSessionResumed(Session session, boolean wasSuspended) {
            Toast.makeText(getApplicationContext(), "ChromeCast Session resumed", Toast.LENGTH_SHORT).show();
        }
        @Override
        public void onSessionResumeFailed(Session session, int error) {
            Toast.makeText(getApplicationContext(), "ChromeCast Session resume failed !", Toast.LENGTH_SHORT).show();
        }
        @Override
        public void onSessionEnding(Session session) {
            Toast.makeText(getApplicationContext(), "ChromeCast Session ending", Toast.LENGTH_SHORT).show();
        }
        @Override
        public void onSessionEnded(Session session, int error) {
            Toast.makeText(getApplicationContext(), "ChromeCast Session ended", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.medialist_activity);

        mediaListView = (ExpandableListView) findViewById(R.id.medialist);

        LayoutInflater vi = (LayoutInflater) this
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View emptyItemView = vi.inflate(R.layout.medialist_item, null);
        mediaListView.setEmptyView(emptyItemView);

        listAdapter = new MediaListAdapter(this);
        listAdapter.setOnResumeButtonListener(this);

        mediaListView.setOnCreateContextMenuListener(this);
        mediaListView.setOnChildClickListener(this);
        mediaListView.setAdapter(listAdapter);

        // Protecting chromecast initialization against any runtime exception
        // (i.e. Google Services version runtime error)
        try {
            mSessionManager = CastContext.getSharedInstance(this).getSessionManager();
        } catch (RuntimeException e) {
            Toast.makeText(this, "Cast service not initialized",
                    Toast.LENGTH_SHORT).show();
        }

        DownloaderServiceIntent = new Intent(this, DownloadService.class);
        startService(DownloaderServiceIntent);
        //AGAMA_ANALYTICS: if (savedInstanceState == null) { // it means it is NOT a re-initialization
        //AGAMA_ANALYTICS:    initializeAgamaPlugin();
        //AGAMA_ANALYTICS: }

    }

    //AGAMA_ANALYTICS: private void initializeAgamaPlugin() {

    //AGAMA_ANALYTICS:     HashMap<String, Object> mAgamaSettings = new HashMap<String, Object>();

        // mandatory settings
    //AGAMA_ANALYTICS:     //mAgamaSettings.put(LVAgamaPlugin.SETTINGS_SERVER_HOST, "213.115.244.81");
    //AGAMA_ANALYTICS:     mAgamaSettings.put(LVAgamaPlugin.SETTINGS_SERVER_HOST, "172.20.182.99");
    //AGAMA_ANALYTICS:     //mAgamaSettings.put(LVAgamaPlugin.SETTINGS_SERVER_PORT, 23050);
    //AGAMA_ANALYTICS:     mAgamaSettings.put(LVAgamaPlugin.SETTINGS_SERVER_PORT, 8050);
    //AGAMA_ANALYTICS:     mAgamaSettings.put(LVAgamaPlugin.SETTINGS_REPORT_INTERVAL, 60);
    //AGAMA_ANALYTICS:     mAgamaSettings.put(LVAgamaPlugin.SETTINGS_ID_REPORT_INTERVAL, 480);
    //AGAMA_ANALYTICS:     mAgamaSettings.put(LVAgamaPlugin.SETTINGS_OPERATOR_ID, "fooSoo");
        // optional settings
    //AGAMA_ANALYTICS:    mAgamaSettings.put(LVAgamaPlugin.SETTINGS_REDIRECT_URI, true);
    //AGAMA_ANALYTICS:     mAgamaSettings.put(LVAgamaPlugin.SETTINGS_REPORT_DELAY, 5);
    //AGAMA_ANALYTICS:     mAgamaSettings.put(LVAgamaPlugin.SETTINGS_USER_ACCOUNT_ID, "myUserAccountId");

    //AGAMA_ANALYTICS:     try {
    //AGAMA_ANALYTICS:        LVAgamaPlugin.getInstance().init(getApplicationContext(), mAgamaSettings);
    //AGAMA_ANALYTICS:     } catch (LVAgamaPlugin.LVAgamaPluginException | IllegalArgumentException e){
    //AGAMA_ANALYTICS:         Log.e(TAG, "onCreate - Error while initializing Agama plugin: " + e.getMessage());
    //AGAMA_ANALYTICS:     }
    //AGAMA_ANALYTICS:     LVAgamaPlugin.getInstance().setAppStartTime(200);//a fake value for the startup time
    //AGAMA_ANALYTICS: }

    @Override
    protected void onPause() {
        super.onPause();
        DLMgr.unregisterOnErrorListener(this);
        DLMgr.unregisterOnInfoListener(this);
        DLMgr.unregisterOnPreparedListener(this);

        if (null != mSessionManager) {
            mSessionManager.removeSessionManagerListener(mSessionManagerListener);
        }
    }

    @Override
    protected void onStop() {
        MediaMetaInfoDB.getInstance(getApplicationContext()).storeLocalCacheToPersistent();
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        // we have to stop the local http server before quitting
        if (null != DLMgr && isFinishing()) {
            DLMgr.stopLocalServer();
            DLMgr.releaseAllDownloaders();
            stopService(DownloaderServiceIntent);
        }

        //AGAMA_ANALYTICS:// Don't stop Agama when Android re-initialize the activity, due to screen rotation for example
        //AGAMA_ANALYTICS:if (isFinishing()) {
        //AGAMA_ANALYTICS:   LVAgamaPlugin.getInstance().dealloc();
        //AGAMA_ANALYTICS:}

        super.onDestroy();
    }

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

        if (null == mediaItems) {
            fillMappedMedias();
        } else {
            refreshMediaList();
        }
        listAdapter.setData(mediaGroups, mediaItems);
        listAdapter.notifyDataSetChanged();
        mediaListView.expandGroup(0);

        updateDlList();

        DLMgr = DownloadManager.getInstance(getApplicationContext());
        DLMgr.registerOnErrorListener(this);
        DLMgr.registerOnInfoListener(this);
        DLMgr.registerOnPreparedListener(this);

        if (null != mSessionManager) {
            mSessionManager.addSessionManagerListener(mSessionManagerListener);
        }
    }

    private void fillMappedMedias() {

        mediaGroups = new ArrayList<String>();
        mediaItems = new ArrayList<List<MediaItem>>();

        MediasMapperInterface mediaHolder = getRequiredMediaHolder();
        if (null != mediaHolder) {

            Map<String, List<MediaItem>> mappedMediaItems = mediaHolder
                    .getMappedMedias();
            for (String mapKey : mappedMediaItems.keySet()) {
                if(!mapKey.equalsIgnoreCase(MediaTypeMapper.SUBTITLE_FILES_MAP_KEY)) {
                    mediaGroups.add(mapKey);
                    mediaItems.add(mappedMediaItems.get(mapKey));
                }
            }
            MediaItem mediaItem = new StreamingMediaItem("20",
                    "http://cdn3.viblast.com/streams/hls/airshow/playlist.m3u8",
                    "Live HLS Planes", false);
            mediaItems.get(0).add(mediaItem);
        }
    }

    private MediasMapperInterface getRequiredMediaHolder() {
        File listOverrideFile = new File(Constants.MEDIA_LIST_OVERRIDE_FILE);
        if(listOverrideFile.exists()) {
            return new MediaCustomListMapper(Constants.MEDIA_LIST_OVERRIDE_FILE);
        }
        else {
            return new MediaTypeMapper(
                    LocalMediasFinder.getInstance(getApplicationContext()));
        }
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v,
            ContextMenuInfo menuInfo) {

        if (menuInfo instanceof ExpandableListView.ExpandableListContextMenuInfo) {

            ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
            int type = ExpandableListView
                    .getPackedPositionType(info.packedPosition);
            int group = ExpandableListView
                    .getPackedPositionGroup(info.packedPosition);
            int child = ExpandableListView
                    .getPackedPositionChild(info.packedPosition);

            // Only create a context menu for child items
            if (1 == type) {
                MediaItem mediaItem = mediaItems.get(group).get(child);

                menu.setHeaderTitle("Select action");
                menu.add(0, CONTEXT_MENU_ACTION_INFO, 0, "Media info");

                // if the menu is for a streaming media (NOT embedded) and downloader feature is available
                if (MediaType.HTTP_STREAMING_MEDIA == mediaItem.getMediaType() ||
                    MediaType.HTTP_STREAMING_MEDIA_EBD == mediaItem.getMediaType()) {
                    populateContextMenuForStreamingItem((StreamingMediaItem)mediaItem, menu);
                }
                else if(MediaType.LOCAL_MEDIA == mediaItem.getMediaType() ||
                        MediaType.SUBTITLE_FILE == mediaItem.getMediaType()) {
                    menu.add(0, CONTEXT_MENU_ACTION_DELETE, 0, "Delete file");
                }
            }
        }
    }

    private void populateContextMenuForStreamingItem(StreamingMediaItem item, Menu menu) {

        boolean addDeleteItemAction = true;
        DatabaseInfo dbInfo = item.getAssociatedDBInfo();

        if (MediaType.HTTP_STREAMING_MEDIA_EBD == item.getMediaType()){
            addDeleteItemAction = false;
        }

        // if the media has an associated Download bitrate,
        // add actions related to Download
        if (null != dbInfo && null != dbInfo.DlLocalServerUrl) {
            /* if the media has a local url, it is fully downloaded, only option is to delete the data
         otherwise, we can either resume or pause the download */
            if(DatabaseInfo.DL_STATUS_FULLY_LOCAL != dbInfo.DlStatus) {
                // if there is a downloader handling the media
                // Uri and currently downloading,
                // the action to propose is "Pause"
                DownloaderWrapper downloader = DLMgr.getDownloaderForMediaId(item.getMediaId());
                if (null != downloader
                        && downloader.getState() == DownloaderWrapper.State.DOWNLOADING) {
                    menu.add(0, CONTEXT_MENU_ACTION_PAUSE_DL, 0, "Pause download");
                }
                // otherwise, the action is resume
                else {
                    menu.add(0, CONTEXT_MENU_ACTION_RESUME_DL, 0, "Resume download");
                }
            }
            menu.add(0, CONTEXT_MENU_ACTION_DELETE_DL, 0, "Delete downloaded data");
            // if we have Verimatrix parameters, display key options as well
            if((null != item.getCompanyName()) && (null != item.getBootAddress()) ||
                    ( null != item.getDrmAgentType() && item.getDrmAgentType().equals(Constants.DRM_AGENT_TYPE_AES))) {
                menu.add(0, CONTEXT_MENU_ACTION_GET_KEY_EXPIRATION, 0, "Get key expiration");
                menu.add(0, CONTEXT_MENU_ACTION_RENEW_KEY, 0, "Renew key");
            }
            addDeleteItemAction = false;
        } else { // we do not
            menu.add(0, CONTEXT_MENU_ACTION_START_DL, 0, "Downloader");
        }

        //add an option to check DRM rights
        if(null != item.getDrmAgentType()) {
            menu.add(0, CONTEXT_MENU_ACTION_DRM_MANAGER, 0, "DRM Manager");
        }

        //add an option to handle Verimatrix client
        if(null != item.getBootAddress() && null != item.getCompanyName()) {
            mStaticClientBootAddress = item.getBootAddress();
            mStaticClientCompanyName = item.getCompanyName();
            if (false == bClientVerimatrixInitialized) {
                menu.add(0, CONTEXT_MENU_ACTION_CLIENT_VMX, 0, "Create Vmx client");
            } else {
                menu.add(0, CONTEXT_MENU_ACTION_CLIENT_VMX, 0, "Release Vmx client");
            }
        }

        if(addDeleteItemAction) {
            menu.add(0, CONTEXT_MENU_ACTION_DELETE, 0, "Delete description file");
        }
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {

        Log.d(TAG, "onContextItemSelected start");
        ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) item
                .getMenuInfo();

        String title = new String("Context menu - action:" + item.getItemId()
                + " ");

        int type = ExpandableListView
                .getPackedPositionType(info.packedPosition);

        if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
            int groupPos = ExpandableListView
                    .getPackedPositionGroup(info.packedPosition);
            int childPos = ExpandableListView
                    .getPackedPositionChild(info.packedPosition);

            executeActionOnMediaItem(item.getItemId(), groupPos, childPos);

            return true;
        } else if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
            int groupPos = ExpandableListView
                    .getPackedPositionGroup(info.packedPosition);
            Toast.makeText(this, title + ": Group " + groupPos + " clicked",
                    Toast.LENGTH_SHORT).show();
            return true;
        }
        Log.d(TAG, "onContextItemSelected end");
        return false;
    }

    private void executeActionOnMediaItem(int action, int groupId, int childId) {

        MediaItem mediaItem = mediaItems.get(groupId).get(childId);

        switch(action) {
        case CONTEXT_MENU_ACTION_INFO:
            MediaType mediaType = mediaItem.getMediaType();
            if (MediaType.HTTP_STREAMING_MEDIA == mediaType
                    || MediaType.HTTP_STREAMING_MEDIA_EBD == mediaType) {
                displayStreamingMediaDetailDialog((StreamingMediaItem) mediaItem);
            }
            break;

        case CONTEXT_MENU_ACTION_DELETE:
            targetedGroup = groupId;
            targetedPosition = childId;
            showDialog(REMOVE_ITEM_DIALOG);
            break;

        case CONTEXT_MENU_ACTION_START_DL:
            Log.d(TAG, "executeActionOnMediaItem - Action = CONTEXT_MENU_ACTION_START_DL");
            DownloadManager DlMgr = DownloadManager.getInstance(getApplicationContext());

            if (DlMgr.getNbAvailableDownloaders() > 0) {
                Log.d(TAG, "executeActionOnMediaItem - forward to alt picker");
                startDownloadAltPickerActivity((StreamingMediaItem) mediaItem);
            } else {
                Log.d(TAG, "executeActionOnMediaItem - no downloader available, cancel another download first");
                targetedGroup = groupId;
                targetedPosition = childId;
                Toast.makeText(getApplicationContext(), "No downloader available, cancel another download first", Toast.LENGTH_SHORT).show();
            }
            break;

        case CONTEXT_MENU_ACTION_PAUSE_DL:
            stopDownloadForItem(mediaItem);
            break;

        case CONTEXT_MENU_ACTION_RESUME_DL:
            resumeDownload(mediaItem);
            break;

        case CONTEXT_MENU_ACTION_DELETE_DL:
            deleteDownloadData(mediaItem);
            break;

        case CONTEXT_MENU_ACTION_GET_KEY_EXPIRATION:
            showKeyExpirationForMedia((StreamingMediaItem) mediaItem);
            break;

        case CONTEXT_MENU_ACTION_RENEW_KEY:
            renewOfflineKey((StreamingMediaItem) mediaItem);
            break;

        case CONTEXT_MENU_ACTION_DRM_MANAGER:
            startDRMManagerActivity((StreamingMediaItem) mediaItem);
            break;

        case CONTEXT_MENU_ACTION_CLIENT_VMX:
            HandleVmxClient();
            break;

        default:
            Log.w(TAG, "unsupported action " + action);
            break;
        }
    }

    private void startDRMManagerActivity(StreamingMediaItem streamingItem) {
        Intent i = new Intent();
        i.setClass(getApplicationContext(), DrmManagerActivity.class);
        i.setAction(Intent.ACTION_VIEW);

        Uri mediaUri = Uri.parse(streamingItem.getMediaUri());
        MediaType type = streamingItem.getMediaType();
        DatabaseInfo dbInfo = streamingItem.getAssociatedDBInfo();
        if ( MediaType.HTTP_STREAMING_MEDIA == type
                || MediaType.HTTP_STREAMING_MEDIA_EBD == type) {

            if (null != streamingItem.getDrmAgentType()) {
                i.putExtra(Constants.DRM_AGENT_TYPE,
                        streamingItem.getDrmAgentType());
            }

            if (null != streamingItem.getDrmPersonalizationUrl()) {
                i.putExtra(Constants.DRM_PERSONALIZATION_URL,
                        streamingItem.getDrmPersonalizationUrl());
            }

            if (null != streamingItem.getDrmPersonalizationAppVersion()) {
                i.putExtra(Constants.DRM_PERSONALIZATION_APPVERSION,
                        streamingItem.getDrmPersonalizationAppVersion());
            }

            if (null != streamingItem.getDrmPersonalizationCustomData()) {
                i.putExtra(Constants.DRM_PERSONALIZATION_CUSTOM_DATA,
                        streamingItem.getDrmPersonalizationCustomData());
            }

            if (null != streamingItem.getDrmPersonalizationCustomerID()) {
                i.putExtra(Constants.DRM_PERSONALIZATION_CUSTOMER_ID,
                        streamingItem.getDrmPersonalizationCustomerID());
            }

            if (null != streamingItem.getDRMLicenseAcquisitionUrl()) {
                i.putExtra(Constants.DRM_LICENSE_URL_SKEY,
                        streamingItem.getDRMLicenseAcquisitionUrl());
            }

            if (null != streamingItem.getDRMLicenseAcquisitionUrlParameters()) {
                i.putExtra(Constants.DRM_LICENSE_URL_PARAMETERS_SKEY,
                        streamingItem.getDRMLicenseAcquisitionUrlParameters());
            }

            if (null != streamingItem.getDRMLicenseAcquisitionCustomData()) {
                i.putExtra(Constants.DRM_LICENSE_CUSTOM_DATA_SKEY,
                        streamingItem.getDRMLicenseAcquisitionCustomData());
            }

            if (null != streamingItem.getDRMLicenseAcquisitionCookie()) {
                i.putExtra(Constants.DRM_LICENSE_COOKIE_SKEY,
                        streamingItem.getDRMLicenseAcquisitionCookie());
            }

            if (null != streamingItem.getDrmContentIdentifier()) {
                i.putExtra(Constants.DRM_CONTENT_IDENTIFIER,
                        streamingItem.getDrmContentIdentifier());
            }

            i.putExtra(Constants.DRM_LICENSE_USE_VOSECURITYGATEWAY,
                        streamingItem.useVOSecurityGateway());

        }

        if (null != dbInfo) {

            if (dbInfo.DlStatus > 0) {
                Log.d(TAG,"startPlayback - THIS IS AN DL STREAM > need to start server first");
                boolean started = startLocalHttpServer();
                if (!started) {
                    Log.e(TAG,
                            "startPlayback - Error with local HTTP server");
                    Toast.makeText(
                            getApplicationContext(),
                            "Error when starting local HTTP server.\nget info impossible.",
                            Toast.LENGTH_SHORT).show();
                    return;
                }

                i.putExtra(Constants.DL_ORG_URI_INTENT_SKEY, streamingItem.toString());
                mediaUri = Uri.parse(dbInfo.DlLocalServerUrl.replace("'", ""));
                i.putExtra(Constants.LOCAL_SERVER_INTENT_ZKEY, true);
            }
        }
        Log.d(TAG, "starting DRM manager for uri: " + mediaUri);
        i.setData(mediaUri);

        this.startActivity(i);
    }

    private void showKeyExpirationForMedia(StreamingMediaItem item) {

        if((null == item.getCompanyName()) ||  (null == item.getBootAddress())) {
            Toast.makeText(getApplicationContext(), "Wrong media type", Toast.LENGTH_SHORT).show();
            return;
        }

        DatabaseInfo dbInfo = item.getAssociatedDBInfo();
        if(null == dbInfo) {
            Log.e(TAG, "Database info should not be null at this point" + item.getDisplayName());
            return;
        }
        if(dbInfo.DlStatus <= 0) {
            Log.e(TAG, "Invalid download status " + item.getDisplayName());
            return;
        }

        if (null != dbInfo.DlLocalServerUrl) {

            DownloaderWrapper downloader = DLMgr.getDownloaderForMediaId(item.getMediaId());

            boolean downloaderCreatedHere = false;
            if((null == downloader) &&
                    (DLMgr.getNbAvailableDownloaders() > 0)) {
                downloader = DLMgr.createDownloaderForMediaId(item.getMediaId(), item.getMediaUri(), item.getBootAddress(), item.getCompanyName());
                downloaderCreatedHere = true;
            }

            if(null != downloader) {
                //Proxy Settings
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
                String proxyTypePref = prefs.getString(Constants.PREF_PROXY_TYPE, "No proxy");
                int ProxyType = 0;
                if (proxyTypePref.equals("HTTP")) {
                    ProxyType = 1;
                } else if (proxyTypePref.equals("SOCKS v4")) {
                    ProxyType = 2;
                } else if (proxyTypePref.equals("SOCKS v5")) {
                    ProxyType = 3;
                } else {
                    ProxyType = 0;
                }
                String proxyTypeUrl = prefs.getString(Constants.PREF_PROXY_URL, "");
                Integer proxyPort = Integer.parseInt(prefs.getString(Constants.PREF_PROXY_PORT, "0"));
                downloader.setProxy(proxyTypeUrl, proxyPort, ProxyType);

                ongoingDownloadAction = OngoingDLActionType.GET_EXPIRATION;
                resumeDlBitrate = dbInfo.DLBitrate;
                int nbQualities = downloader.getNbQualities();
                int selectedQualityId = -1;
                for (int i = 0; i < nbQualities; i++) {
                    if (resumeDlBitrate == downloader.getBitrateByIndex(i)) {
                        selectedQualityId = i;
                        break;
                    }
                }
                if(downloader.getState() == State.INITIALIZED) {
                    downloader.asyncPrepare();
                } else {
                    if (selectedQualityId >= 0) {
                        downloader.selectQualityByIndex(selectedQualityId);
                        int expires = downloader.getOfflineKeysExpiration();
                        Toast.makeText(getApplicationContext(), "expiration: " + expires, Toast.LENGTH_SHORT).show();
                    }
                    if(downloaderCreatedHere) {
                        downloader = null;
                        DLMgr.releaseDownloaderForMediaId(item.getMediaId());
                    }
                }

            } else {
                Toast.makeText(getApplicationContext(), "Action impossible now.\nTry with less parallel downloads", Toast.LENGTH_SHORT).show();
            }
        }
    }

    /***
     * Create/Release VMX client asynchronously
     */

    /**
     * Asynchronous task that runs the player benchmark in a separate thread, to avoid freezing the UI
     */
    private class RunVerimatrixCreateClientAsyncTask extends AsyncTask<Void, Void, Void> {

        private static final String TAG = "RunVerimatrixCreateClientAsyncTask";

        protected Void doInBackground(Void... nothing) {
            try {
                VOVerimatrixAgent VerimatrixAgent = mPlayerForVmxInit.getAgentVerimatrix();
                VerimatrixAgent.setBootAddress(mStaticClientBootAddress);
                VerimatrixAgent.setCompanyName(mStaticClientCompanyName);
                VerimatrixAgent.createClient();
                bClientVerimatrixInitialized = true;
            } catch (VOException e) {
                e.printStackTrace();

            } catch (IllegalStateException e){
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            if (bClientVerimatrixInitialized) {
                Toast.makeText(getApplicationContext(), "Verimatrix Client created",
                        Toast.LENGTH_SHORT).show();
            }
        }
    }

    private void HandleVmxClient() {
        //vmx client intialized
        if (null == mPlayerForVmxInit) {
            mPlayerForVmxInit = new VOPlayer(getApplicationContext());
        }
        if (!bClientVerimatrixInitialized) {
            new RunVerimatrixCreateClientAsyncTask().execute();
        } else {
            VOVerimatrixAgent VerimatrixAgent = mPlayerForVmxInit.getAgentVerimatrix();
            try {
                VerimatrixAgent.releaseClient();
            } catch (IllegalStateException e){
                e.printStackTrace();
            }
            mPlayerForVmxInit.release();
            mPlayerForVmxInit = null;
            bClientVerimatrixInitialized = false;
        }
    }


    private void renewOfflineKey(StreamingMediaItem item) {

        if ((null == item.getBootAddress()) ||
                (null == item.getCompanyName())) {
            Log.w(TAG, "renewOfflineKey - Invalid media item");
            return;
        }

        DatabaseInfo dbInfo = item.getAssociatedDBInfo();
        if(null == dbInfo) {
            Log.e(TAG, "Database info should not be null at this point" + item.getDisplayName());
            // TODO: fix database entry
            return;
        }
        if(dbInfo.DlStatus <= 0) {
            Log.e(TAG, "Invalid download status " + item.getDisplayName());
            // TODO: fix database entry
            return;
        }

        if (null != dbInfo.DlLocalServerUrl) {

            DownloaderWrapper downloader = DLMgr.getDownloaderForMediaId(item.getMediaId());

            if((null == downloader) &&
                    (DLMgr.getNbAvailableDownloaders() > 0)) {
                downloader = DLMgr.createDownloaderForMediaId(item.getMediaId(), item.getMediaUri(), item.getBootAddress(), item.getCompanyName());
            }
            if(null != downloader) {
                //Proxy Settings
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
                String proxyTypePref = prefs.getString(Constants.PREF_PROXY_TYPE, "No proxy");
                int ProxyType = 0;
                if (proxyTypePref.equals("HTTP")) {
                    ProxyType = 1;
                } else if (proxyTypePref.equals("SOCKS v4")) {
                    ProxyType = 2;
                } else if (proxyTypePref.equals("SOCKS v5")) {
                    ProxyType = 3;
                } else {
                    ProxyType = 0;
                }
                String proxyTypeUrl = prefs.getString(Constants.PREF_PROXY_URL, "");
                Integer proxyPort = Integer.parseInt(prefs.getString(Constants.PREF_PROXY_PORT, "0"));
                downloader.setProxy(proxyTypeUrl, proxyPort, ProxyType);

                showDialog(PROCESSING_DL_DIALOG);
                ongoingDownloadAction = OngoingDLActionType.RENEW_KEY;
                resumeDlBitrate = dbInfo.DLBitrate;
                Log.d(TAG, "renewOfflineKey - downloader state: " + downloader.getState());
                if(downloader.getState() == State.INITIALIZED) {
                    downloader.asyncPrepare();
                } else {
                    try {
                        downloader.renewOfflineKeys();
                    } catch(IllegalStateException e) {
                        Toast.makeText(getApplicationContext(), "Error while renewing key", Toast.LENGTH_SHORT).show();
                    }
                }
            } else {
                Toast.makeText(getApplicationContext(), "No downloader available, please cancel another download first", Toast.LENGTH_SHORT).show();
            }
        } else {
            Log.w(TAG, "resumeDownload - DL bitrate <= 0, corruption ??");
        }
    }

    private void deleteDownloadData(MediaItem item) {
        if (MediaType.HTTP_STREAMING_MEDIA != item.getMediaType()
                && MediaType.HTTP_STREAMING_MEDIA_EBD != item.getMediaType()) {
            Log.w(TAG, "deleteDownloadData - Invalid media item");
            return;
        }
        StreamingMediaItem strItem = (StreamingMediaItem) item;
        DatabaseInfo dbInfo = strItem.getAssociatedDBInfo();

        if(null == dbInfo) {
            Log.e(TAG, "Database info should not be null at this point" + item.getDisplayName());
            return;
        }

        if (null != dbInfo.DlLocalServerUrl) {

            showDialog(PROCESSING_DL_DIALOG);

            DownloaderWrapper downloader = DLMgr.getDownloaderForMediaId(item.getMediaId());

            // if a downloader is already register for this uri, we first need to stop it
            if(null != downloader) {
                stopDownloadForItem(item);
            }
            if (DLMgr.getNbAvailableDownloaders() > 0) {
                ongoingDownloadAction = OngoingDLActionType.DELETE;
                resumeDlBitrate = dbInfo.DLBitrate;
                downloader = DLMgr.createDownloaderForMediaId(item.getMediaId(), item.getMediaUri());
                downloader.asyncPrepare();
            } else {
                try {
                    dismissDialog(PROCESSING_DL_DIALOG);
                } catch (IllegalArgumentException e) {
                }
                Toast.makeText(getApplicationContext(),
                        "No downloader available, cancel another download first",
                        Toast.LENGTH_SHORT).show();
            }
        } else {
            Log.w(TAG, "resumeDownload - DL bitrate <= 0, corruption ??");
        }
    }

    private void displayDownloadErrorToast() {
        Toast.makeText(getApplicationContext(), "Download error",
                Toast.LENGTH_SHORT).show();
    }

    private void startDownloadAltPickerActivity(StreamingMediaItem streamingItem) {

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        Intent i = new Intent();
        i.setClass(getApplicationContext(), DownloadActivity.class);
        i.setAction(Intent.ACTION_VIEW);
        Log.d(TAG,
                "starting Download alt picker for uri: "
                        + streamingItem.getMediaUri());
        i.setData(Uri.parse(streamingItem.getMediaUri()));

        i.putExtra(Constants.MEDIA_ID_SKEY, streamingItem.getMediaId());

        DatabaseInfo dbInfo = streamingItem.getAssociatedDBInfo();

        if (null != dbInfo) {
            if (null != dbInfo.associatedSubtitleFile) {
                i.putExtra(Constants.SUBTITLE_FILE_INTENT_SKEY,
                        dbInfo.associatedSubtitleFile);
            }
            if (null != dbInfo.associatedTimedTextTrack) {
                i.putExtra(Constants.SUBTITLE_TRACK_INTENT_SKEY,
                        dbInfo.associatedTimedTextTrack);
            }
            i.putExtra(Constants.SUBTITLE_TRACKTYPE_INTENT_SKEY,
                        dbInfo.associatedTimedTextType);
        }

        if (null != streamingItem.getBootAddress()
                && null != streamingItem.getCompanyName()) {
            i.putExtra(Constants.VCAS_BOOT_ADDRESS_INTENT_SKEY,
                    streamingItem.getBootAddress());
            i.putExtra(Constants.VCAS_COMPANY_NAME_INTENT_SKEY,
                    streamingItem.getCompanyName());
        }

        if (null != streamingItem.getDrmAgentType()) {
            i.putExtra(Constants.DRM_AGENT_TYPE,
                    streamingItem.getDrmAgentType());
        }

        if (null != streamingItem.getDrmPersonalizationUrl()) {
            i.putExtra(Constants.DRM_PERSONALIZATION_URL,
                    streamingItem.getDrmPersonalizationUrl());
        }

        if (null != streamingItem.getDrmPersonalizationAppVersion()) {
            i.putExtra(Constants.DRM_PERSONALIZATION_APPVERSION,
                    streamingItem.getDrmPersonalizationAppVersion());
        }

        if (null != streamingItem.getDrmPersonalizationCustomData()) {
            i.putExtra(Constants.DRM_PERSONALIZATION_CUSTOM_DATA,
                    streamingItem.getDrmPersonalizationCustomData());
        }

        if (null != streamingItem.getDrmPersonalizationCustomerID()) {
            i.putExtra(Constants.DRM_PERSONALIZATION_CUSTOMER_ID,
                    streamingItem.getDrmPersonalizationCustomerID());
        }

        if (null != streamingItem.getDRMLicenseAcquisitionUrl()) {
            i.putExtra(Constants.DRM_LICENSE_URL_SKEY,
                    streamingItem.getDRMLicenseAcquisitionUrl());
        }

        if (null != streamingItem.getDRMLicenseAcquisitionUrlParameters()) {
            i.putExtra(Constants.DRM_LICENSE_URL_PARAMETERS_SKEY,
                    streamingItem.getDRMLicenseAcquisitionUrlParameters());
        }

        if (null != streamingItem.getDRMLicenseAcquisitionCustomData()) {
            i.putExtra(Constants.DRM_LICENSE_CUSTOM_DATA_SKEY,
                    streamingItem.getDRMLicenseAcquisitionCustomData());
        }

        if (null != streamingItem.getDRMLicenseAcquisitionCookie()) {
            i.putExtra(Constants.DRM_LICENSE_COOKIE_SKEY,
                    streamingItem.getDRMLicenseAcquisitionCookie());
        }

        i.putExtra(Constants.MARLIN_PROTECTED_SKEY, streamingItem.getMarlinProtected());
        i.putExtra(Constants.FAST_STARTUP_BKEY, streamingItem.getFastStartup());
        i.putExtra(Constants.LOCAL_SERVER_DEMO_BKEY, streamingItem.getLocalServerDemo());

        if (null != streamingItem.getDbFaasOffline()) {
                i.putExtra(Constants.DB_FAAS_OFFLINE_SKEY,
                        streamingItem.getDbFaasOffline());
        }

        if(null != streamingItem.getHttpAuthUsername() &&
           null != streamingItem.getHttpAuthPassword()) {
            i.putExtra(Constants.AUTH_USER_NAME_INTENT_SKEY,
                    streamingItem.getHttpAuthUsername());
            i.putExtra(Constants.AUTH_PASSWORD_INTENT_SKEY,
                    streamingItem.getHttpAuthPassword());
        }

        if(null != streamingItem.getSSLCACertFilePath() &&
           null != streamingItem.getSSLCACertFileType()) {
            i.putExtra(Constants.SSL_CA_CERT_FILE_PATH_INTENT_SKEY,
                    streamingItem.getSSLCACertFilePath());
            i.putExtra(Constants.SSL_CA_CERT_FILE_TYPE_INTENT_SKEY,
                    streamingItem.getSSLCACertFileType());
        }

        if(null != streamingItem.getSSLClientCertFilePath() &&
           null != streamingItem.getSSLClientCertFileType()) {
            i.putExtra(Constants.SSL_CLIENT_CERT_FILE_PATH_INTENT_SKEY,
                    streamingItem.getSSLClientCertFilePath());
            i.putExtra(Constants.SSL_CLIENT_CERT_FILE_TYPE_INTENT_SKEY,
                    streamingItem.getSSLClientCertFileType());
        }

        if(null != streamingItem.getSSLClientKeyFilePath() &&
           null != streamingItem.getSSLClientKeyFileType()) {
            i.putExtra(Constants.SSL_CLIENT_KEY_FILE_PATH_INTENT_SKEY,
                    streamingItem.getSSLClientKeyFilePath());
            i.putExtra(Constants.SSL_CLIENT_KEY_FILE_TYPE_INTENT_SKEY,
                    streamingItem.getSSLClientKeyFileType());
        }

        if(null != streamingItem.getHttpCustomHeader()) {
            i.putExtra(Constants.HTTP_CUSTOM_HEADER_INTENT_SKEY,
                    streamingItem.getHttpCustomHeader());
        }

        this.startActivity(i);
    }

    @Override
    protected Dialog onCreateDialog(int id) {

        switch (id) {

        case REMOVE_ITEM_DIALOG:
            AlertDialog.Builder rmItemBuilder = new AlertDialog.Builder(this);
            rmItemBuilder.setMessage(getText(R.string.delete_file_text));
            rmItemBuilder.setCancelable(false);
            rmItemBuilder.setPositiveButton(getText(R.string.yes_text),
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            removeMediaFromList();
                        }
                    });
            rmItemBuilder.setNegativeButton(getText(R.string.no_text),
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.cancel();
                        }
                    });
            return rmItemBuilder.create();

        case ABOUT_DIALOG:
            AlertDialog.Builder aboutBuilder = new AlertDialog.Builder(this);
            aboutBuilder.setTitle(R.string.about);
            aboutBuilder.setIcon(R.drawable.icon_nbg);
            CharSequence aboutMsg = getAboutMessage();
            aboutBuilder.setMessage(aboutMsg);
            return aboutBuilder.create();

        case PROCESSING_DL_DIALOG:
            Log.d(TAG, "create processing dialog");
            processingDialog = new ProgressDialog(this);
            processingDialog.setCancelable(false);
            processingDialog.setTitle(R.string.wait);
            processingDialog.setMessage("Processing Download action");
            processingDialog.setIndeterminate(true);
            processingDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            return processingDialog;

        case RIGHT_ACQUISITION_DIALOG:
            Log.d(TAG, "create right acquisition dialog");
            processingDialog = new ProgressDialog(this);
            processingDialog.setCancelable(false);
            processingDialog.setTitle(R.string.wait);
            processingDialog.setMessage("Right acquisition on going");
            processingDialog.setIndeterminate(true);
            processingDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            return processingDialog;

        default:
            return super.onCreateDialog(id);
        }
    }

    private void stopDownloadForItem(MediaItem item) {

        if (MediaType.HTTP_STREAMING_MEDIA != item.getMediaType()
                && MediaType.HTTP_STREAMING_MEDIA_EBD != item.getMediaType()) {
            Log.w(TAG, "resumeDownload - Invalid media item");
            return;
        }

        DownloaderWrapper downloader = DLMgr.createDownloaderForMediaId(item.getMediaId(), item.getMediaUri());
        // if the media is actually "known" by downloader module, we can proceed
        if (null != downloader) {

            if(downloader.getState() != State.ERROR) {
                // stop the download
                downloader.stop();
            }

            // update the database information for the media
            MediaMetaInfoDB db = MediaMetaInfoDB.getInstance(getApplicationContext());

            DatabaseInfo dbInfo = db.getAssociatedDataForMedia(item.getMediaId());
            if(null == dbInfo) {
                Log.w(TAG, "Error, at this place database info should never be null" + item.getMediaId());
                return;
            }

            dbInfo.DLProgress = downloader.getDownloadedDuration();
            dbInfo.DlStatus = DatabaseInfo.DL_STATUS_PAUSED;
            db.setDbInfoForMedia(item.getMediaId(), dbInfo);

            // release downloader
            downloader = null;
            DLMgr.releaseDownloaderForMediaId(item.getMediaId());

            // update the list of displayed items matching the uri
            List<MediaItem> matchItems = findStreamingItemsMatchingMediaId(item.getMediaId());

            Log.d(TAG, "stopCurrentDownload - found " + matchItems.size()
                    + " items matching url: " + item.getMediaUri());
            for (MediaItem i : matchItems) {

                Log.d(TAG, "stopCurrentDownload for item: " + i.toString());
                if (i.getMediaType() != MediaType.HTTP_STREAMING_MEDIA) {
                    continue;
                }
                i.setAssociatedDBInfo(dbInfo);
            }
            listAdapter.notifyDataSetChanged();
        } else {
            Log.w(TAG, "stopDownloadForItem - no downloader found for mediaId: "
                    + item.getMediaId());
        }
    }

    private void resumeDownload(MediaItem item) {
        if ((MediaType.HTTP_STREAMING_MEDIA != item.getMediaType()) && (MediaType.HTTP_STREAMING_MEDIA_EBD != item.getMediaType()) ) {
            Log.w(TAG, "resumeDownload - Invalid media item");
            return;
        }
        StreamingMediaItem strItem = (StreamingMediaItem) item;
        DatabaseInfo dbInfo = strItem.getAssociatedDBInfo();

        if(null == dbInfo) {
            Log.w(TAG, "Database info should not be null at this point" + item.getDisplayName());
            // TODO: fix database entry
            return;
        }
        if(dbInfo.DlStatus <= 0) {
            Log.w(TAG, "Invalid download status " + item.getDisplayName());
            // TODO: fix database entry
            return;
        }

        if (null != dbInfo.DlLocalServerUrl) {

            // if there are still downloaders available
            if (DLMgr.getNbAvailableDownloaders() > 0) {
                showDialog(PROCESSING_DL_DIALOG);
                DownloaderWrapper downloader = DLMgr.createDownloaderForMediaId(item.getMediaId(), item.getMediaUri());

                //Proxy Settings
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
                String proxyTypePref = prefs.getString(Constants.PREF_PROXY_TYPE, "No proxy");
                int ProxyType = 0;
                if (proxyTypePref.equals("HTTP")) {
                    ProxyType = 1;
                } else if (proxyTypePref.equals("SOCKS v4")) {
                    ProxyType = 2;
                } else if (proxyTypePref.equals("SOCKS v5")) {
                    ProxyType = 3;
                } else {
                    ProxyType = 0;
                }
                String proxyTypeUrl = prefs.getString(Constants.PREF_PROXY_URL, "");
                Integer proxyPort = Integer.parseInt(prefs.getString(Constants.PREF_PROXY_PORT, "0"));
                downloader.setProxy(proxyTypeUrl, proxyPort, ProxyType);

                ongoingDownloadAction = OngoingDLActionType.RESUME;
                resumeDlBitrate = dbInfo.DLBitrate;
                downloader.asyncPrepare();

            } else {
                Toast.makeText(getApplicationContext(),
                        "No downloader available, please cancel another download first",
                        Toast.LENGTH_SHORT).show();
            }
        } else {
            Log.w(TAG,
                    "resumeDownload - DL bitrate <= 0, corruption ??");
        }
    }

    private void removeMediaFromList() {
        if (targetedGroup >= 0 && targetedGroup < mediaItems.size()) {
            if (targetedPosition >= 0
                    && targetedPosition < mediaItems.get(targetedGroup).size()) {

                MediaItem item = mediaItems.get(targetedGroup).get(
                        targetedPosition);
                removeMediaFileForItem(item);

                mediaItems.get(targetedGroup).remove(targetedPosition);

                MediaMetaInfoDB database = MediaMetaInfoDB.getInstance(getApplicationContext());
                database.removeDbEntryForUri(item.getMediaId());
                listAdapter.notifyDataSetChanged();
            }
        }
        targetedGroup = -1;
        targetedPosition = -1;
    }

    private void removeMediaFileForItem(MediaItem item) {
        boolean deleted = false;
        switch (item.getMediaType()) {
        case HTTP_STREAMING_MEDIA:
            File mediaDescFile = new File(
                    ((StreamingMediaItem) item).getDescriptionFilePath());
            deleted = mediaDescFile.delete();
            break;
        case LOCAL_MEDIA:
        case SUBTITLE_FILE:
            File mediaFile = new File(item.getMediaUri());
            deleted = mediaFile.delete();
            break;
        default:
            Log.w(TAG,
                    "removeMediaFileForItem - impossible to remove file for item");
            break;
        }
        if (deleted) {
            Toast.makeText(getApplicationContext(),
                    "Media succesfully deleted", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(getApplicationContext(),
                    "Impossible to delete media", Toast.LENGTH_SHORT).show();
        }
    }

    private CharSequence getAboutMessage() {

        int startSpan, endSpan;
        ForegroundColorSpan fcs;
        SpannableStringBuilder strBuffer = new SpannableStringBuilder();
        strBuffer.append("- App name: ");
        strBuffer.append(getResources().getText(R.string.app_name) + "\n");

        try {
            PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
            strBuffer.append("- App version: " + packageInfo.versionName + "\n");
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }

        fcs = new ForegroundColorSpan(Color.BLUE);
        startSpan = strBuffer.length();
        strBuffer.append("** VoPlayer SDK **\n");
        endSpan =  strBuffer.length();
        strBuffer.setSpan(fcs, startSpan, endSpan, Spannable.SPAN_COMPOSING);

        try {
            strBuffer.append(
                    "- SDK version: " + VOPlayer.getSdkVersion(getApplicationContext()) + "\n");
        } catch (VOException e){
            Log.e(TAG, "Impossible to get SDK version, with status code:"+e.getStatus().toString());
            Toast.makeText(getApplicationContext(), "Impossible to get SDK version, with status code:"+e.getStatus().toString(), Toast.LENGTH_LONG).show();

        }
        long sdkExpirationTimeMs = (long)VOPlayer.getSDKExpirationTime(getApplicationContext()) * 1000;
        if(0 == sdkExpirationTimeMs) {
            strBuffer.append("- No SDK expiration date\n");
        }
        else {
            startSpan = strBuffer.length();
            if(sdkExpirationTimeMs > System.currentTimeMillis()) {
                fcs = new ForegroundColorSpan(Color.YELLOW);
                DateFormat df = DateFormat.getDateTimeInstance();
                strBuffer.append("- SDK expiration date: "+ df.format(new Date(sdkExpirationTimeMs))+ "\n" );

            } else {
                fcs = new ForegroundColorSpan(Color.RED);
                strBuffer.append("- SDK expired !\n");
            }
            endSpan =  strBuffer.length();
            strBuffer.setSpan(fcs, startSpan, endSpan, Spannable.SPAN_COMPOSING);
        }

        String deviceID = "error";
        try {
            deviceID = VOPlayer.getUniqueIdentifier(getApplicationContext());
        }catch (VOMissingPermissionException e) {
            Log.e(TAG, "Impossible to get device ID, with missing permission:"+  Arrays.toString(e.getPermissions()));
            Toast.makeText(getApplicationContext(), "Impossible to get device ID with missing permission:"+  Arrays.toString(e.getPermissions()), Toast.LENGTH_LONG).show();

        }catch (VOException e) {
            Log.e(TAG, "Impossible to get device ID, with status code:"+e.getStatus().toString());
            Toast.makeText(getApplicationContext(), "Impossible to get device ID, with status code:"+e.getStatus().toString(), Toast.LENGTH_LONG).show();

        }
        strBuffer.append("- Device ID: " + deviceID);

        VOSystemInfo sysInfo = VOSystemInfoRetriever.getSystemInfo(getApplicationContext());
        strBuffer.append("\n- Screen size: " + sysInfo.screenWidth + "x" + sysInfo.screenHeight);
        strBuffer.append("\n- Model name: " + sysInfo.deviceModel);

        return strBuffer;
    }

    private void onMediaItemClick(int groupPosition, int childPosition) {

        MediaItem mediaItem = mediaItems.get(groupPosition).get(childPosition);
        MediaType mediaType = mediaItem.getMediaType();
        switch (mediaType) {
        case HTTP_STREAMING_MEDIA:
        case HTTP_STREAMING_MEDIA_EBD:
        case MEDIA_PLAYLIST:
        case LOCAL_MEDIA:
            startPlayback(mediaItem, false);
            break;
        default:
            break;
        }
    }

    private void startPlayback(MediaItem mediaItem, boolean useResumeTime) {

        Uri mediaUri;

        Intent i = new Intent();
        i.setClass(getApplicationContext(), PlayerActivity.class);
        i.setAction(Intent.ACTION_VIEW);

        mediaUri = Uri.parse(mediaItem.getMediaUri());

        Utils.fillIntentWithMediaItem(i, mediaItem);

        DatabaseInfo dbInfo =  mediaItem.getAssociatedDBInfo();

        if (null != dbInfo) {

            if (dbInfo.DlStatus > 0) {
                Log.d(TAG,
                        "startPlayback - THIS IS AN DL STREAM > need to start server first");
                boolean started = startLocalHttpServer();
                if (!started) {
                    Log.e(TAG,
                            "startPlayback - Error with local HTTP server");
                    Toast.makeText(
                            getApplicationContext(),
                            "Error when starting local HTTP server.\nPlayback impossible.",
                            Toast.LENGTH_SHORT).show();
                    return;
                }
                i.putExtra(Constants.DL_ORG_URI_INTENT_SKEY, mediaUri.toString());
                mediaUri = Uri.parse(dbInfo.DlLocalServerUrl.replace("'", ""));
                i.putExtra(Constants.LOCAL_SERVER_INTENT_ZKEY, true);
            }
            if (useResumeTime) {
                i.putExtra(Constants.RESUME_TIME_INTENT_IKEY,
                        dbInfo.lastPlaybackPosInMs);
            }
            if (null != dbInfo.associatedSubtitleFile) {
                i.putExtra(Constants.SUBTITLE_FILE_INTENT_SKEY,
                        dbInfo.associatedSubtitleFile);
            }
            if (null != dbInfo.associatedTimedTextTrack) {
                i.putExtra(Constants.SUBTITLE_TRACK_INTENT_SKEY,
                        dbInfo.associatedTimedTextTrack);
            }
            i.putExtra(Constants.SUBTITLE_TRACKTYPE_INTENT_SKEY,
                    dbInfo.associatedTimedTextType);

            if(null != dbInfo.associatedAudioTrack) {
                i.putExtra(Constants.AUDIO_LANGUAGE_INTENT_SKEY, dbInfo.associatedAudioTrack);
            }
        }

        Log.d(TAG, "starting playback for uri: " + mediaUri);
        i.setData(mediaUri);
        // Inform QP it's a native browser Call
        i.putExtra("nativeBrowserCall", true);
        i.putExtra(Constants.MEDIA_ID_SKEY, mediaItem.getMediaId());

        prepareBeforePlayback(i);

        this.startActivity(i);
    }

    private void prepareBeforePlayback(Intent playerStartIntent) {

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        boolean faasOfflineEnabled = prefs.getBoolean(Constants.PREF_ENABLE_FAAS_OFFLINE, false);
        String localFAASOffline = playerStartIntent.getStringExtra(Constants.DB_FAAS_OFFLINE_SKEY);

        // clear codec type exception if needed
        if(faasOfflineEnabled || null != localFAASOffline) {
            Log.d(TAG, "prepareBeforePlayback FaasOffline enabled");
            SharedPreferences mySPrefs = getApplicationContext().getSharedPreferences("VoPlayerBenchmarkPrefs", Context.MODE_PRIVATE);
            SharedPreferences.Editor editor = mySPrefs.edit();
            editor.remove("lastCodecExceptionType");
            editor.apply();
        }
    }

    private boolean startLocalHttpServer() {
        return DLMgr.startLocalServer();
    }

    @Override
    public boolean onChildClick(ExpandableListView arg0, View arg1,
            int groupId, int childId, long arg4) {
        onMediaItemClick(groupId, childId);
        return true;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.medialist_activity_menu, menu);

        if (null != mSessionManager) {
            CastButtonFactory.setUpMediaRouteButton(getApplicationContext(),
                    menu,
                    R.id.media_route_menu_item);
        }

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        Intent intent;
        switch (item.getItemId()) {
        case R.id.settings:
            intent = new Intent();
            intent.setClass(getApplicationContext(), SettingsActivity.class);
            intent.setAction(Intent.ACTION_VIEW);
            this.startActivity(intent);
            return true;
        case R.id.about_menu:
            showDialog(ABOUT_DIALOG);
            return true;
        case R.id.clear_benchmark_data:
            clearBenchmarkData();
            return true;
        case R.id.loglevels_menu:
            intent = new Intent();
            intent.setClass(getApplicationContext(), LogLevelsActivity.class);
            intent.setAction(Intent.ACTION_VIEW);
            this.startActivity(intent);
            return true;
            case R.id.youbora_options:
                YouboraConfigManager.Companion.getInstance().showConfig(this);
                return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    private void clearBenchmarkData() {
        SharedPreferences benchmarkPrefs = getSharedPreferences("VOPlayerBenchmarkPrefs", Context.MODE_PRIVATE);
        SharedPreferences.Editor prefEditor = benchmarkPrefs.edit();
        prefEditor.clear();
        prefEditor.commit();
        Toast.makeText(getApplicationContext(), "Benchmark preferences erased", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onResumeButtonClick(int groupId, int childId) {

        MediaItem mediaItem = mediaItems.get(groupId).get(childId);
        MediaType mediaType = mediaItem.getMediaType();
        switch (mediaType) {
        case HTTP_STREAMING_MEDIA:
        case HTTP_STREAMING_MEDIA_EBD:
        case LOCAL_MEDIA:
            startPlayback(mediaItem, true);
            break;
        default:
            break;
        }
    }

    private void displayStreamingMediaDetailDialog(StreamingMediaItem mediaItem) {

        Log.d(TAG, "testMediaDetail " + mediaItem.getMediaUri());

        LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
        View layout = inflater.inflate(R.layout.mediaitem_detail_dialog,
                (ViewGroup) findViewById(R.id.mediadetail_dialog_root));

        TextView mediaUri = (TextView) layout
                .findViewById(R.id.detail_complete_uri);
        mediaUri.setText(mediaItem.getMediaUri());

        if (null != mediaItem.getBootAddress()
                && null != mediaItem.getCompanyName()) {
            TextView bootAddressTitle = (TextView) layout
                    .findViewById(R.id.detail_vmx_address_title);
            bootAddressTitle.setVisibility(View.VISIBLE);

            TextView bootAddress = (TextView) layout
                    .findViewById(R.id.detail_vmx_address);
            bootAddress.setVisibility(View.VISIBLE);
            bootAddress.setText(mediaItem.getBootAddress());

            TextView companyNameTitle = (TextView) layout
                    .findViewById(R.id.detail_vmx_name_title);
            companyNameTitle.setVisibility(View.VISIBLE);

            TextView companyName = (TextView) layout
                    .findViewById(R.id.detail_vmx_name);
            companyName.setVisibility(View.VISIBLE);
            companyName.setText(mediaItem.getCompanyName());
        }

        DatabaseInfo dbInfo = mediaItem.getAssociatedDBInfo();
        if (null != dbInfo) {
            if (null != dbInfo.associatedSubtitleFile) {

                TextView associatedSubtitle = (TextView) layout
                        .findViewById(R.id.detail_associated_subtitle);

                File file = new File(dbInfo.associatedSubtitleFile);
                String text = file.getName();

                if (null != dbInfo.associatedTimedTextTrack) {
                    text = new String(text + " - "
                            + dbInfo.associatedTimedTextTrack);
                }
                associatedSubtitle.setText(text);
            }

            TextView lastPos = (TextView) layout
                    .findViewById(R.id.detail_resume_pos);
            ProgressBar progress = (ProgressBar) layout
                    .findViewById(R.id.detail_resume_pos_progress);

            if (dbInfo.lastPlaybackPosInMs > 0
                    && dbInfo.mediaDurationInMs > dbInfo.lastPlaybackPosInMs) {

                progress.setMax(dbInfo.mediaDurationInMs);
                progress.setProgress(dbInfo.lastPlaybackPosInMs);
                lastPos.setText(VOUtils
                        .convertTimeToText(dbInfo.lastPlaybackPosInMs));
            } else {
                progress.setVisibility(View.GONE);
                lastPos.setText("None");
            }

            if(dbInfo.DlStatus > 0) {
                LinearLayout DlLayout = (LinearLayout)layout.findViewById(R.id.detail_dl_layout);
                DlLayout.setVisibility(View.VISIBLE);

                TextView DlProgress = (TextView)layout.findViewById(R.id.detail_dl_progress);
                if(DatabaseInfo.DL_STATUS_FULLY_LOCAL == dbInfo.DlStatus) {
                    DlProgress.setText("Locally available");
                }
                else {
                    DlProgress.setText(((float)dbInfo.DLProgress / (float)dbInfo.mediaDurationInMs)*100 + " %");
                }
                TextView DlBitrate = (TextView)layout.findViewById(R.id.detail_dl_bitrate);
                DlBitrate.setText((dbInfo.DLBitrate / 1000) + " kbps");
            }

        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setView(layout);
        builder.setCancelable(true);
        builder.setPositiveButton(R.string.OK_text,
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        dialog.dismiss();
                    }
                });

        AlertDialog dialog = builder.create();
        dialog.show();
    }

    private void refreshMediaList() {

        mediaGroups.clear();
        mediaItems.clear();

        MediasMapperInterface mediaHolder = getRequiredMediaHolder();

        if (null != mediaHolder) {
            mediaHolder.refresh();
            Map<String, List<MediaItem>> mappedMediaItems = mediaHolder
                    .getMappedMedias();
            for (String mapKey : mappedMediaItems.keySet()) {
                if(! mapKey.equalsIgnoreCase(MediaTypeMapper.SUBTITLE_FILES_MAP_KEY)) {
                    mediaGroups.add(mapKey);
                    mediaItems.add(mappedMediaItems.get(mapKey));
                }
            }
        }
    }

    private List<MediaItem> findStreamingItemsMatchingMediaId(String mediaId) {
        ArrayList<MediaItem> foundMediaItems = new ArrayList<MediaItem>(0);
        for (List<MediaItem> subList : this.mediaItems) {
            for (MediaItem item : subList) {
                if (mediaId.equalsIgnoreCase(item.getMediaId())) {
                    foundMediaItems.add(item);
                }
            }
        }
        return foundMediaItems;
    }

    @Override
    public boolean onError(DownloaderWrapper downloader, int what, int extra) {

        Log.w(TAG, "onError " + downloader.getUri() + " " + what + " " + extra);
        switch (what) {
        case DownloadManager.DOWNLOADER_ERROR_NOMORESPACE:
            // TODO Stop download and display to user
            break;
        case DownloadManager.DOWNLOADER_ERROR_NETWORK_BROKEN:
            break;
        case DownloadManager.DOWNLOADER_ERROR_OFFLINE_NOT_ALLOWED:
            dismissDialog(PROCESSING_DL_DIALOG);
            //display a message
            Toast.makeText(getApplicationContext(), "Download offline key not allowed (ERROR)", Toast.LENGTH_SHORT).show();
            return false;
        }
        if (OngoingDLActionType.NONE != ongoingDownloadAction) {
            ongoingDownloadAction = OngoingDLActionType.NONE;
            resumeDlBitrate = 0;
            try {
                dismissDialog(PROCESSING_DL_DIALOG);
            } catch (IllegalArgumentException e) {
            }
        }
        displayDownloadErrorToast();
        DLMgr.releaseDownloaderForMediaId(downloader.getMediaId());
        return false;
    }

    @Override
    public boolean onInfo(DownloaderWrapper downloader, int what, int extra) {

        Log.d(TAG, "onInfo - " + what + " " + extra);
        switch (what) {
        case DownloadManager.DOWNLOADER_INFO_DOWNLOAD_COMPLETED:
            updateDlCompleted(downloader);
            break;

        case DownloadManager.DOWNLOADER_INFO_DOWNLOAD_PROGRESS:
            updateDlProgress(downloader);
            break;

        case DownloadManager.DOWNLOADER_INFO_LOWSPACE:
            // TODO Stop download and display to user
            Toast.makeText(getApplicationContext(), "Low storage space !!", Toast.LENGTH_SHORT).show();
            break;

        case DownloaderWrapper.DOWNLOADER_INFO_OFFLINE_KEYS_RENEWAL_STARTED:
            Toast.makeText(getApplicationContext(), "Starting key renewal", Toast.LENGTH_SHORT).show();
            break;

        case DownloaderWrapper.DOWNLOADER_INFO_OFFLINE_KEYS_RENEWAL_COMPLETED:
            Toast.makeText(getApplicationContext(), "Key renewal completed", Toast.LENGTH_SHORT).show();
            try {
                dismissDialog(PROCESSING_DL_DIALOG);
            } catch (IllegalArgumentException e) {
            }
            break;
        case DownloaderWrapper.DOWNLOADER_INFO_OFFLINE_NOT_ALLOWED:
            Toast.makeText(getApplicationContext(), "Offline key not allowed", Toast.LENGTH_SHORT).show();
            try {
                dismissDialog(PROCESSING_DL_DIALOG);
            } catch (IllegalArgumentException e) {
            }
            break;

        default:
            break;
        }
        return false;
    }

    @Override
    public void onPrepared(DownloaderWrapper downloader) {

        boolean result = false;
        switch (ongoingDownloadAction) {
            case GET_EXPIRATION:
                int nbQualities = downloader.getNbQualities();
                int selectedQualityId = -1;
                for (int i = 0; i < nbQualities; i++) {
                    if (resumeDlBitrate == downloader.getBitrateByIndex(i)) {
                        selectedQualityId = i;
                        break;
                    }
                }
                if (selectedQualityId >= 0) {
                    downloader.selectQualityByIndex(selectedQualityId);
                    int expires = downloader.getOfflineKeysExpiration();
                    Toast.makeText(getApplicationContext(), "expiration: " + expires, Toast.LENGTH_SHORT).show();
                }
                DLMgr.releaseDownloaderForMediaId(downloader.getMediaId());
                downloader = null;
                break;
            case RENEW_KEY:
                result = setupDownloaderToResumeDownload(downloader);
                if (result) {
                    downloader.renewOfflineKeys();
                    // ongoingDownloadAction will be set to "NONE" on callback (info or error)
                } else {
                    Toast.makeText(getApplicationContext(), "Impossible to renew keys", Toast.LENGTH_SHORT).show();
                }
                break;

            case RESUME:
                result = setupDownloaderToResumeDownload(downloader);
                if (result) {
                    resumeDlBitrate = 0;
                    ongoingDownloadAction = OngoingDLActionType.NONE;
                    try {
                        dismissDialog(PROCESSING_DL_DIALOG);
                    } catch (IllegalArgumentException e) { /* just to catch the exception in case the dialog box is not there (no side effect) */ }
                } else {
                    Toast.makeText(getApplicationContext(), "Impossible to resume download", Toast.LENGTH_SHORT).show();
                }
                break;

            case DELETE:
                String deletedMediaId = downloader.getMediaId();
                downloader.deleteData();

                // update download status in database
                MediaMetaInfoDB db = MediaMetaInfoDB.getInstance(getApplicationContext());

                DatabaseInfo dbInfo = db.getAssociatedDataForMedia(deletedMediaId);

                if (null != dbInfo) {
                    dbInfo.DlStatus = DatabaseInfo.DL_STATUS_NONE;
                    dbInfo.DLProgress = 0;
                    dbInfo.DlLocalServerUrl = null;
                    dbInfo.lastPlaybackPosInMs = 0;

                    db.setDbInfoForMedia(deletedMediaId, dbInfo);
                } else{
                    Log.e(TAG, "Database info should not be null at this point" + deletedMediaId);
                }

                updateListForDlDeleted(deletedMediaId);

                DLMgr.releaseDownloaderForMediaId(downloader.getMediaId());
                downloader = null;
                try {
                    dismissDialog(PROCESSING_DL_DIALOG);
                } catch (IllegalArgumentException e) { }
                ongoingDownloadAction = OngoingDLActionType.NONE;
                break;

        default:
            Log.w(TAG,
                    "recieved onPrepared event without any associated action...");
            break;
        }
    }

    /**
     * Selects the quality and starts the given downloader provided it matches the previously set "resumeDlBitrate"
     * @param downloader download to process
     * @return true if the operation went well, false otherwise (wrong downloader, no selected quality found)
     */
    private boolean setupDownloaderToResumeDownload(DownloaderWrapper downloader) {

        if(null == downloader) {
            Log.e(TAG, "selectQualityAndStartDownloader - downloader cannot be null!");
            return false;
        }

        int nbQualities = downloader.getNbQualities();
        int selectedQualityId = -1;
        for (int i = 0; i < nbQualities; i++) {
            if (resumeDlBitrate == downloader.getBitrateByIndex(i)) {
                selectedQualityId = i;
                break;
            }
        }
        if (selectedQualityId >= 0) {
            downloader.selectQualityByIndex(selectedQualityId);

            DatabaseInfo dbInfo = MediaMetaInfoDB.getInstance(getApplicationContext()).getAssociatedDataForMedia(downloader.getMediaId());
            if( null != dbInfo.DLSelectedSubtitles) {
                String[] subTracks = dbInfo.DLSelectedSubtitles.split(",");
                downloader.setSubtitleTracks(subTracks);
            }
            if(null != dbInfo.DLSelectedAudioTracks) {
                String[] audioTracks = dbInfo.DLSelectedAudioTracks.split(",");
                downloader.setAudioTracks(audioTracks);
            }
            if (OngoingDLActionType.RENEW_KEY != ongoingDownloadAction)
            {
                try {
                    downloader.start();
                } catch (UnsupportedOperationException e) {
                    e.printStackTrace();
                    return false;
                }
            }
            return true;
        } else {
            Log.w(TAG, "selectQualityAndStartDownloader - could not found selectedQuality for download with uri" + downloader.getUri());
            return false;
        }
    }

    private void updateListForDlDeleted(String mediaId) {
        List<MediaItem> matchItems = findStreamingItemsMatchingMediaId(mediaId);

        if (matchItems.size() > 0) {
            DatabaseInfo dbInfo;
            for (MediaItem i : matchItems) {
                dbInfo = i.getAssociatedDBInfo();
                if (null != dbInfo) {
                    dbInfo.DlStatus = DatabaseInfo.DL_STATUS_NONE;
                    dbInfo.DLProgress = 0;
                    dbInfo.DlLocalServerUrl = null;
                    dbInfo.DLBitrate = 0;
                    dbInfo.lastPlaybackPosInMs = 0;
                    i.setAssociatedDBInfo(dbInfo);
                }
            }
            listAdapter.notifyDataSetChanged();
        }
    }

    private void updateDlList() {
        MediaMetaInfoDB db = MediaMetaInfoDB.getInstance(getApplicationContext());

        for (List<MediaItem> subList : this.mediaItems) {
            for (MediaItem item : subList) {
                DatabaseInfo dbInfo = db.getAssociatedDataForMedia(item.getMediaId());
                item.setAssociatedDBInfo(dbInfo);
            }
        }
        listAdapter.notifyDataSetChanged();
    }

    private void updateDlCompleted(DownloaderWrapper downloader) {
        String updatedId = downloader.getMediaId();
        List<MediaItem> matchItems = findStreamingItemsMatchingMediaId(updatedId);

        if (matchItems.size() > 0) {

            MediaMetaInfoDB db = MediaMetaInfoDB.getInstance(getApplicationContext());
            DatabaseInfo dbInfo = db.getAssociatedDataForMedia(updatedId);
            for (MediaItem i : matchItems) {
                i.setAssociatedDBInfo(dbInfo);
            }
            listAdapter.notifyDataSetChanged();
        }
    }

    private void updateDlProgress(DownloaderWrapper downloader) {

        String updatedId = downloader.getMediaId();
        List<MediaItem> matchItems = findStreamingItemsMatchingMediaId(updatedId);

        Log.d(TAG, "updateDlProgress - for mediaId: " + updatedId);
        if (matchItems.size() > 0) {

            Log.d(TAG, "updateDlProgress - found " + matchItems.size()
                    + " items matching url: " + updatedId);

            MediaMetaInfoDB db = MediaMetaInfoDB.getInstance(getApplicationContext());
            DatabaseInfo dbInfo = db.getAssociatedDataForMedia(updatedId);

            for (MediaItem i : matchItems) {
                Log.d(TAG, "updateDlProgress for item: " + i.toString());
                if (i.getMediaType() != MediaType.HTTP_STREAMING_MEDIA
                        && i.getMediaType() != MediaType.HTTP_STREAMING_MEDIA_EBD) {
                    Log.d(TAG, "Wrong type, continue");
                    continue;
                }
                i.setAssociatedDBInfo(dbInfo);
            }
            listAdapter.notifyDataSetChanged();
        }
    }
}
