package com.media.cache;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkRequest;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;

import com.android.baselib.MediaSDKReceiver;
import com.android.baselib.NetworkCallbackImpl;
import com.android.baselib.NetworkListener;
import com.android.baselib.utils.LogUtils;
import com.media.cache.download.BaseVideoDownloadTask;
import com.media.cache.download.M3U8VideoDownloadTask;
import com.media.cache.download.VideoDownloadTask;
import com.media.cache.hls.M3U8;
import com.media.cache.listener.IDownloadInfosCallback;
import com.media.cache.listener.IDownloadListener;
import com.media.cache.listener.IVideoInfoCallback;
import com.media.cache.listener.IVideoInfoParseCallback;
import com.media.cache.listener.IDownloadTaskListener;
import com.media.cache.model.Video;
import com.media.cache.model.VideoCacheInfo;
import com.media.cache.model.VideoTaskItem;
import com.media.cache.model.VideoTaskState;
import com.media.cache.proxy.AsyncProxyServer;
import com.media.cache.utils.DownloadExceptionUtils;
import com.media.cache.utils.LocalProxyUtils;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

public class VideoDownloadManager {

    private static final int MSG_DOWNLOAD_DEFAULT = 0;
    private static final int MSG_DOWNLOAD_PENDING = 1;
    private static final int MSG_DOWNLOAD_PREPARE = 2;
    private static final int MSG_DOWNLOAD_START = 3;
    private static final int MSG_DOWNLOAD_PROXY_READY = 4;
    private static final int MSG_DOWNLOAD_PROCESSING = 5;
    private static final int MSG_DOWNLOAD_SPEED = 6;
    private static final int MSG_DOWNLOAD_PAUSE = 7;
    private static final int MSG_DOWNLOAD_SUCCESS = 8;
    private static final int MSG_DOWNLOAD_ERROR = 9;
    private static final int MSG_DOWNLOAD_PROXY_FORBIDDEN = 10;

    private static final int MSG_DOWNLOAD_INFOS = 100;

    private static final long VIDEO_PROXY_CACHE_SIZE = 2 * 1024 * 1024 * 1024L;
    private static final int READ_TIMEOUT = 30 * 1000;
    private static final int CONN_TIMEOUT = 30 * 1000;
    private static final int SOCKET_TIMEOUT = 60 * 1000;
    private static final int CONCURRENT_COUNT = 2;

    private static VideoDownloadManager sInstance = null;
    private LocalProxyConfig mConfig;
    private VideoDownloadQueue mVideoDownloadQueue;
    private Handler mDownloadHandler = new DownloadHandler();
    private IDownloadListener mGlobalDownloadListener;
    private List<VideoTaskItem> mDownloadList = new CopyOnWriteArrayList<>();
    private List<IDownloadInfosCallback> mDownloadInfoCallbacks = new CopyOnWriteArrayList<>();
    private Map<String, VideoDownloadTask> mVideoDownloadTaskMap = new ConcurrentHashMap<>();
    private Map<String, IDownloadListener> mDownloadListenerMap = new ConcurrentHashMap<>();

    public static VideoDownloadManager getInstance() {
        if (sInstance == null) {
            synchronized (VideoDownloadManager.class) {
                if (sInstance == null) {
                    sInstance = new VideoDownloadManager();
                }
            }
        }
        return sInstance;
    }

    private VideoDownloadManager() {
        mVideoDownloadQueue = new VideoDownloadQueue();
    }

    public LocalProxyConfig downloadConfig() { return mConfig; }

    public void initConfig(LocalProxyConfig config) {
        if (config == null)
            return;
        mConfig = config;
        new AsyncProxyServer(mConfig);
        VideoInfoParserManager.getInstance().initConfig(config);
        registerReceiver(mConfig.getContext());
    }

    public void registerReceiver(Context context) {
        MediaSDKReceiver receiver = new MediaSDKReceiver();
        context.registerReceiver(receiver, new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE"));
    }

    @SuppressLint("NewApi")
    @SuppressWarnings({"MissingPermission"})
    private void registerConnectionListener(Context context) {
        NetworkCallbackImpl networkCallback = new NetworkCallbackImpl(mNetworkListener);
        NetworkRequest request = new NetworkRequest.Builder().build();
        ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (manager != null) {
            manager.registerNetworkCallback(request, networkCallback);
        }
    }

    public String getCacheFilePath() {
        if (mConfig != null) {
            return mConfig.getCacheRoot().getAbsolutePath();
        }
        return null;
    }

    public VideoDownloadManager(LocalProxyConfig config) {
        new AsyncProxyServer(config);
        mConfig = config;
    }

    //1.DOWNLOAD MODULE
    //-----------------------------------------------------------------------
    //-------------------------DOWNLOAD MODULE-------------------------------
    //-----------------------------------------------------------------------
    public void fetchDownloadItems(IDownloadInfosCallback callback) {
        mDownloadInfoCallbacks.add(callback);
    }

    public void removeDownloadInfosCallback(IDownloadInfosCallback callback) {
        mDownloadInfoCallbacks.remove(callback);
    }

    public void setGlobalDownloadListener(IDownloadListener listener) {
        mGlobalDownloadListener = listener;
    }

    public void startDownload(VideoTaskItem taskItem) {
        if (taskItem == null || TextUtils.isEmpty(taskItem.getUrl()) || taskItem.getUrl().startsWith("http://127.0.0.1"))
            return;

        if (mVideoDownloadQueue.contains(taskItem)) {
            taskItem = mVideoDownloadQueue.getTaskItem(taskItem.getUrl());
        } else {
            mVideoDownloadQueue.offer(taskItem);
        }
        taskItem.setTaskState(VideoTaskState.PENDING);
        mDownloadHandler.obtainMessage(MSG_DOWNLOAD_PENDING, taskItem).sendToTarget();

        if (mVideoDownloadQueue.getDownloadingCount() < mConfig.getConcurrentCount()) {
            startDownload(taskItem, null);
        }
    }

    public void startDownload(VideoTaskItem taskItem, HashMap<String, String> headers) {
        if (taskItem == null || TextUtils.isEmpty(taskItem.getUrl()) || taskItem.getUrl().startsWith("http://127.0.0.1"))
            return;
        taskItem.setTaskState(VideoTaskState.PREPARE);
        mDownloadHandler.obtainMessage(MSG_DOWNLOAD_PREPARE, taskItem).sendToTarget();
        parseVideoInfo(taskItem, headers);
    }

    public void removeDownloadQueue(VideoTaskItem item) {
        mVideoDownloadQueue.remove(item);
        while(mVideoDownloadQueue.getDownloadingCount() < mConfig.getConcurrentCount() ) {
            if (mVideoDownloadQueue.getDownloadingCount() == mVideoDownloadQueue.size())
                break;
            VideoTaskItem item1 = mVideoDownloadQueue.peekPendingTask();
            startDownload(item1, null);
        }

    }

    //Delete one task
    public void deleteVideoTask(VideoTaskItem taskItem) {
        String cacheFilePath = getCacheFilePath();
        if (!TextUtils.isEmpty(cacheFilePath)) {
            if (taskItem.isRunningTask()) {
                pauseDownloadTask(taskItem);
            }
            String saveName = LocalProxyUtils.computeMD5(taskItem.getUrl());
            File file = new File(cacheFilePath + File.separator + saveName);
            LocalProxyUtils.deleteCacheFile(file);
            taskItem.setTaskState(VideoTaskState.DEFAULT);
            mDownloadHandler.obtainMessage(MSG_DOWNLOAD_DEFAULT, taskItem).sendToTarget();
        }
    }

    public void deleteVideoTasks(VideoTaskItem[] taskItems) {
        String cacheFilePath = getCacheFilePath();
        if (!TextUtils.isEmpty(cacheFilePath)) {
            for (VideoTaskItem item : taskItems) {
                deleteVideoTask(item);
            }
        }
    }

    //Delete all files
    public void deleteAllVideoFiles(Context context) {
        try {
            LocalProxyUtils.clearVideoCacheDir(context);
        } catch (Exception e) {
            LogUtils.w("clearVideoCacheDir failed, exception = " + e.getMessage());
        }
    }

    //Pause all download task
    public void pauseDownloadTasks(VideoTaskItem[] taskItems) {
        for (VideoTaskItem item : taskItems) {
            if (item.isRunningTask()) {
                pauseDownloadTask(item);
            }
        }
    }
    //-----------------------------------------------------------------------
    //-------------------------DOWNLOAD MODULE-------------------------------
    //-----------------------------------------------------------------------


    //2.PLAY MODULE
    //-----------------------------------------------------------------------
    //-----------------------------PLAY MODULE-------------------------------
    //-----------------------------------------------------------------------
    public void startPlayCacheTask(VideoTaskItem taskItem, IDownloadListener listener) {
        if (taskItem == null || TextUtils.isEmpty(taskItem.getUrl()) || taskItem.getUrl().startsWith("http://127.0.0.1"))
            return;

        startPlayCacheTask(taskItem, null, listener);
    }

    public void startPlayCacheTask(VideoTaskItem taskItem, HashMap<String, String> headers, IDownloadListener listener) {
        if (taskItem == null || TextUtils.isEmpty(taskItem.getUrl()) || taskItem.getUrl().startsWith("http://127.0.0.1"))
            return;
        addCallback(taskItem.getUrl(), listener);
        taskItem.setTaskState(VideoTaskState.PREPARE);
        mDownloadHandler.obtainMessage(MSG_DOWNLOAD_PREPARE, taskItem).sendToTarget();
        parseVideoInfo(taskItem, headers);
    }
    //-----------------------------------------------------------------------
    //-----------------------------PLAY MODULE-------------------------------
    //-----------------------------------------------------------------------


    private void parseVideoInfo(VideoTaskItem taskItem, final HashMap<String, String> headers) {
        String videoUrl = taskItem.getUrl();
        String saveName = LocalProxyUtils.computeMD5(videoUrl);
        VideoCacheInfo cacheInfo = LocalProxyUtils.readProxyCacheInfo(new File(mConfig.getCacheRoot(), saveName));
        if (cacheInfo != null) {
            LogUtils.w("parseVideoInfo info = " + cacheInfo);
            if (taskItem.isDownloadMode()) {
                long createTime = cacheInfo.getDownloadTime();
                if (createTime == 0L) {
                    createTime = System.currentTimeMillis();
                    cacheInfo.setDownloadTime(createTime);
                    taskItem.setDownloadTime(createTime);
                } else {
                    taskItem.setDownloadTime(createTime);
                }
            }

            if (cacheInfo.getVideoType() == Video.Type.MP4_TYPE
                    || cacheInfo.getVideoType() == Video.Type.WEBM_TYPE
                    || cacheInfo.getVideoType() == Video.Type.QUICKTIME_TYPE
                    || cacheInfo.getVideoType() == Video.Type.GP3_TYPE) {
                startBaseVideoDownloadTask(taskItem, cacheInfo, headers);
            } else if (cacheInfo.getVideoType() == Video.Type.HLS_TYPE) {
                VideoInfoParserManager.getInstance()
                        .parseM3U8File(cacheInfo, new IVideoInfoParseCallback() {

                            @Override
                            public void onM3U8FileParseSuccess(VideoCacheInfo info, M3U8 m3u8) {
                                startM3U8VideoDownloadTask(taskItem, info, m3u8, headers);
                            }

                            @Override
                            public void onM3U8FileParseFailed(VideoCacheInfo info, Throwable error) {
                                parseVideoInfo(taskItem, info, headers);
                            }
                        });
            }
        } else {
            cacheInfo = new VideoCacheInfo(videoUrl);
            cacheInfo.setTaskMode(taskItem.getTaskMode());
            if (taskItem.isDownloadMode()) {
                long createTime = System.currentTimeMillis();
                cacheInfo.setDownloadTime(createTime);
                taskItem.setDownloadTime(createTime);
            }
            parseVideoInfo(taskItem, cacheInfo, headers);
        }
    }

    private void parseVideoInfo(VideoTaskItem taskItem, final VideoCacheInfo cacheInfo, final HashMap<String, String> headers) {
        VideoInfoParserManager.getInstance().parseVideoInfo(cacheInfo, new IVideoInfoCallback() {
            @Override
            public void onFinalUrl(String finalUrl) {
                //Get final url by redirecting.
            }

            @Override
            public void onBaseVideoInfoSuccess(VideoCacheInfo cacheInfo) {
                startBaseVideoDownloadTask(taskItem, cacheInfo, headers);
            }

            @Override
            public void onBaseVideoInfoFailed(Throwable error) {
                LogUtils.w("onInfoFailed error=" +error);
                int errorCode = DownloadExceptionUtils.getErrorCode(error);
                taskItem.setErrorCode(errorCode);
                taskItem.setTaskState(VideoTaskState.ERROR);
                mDownloadHandler.obtainMessage(MSG_DOWNLOAD_PROXY_FORBIDDEN, taskItem).sendToTarget();
            }

            @Override
            public void onM3U8InfoSuccess(VideoCacheInfo cacheInfo, M3U8 m3u8) {
                startM3U8VideoDownloadTask(taskItem, cacheInfo, m3u8, headers);
            }

            @Override
            public void onLiveM3U8Callback(VideoCacheInfo info) {
                LogUtils.i("onLiveM3U8Callback cannot be cached.");
                taskItem.setTaskState(VideoTaskState.ERROR);
                mDownloadHandler.obtainMessage(MSG_DOWNLOAD_PROXY_FORBIDDEN, taskItem).sendToTarget();
            }

            @Override
            public void onM3U8InfoFailed(Throwable error) {
                LogUtils.w("onM3U8InfoFailed : " + error);
                int errorCode = DownloadExceptionUtils.getErrorCode(error);
                taskItem.setErrorCode(errorCode);
                taskItem.setTaskState(VideoTaskState.ERROR);
                mDownloadHandler.obtainMessage(MSG_DOWNLOAD_PROXY_FORBIDDEN, taskItem).sendToTarget();
            }
        }, headers);
    }

    public void startBaseVideoDownloadTask(VideoTaskItem taskItem,
                                           VideoCacheInfo cacheInfo,
                                           HashMap<String, String> headers) {
        taskItem.setVideoType(cacheInfo.getVideoType());
        VideoDownloadTask downloadTask = null;
        if (!mVideoDownloadTaskMap.containsKey(cacheInfo.getUrl())) {
            downloadTask = new BaseVideoDownloadTask(mConfig, cacheInfo, headers);
            mVideoDownloadTaskMap.put(cacheInfo.getUrl(), downloadTask);
        } else {
            downloadTask = mVideoDownloadTaskMap.get(cacheInfo.getUrl());
        }

        if (downloadTask != null) {
            downloadTask.startDownload(
                    new IDownloadTaskListener() {

                        @Override
                        public void onTaskStart(String url) {
                            taskItem.setTaskState(VideoTaskState.START);
                            mDownloadHandler.obtainMessage(MSG_DOWNLOAD_START, taskItem).sendToTarget();
                        }

                        @Override
                        public void onLocalProxyReady(String proxyUrl) {
                            taskItem.setProxyUrl(proxyUrl);
                            taskItem.setTaskState(VideoTaskState.PROXYREADY);
                            mDownloadHandler.obtainMessage(MSG_DOWNLOAD_PROXY_READY, taskItem).sendToTarget();
                        }

                        @Override
                        public void onTaskProgress(float percent, long cachedSize, M3U8 m3u8) {
                            if (taskItem.getTaskState() == VideoTaskState.PAUSE || taskItem.getTaskState() == VideoTaskState.SUCCESS) {
                                LogUtils.d("litianpeng taskItem state="+taskItem.getTaskState());
                            } else {
                                taskItem.setTaskState(VideoTaskState.DOWNLOADING);
                                taskItem.setPercent(percent);
                                taskItem.setDownloadSize(cachedSize);
                                taskItem.setM3U8(m3u8);
                                mDownloadHandler.obtainMessage(MSG_DOWNLOAD_PROCESSING, taskItem).sendToTarget();
                            }
                        }

                        @Override
                        public void onTaskSpeedChanged(float speed) {
                            taskItem.setSpeed(speed);
                            mDownloadHandler.obtainMessage(MSG_DOWNLOAD_SPEED, taskItem).sendToTarget();
                        }

                        @Override
                        public void onTaskPaused() {
                            taskItem.setTaskState(VideoTaskState.PAUSE);
                            mDownloadHandler.obtainMessage(MSG_DOWNLOAD_PAUSE, taskItem).sendToTarget();
                        }

                        @Override
                        public void onTaskFinished(long totalSize) {
                            taskItem.setTaskState(VideoTaskState.SUCCESS);
                            taskItem.setDownloadSize(totalSize);
                            taskItem.setPercent(100f);
                            mDownloadHandler.obtainMessage(MSG_DOWNLOAD_SUCCESS, taskItem).sendToTarget();
                        }

                        @Override
                        public void onTaskFailed(Throwable e) {
                            int errorCode = DownloadExceptionUtils.getErrorCode(e);
                            taskItem.setErrorCode(errorCode);
                            taskItem.setTaskState(VideoTaskState.ERROR);
                            mDownloadHandler.obtainMessage(MSG_DOWNLOAD_ERROR, taskItem).sendToTarget();
                        }
                    });
        }

    }

    public void startM3U8VideoDownloadTask(VideoTaskItem taskItem,
                                           VideoCacheInfo cacheInfo,
                                           M3U8 m3u8,
                                           HashMap<String, String> headers) {
        taskItem.setVideoType(cacheInfo.getVideoType());
        VideoDownloadTask downloadTask = null;
        if (!mVideoDownloadTaskMap.containsKey(cacheInfo.getUrl())) {
            downloadTask = new M3U8VideoDownloadTask(mConfig, cacheInfo, m3u8, headers);
            mVideoDownloadTaskMap.put(cacheInfo.getUrl(), downloadTask);
        } else {
            downloadTask = mVideoDownloadTaskMap.get(cacheInfo.getUrl());
        }

        if (downloadTask != null) {
            downloadTask.startDownload(
                    new IDownloadTaskListener() {
                        @Override
                        public void onTaskStart(String url) {
                            taskItem.setTaskState(VideoTaskState.START);
                            mDownloadHandler.obtainMessage(MSG_DOWNLOAD_START, taskItem).sendToTarget();
                        }

                        @Override
                        public void onLocalProxyReady(String proxyUrl) {
                            taskItem.setProxyUrl(proxyUrl);
                            taskItem.setTaskState(VideoTaskState.PROXYREADY);
                            mDownloadHandler.obtainMessage(MSG_DOWNLOAD_PROXY_READY, taskItem).sendToTarget();
                        }

                        @Override
                        public void onTaskProgress(float percent, long cachedSize, M3U8 m3u8) {
                            if (taskItem.getTaskState() == VideoTaskState.PAUSE || taskItem.getTaskState() == VideoTaskState.SUCCESS) {

                            } else {
                                taskItem.setTaskState(VideoTaskState.DOWNLOADING);
                                taskItem.setPercent(percent);
                                taskItem.setDownloadSize(cachedSize);
                                taskItem.setM3U8(m3u8);
                                mDownloadHandler.obtainMessage(MSG_DOWNLOAD_PROCESSING, taskItem).sendToTarget();
                            }
                        }

                        @Override
                        public void onTaskSpeedChanged(float speed) {
                            taskItem.setSpeed(speed);
                            mDownloadHandler.obtainMessage(MSG_DOWNLOAD_SPEED, taskItem).sendToTarget();
                        }

                        @Override
                        public void onTaskPaused() {
                            taskItem.setTaskState(VideoTaskState.PAUSE);
                            mDownloadHandler.obtainMessage(MSG_DOWNLOAD_PAUSE, taskItem).sendToTarget();
                        }

                        @Override
                        public void onTaskFinished(long totalSize) {
                            taskItem.setTaskState(VideoTaskState.SUCCESS);
                            taskItem.setPercent(100f);
                            taskItem.setDownloadSize(totalSize);
                            mDownloadHandler.obtainMessage(MSG_DOWNLOAD_SUCCESS, taskItem).sendToTarget();
                        }

                        @Override
                        public void onTaskFailed(Throwable e) {
                            int errorCode = DownloadExceptionUtils.getErrorCode(e);
                            taskItem.setErrorCode(errorCode);
                            taskItem.setTaskState(VideoTaskState.ERROR);
                            mDownloadHandler.obtainMessage(MSG_DOWNLOAD_ERROR, taskItem).sendToTarget();
                        }
                    });
        }

    }

    public void seekToDownloadTask(long curPosition, long totalDuration, String url) {
        VideoDownloadTask task = mVideoDownloadTaskMap.get(url);
        if (task != null) {
            task.seekToDownload(curPosition, totalDuration);
        }
    }

    public void seekToDownloadTask(float seekPercent, String url) {
        VideoDownloadTask task = mVideoDownloadTaskMap.get(url);
        if (task != null) {
            task.seekToDownload(seekPercent);
        }
    }

    public void resumeDownloadTask(VideoTaskItem taskItem, IDownloadListener listener) {
        if (taskItem == null || TextUtils.isEmpty(taskItem.getUrl()))
            return;
        String url = taskItem.getUrl();
        VideoDownloadTask task = mVideoDownloadTaskMap.get(url);
        if (task != null) {
            task.resumeDownload();
            addCallback(url, listener);
        }
    }

    public void pauseDownloadTask(VideoTaskItem taskItem) {
        if (taskItem == null || TextUtils.isEmpty(taskItem.getUrl()))
            return;
        String url = taskItem.getUrl();
        VideoDownloadTask task = mVideoDownloadTaskMap.get(url);
        if (task != null) {
            task.pauseDownload();
        }
    }

    public void stopDownloadTask(VideoTaskItem taskItem) {
        if (taskItem == null || TextUtils.isEmpty(taskItem.getUrl()))
            return;
        String url = taskItem.getUrl();
        VideoDownloadTask task = mVideoDownloadTaskMap.get(url);
        if (task != null) {
            task.stopDownload();
            mVideoDownloadTaskMap.remove(url);
            removeCallback(url);
        }
    }

    public void addCallback(String url, IDownloadListener listener){
        if (TextUtils.isEmpty(url))
            return;
        mDownloadListenerMap.put(url, listener);
        LogUtils.w("litianpeng addCallback listener="+listener + "");
    }

    public void removeCallback(String url){
        if (TextUtils.isEmpty(url))
            return;
        mDownloadListenerMap.remove(url);
    }

    class DownloadHandler extends Handler {

        public DownloadHandler() {
            super(Looper.getMainLooper());
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == MSG_DOWNLOAD_INFOS) {
                dispatchDownloadInfos(msg.what, msg.obj);
            } else {
                dispatchVideoCacheState(msg.what, msg.obj);
            }
        }

        private void dispatchDownloadInfos(int msg, Object obj) {

        }

        private void dispatchVideoCacheState(int msg, Object obj) {
            VideoTaskItem item = (VideoTaskItem)obj;
//            if (item.isPlayMode()) {
                IDownloadListener listener = mDownloadListenerMap.containsKey(item.getUrl()) ?
                        mDownloadListenerMap.get(item.getUrl()) : null;
                handleMessage(msg, item, listener);
//            } else if (item.isDownloadMode()) {
                handleMessage(msg, item, mGlobalDownloadListener);
//            }
        }

        private void handleMessage(int msg, VideoTaskItem item, IDownloadListener listener) {
            if (listener != null) {
                switch (msg) {
                    case MSG_DOWNLOAD_DEFAULT:
                        listener.onDownloadDefault(item);
                        break;
                    case MSG_DOWNLOAD_PENDING:
                        listener.onDownloadPending(item);
                        break;
                    case MSG_DOWNLOAD_PREPARE:
                        listener.onDownloadPrepare(item);
                        break;
                    case MSG_DOWNLOAD_START:
                        listener.onDownloadStart(item);
                        break;
                    case MSG_DOWNLOAD_PROXY_READY:
                        listener.onDownloadProxyReady(item);
                        break;
                    case MSG_DOWNLOAD_PROCESSING:
                        listener.onDownloadProgress(item);
                        break;
                    case MSG_DOWNLOAD_SPEED:
                        listener.onDownloadSpeed(item);
                        break;
                    case MSG_DOWNLOAD_PAUSE:
                        removeDownloadQueue(item);
                        listener.onDownloadPause(item);
                        break;
                    case MSG_DOWNLOAD_PROXY_FORBIDDEN:
                        removeDownloadQueue(item);
                        listener.onDownloadProxyForbidden(item);
                        break;
                    case MSG_DOWNLOAD_ERROR:
                        removeDownloadQueue(item);
                        listener.onDownloadError(item);
                        break;
                    case MSG_DOWNLOAD_SUCCESS:
                        removeDownloadQueue(item);
                        listener.onDownloadSuccess(item);
                        break;
                }
            }
        }
    }

    private NetworkListener mNetworkListener = new NetworkListener() {
        @Override
        public void onAvailable() {
            LogUtils.e("onAvailable");
        }

        @Override
        public void onWifiConnected() {
            LogUtils.e("onWifiConnected");
        }

        @Override
        public void onMobileConnected() {
            LogUtils.e("onMobileConnected");
        }

        @Override
        public void onNetworkType() {
            LogUtils.e("onNetworkType");
        }

        @Override
        public void onUnConnected() {
            LogUtils.e("onUnConnected");
        }
    };

    public static class Build {
        private Context mContext;
        private File mCacheRoot;
        private long mCacheSize = 2 * 1024 * 1024 * 1024L;  // Default 2G.
        private int mReadTimeOut = 30 * 1000;    // 30 seconds
        private int mConnTimeOut = 30 * 1000;    // 30 seconds
        private int mSocketTimeOut = 60 * 1000; // 60 seconds
        private boolean mRedirect = false;
        private boolean mIgnoreAllCertErrors = false;
        private int mConcurrentCount = 3;
        private int mPort;
        private boolean mFlowControlEnable = false; // true: control flow; false: no control
        private long mMaxBufferSize = 20 * 1024 * 1024L;  // 20M
        private long mMinBufferSize = 10 * 1024 * 1024L;  // 10M

        public Build(Context context) {
            mContext = context;
        }

        public Build setCacheRoot(File cacheRoot) {
            mCacheRoot = cacheRoot;
            return this;
        }

        public Build setCacheSize(long cacheSize) {
            mCacheSize = cacheSize;
            return this;
        }

        public Build setTimeOut(int readTimeOut, int connTimeOut, int socketTimeOut) {
            mReadTimeOut = readTimeOut;
            mConnTimeOut = connTimeOut;
            mSocketTimeOut = socketTimeOut;
            return this;
        }

        public Build setUrlRedirect(boolean redirect) {
            mRedirect = redirect;
            return this;
        }

        public Build setConcurrentCount(int count) {
            mConcurrentCount = count;
            return this;
        }

        public Build setIgnoreAllCertErrors(boolean ignoreAllCertErrors) {
            mIgnoreAllCertErrors = ignoreAllCertErrors;
            return this;
        }

        public Build setPort(int port) {
            mPort = port;
            return this;
        }

        //You can set enable=true to control flow.
        public Build setFlowControlEnable(boolean enable) {
            mFlowControlEnable = enable;
            return this;
        }

        //You can set maxBufferSize and minBufferSize when in mobile state.
        public Build setBufferSize(long maxBufferSize, long minBufferSize) {
            mMaxBufferSize = maxBufferSize;
            mMinBufferSize = minBufferSize;
            return this;
        }

        public VideoDownloadManager build() {
            return new VideoDownloadManager(buildConfig());
        }

        public LocalProxyConfig buildConfig() {
            return new LocalProxyConfig(mContext, mCacheRoot, mCacheSize,
                    mReadTimeOut, mConnTimeOut, mSocketTimeOut, mRedirect,
                    mIgnoreAllCertErrors, mPort, mFlowControlEnable,
                    mMaxBufferSize, mMinBufferSize, mConcurrentCount);
        }
    }

    public void setIgnoreAllCertErrors(boolean enable) {
        if (mConfig != null) {
            mConfig.setIgnoreAllCertErrors(enable);
        }
    }

    public void setConcurrentCount(int count) {
        if (mConfig != null) {
            mConfig.setConcurrentCount(count);
        }
    }

}