package com.gh.download;

import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.support.v4.util.ArrayMap;
import android.widget.Toast;

import com.gh.common.constant.Constants;
import com.gh.common.util.FileUtils;
import com.gh.common.util.MD5Utils;
import com.gh.common.util.Utils;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.LinkedBlockingQueue;

public class DownloadManager {

	private static DownloadManager mInstance;

	private Context context;
	private Handler handler;

	private ArrayMap<String, Long> lastTimeMap;
	private ArrayMap<String, LinkedBlockingQueue<String>> platformMap;
	private ArrayMap<String, ArrayMap<String, DownloadEntity>> gameMap;
	private ArrayMap<String, String> statusMap;

	private DownloadManager(Context context) {
		this.context = context;

		lastTimeMap = new ArrayMap<>();
		platformMap = new ArrayMap<>();
		gameMap = new ArrayMap<>();
		statusMap = new ArrayMap<>();

		handler = new Handler(context.getMainLooper()){
			@Override
			public void handleMessage(Message msg) {
				if (msg.what == Constants.CONTINUE_DOWNLOAD_TASK) {
					String url = (String) msg.obj;
					if (System.currentTimeMillis() - lastTimeMap.get(url) >= 1000) {
						resume(url);
					}
				} else if (msg.what == Constants.PAUSE_DOWNLOAD_TASK) {
					String url = (String) msg.obj;
					if (System.currentTimeMillis() - lastTimeMap.get(url) >= 1000) {
						pause(url);
					}
				} else if (msg.what == Constants.DOWNLOAD_ROLL) {
					String name = (String) msg.obj;
					LinkedBlockingQueue<String> queue = platformMap.get(name);
					if (queue.size() > 1) {
						queue.offer(queue.poll());
						Message message = Message.obtain();
						message.obj = name;
						message.what = Constants.DOWNLOAD_ROLL;
						sendMessageDelayed(message, 3000);
					}
				}
			}
		};
		context.startService(new Intent(context, DownloadService.class));
	}

	public void put(String url, long time) {
		lastTimeMap.put(url, time);
	}

	public void putQueue(String name, LinkedBlockingQueue<String> queue) {
		platformMap.put(name, queue);
	}

	public LinkedBlockingQueue<String> getQueue(String name) {
		return platformMap.get(name);
	}

	public void removePlatform(String name, String platform) {
		LinkedBlockingQueue<String> queue = platformMap.get(name);
		if (queue != null) {
			queue.remove(platform);
			platformMap.put(name, queue);
		}
	}

	public void initGameMap() {
		gameMap.clear();
		List<DownloadEntity> list = DownloadManager.getInstance(context).getAll();
		if (list != null && list.size() != 0) {
			String name;
			for (DownloadEntity downloadEntity : list) {
				name = downloadEntity.getName();
				ArrayMap<String, DownloadEntity> map = gameMap.get(name);
				if (map == null) {
					map = new ArrayMap<>();
					gameMap.put(name, map);
				}
				map.put(downloadEntity.getPlatform(), downloadEntity);
			}
		}
	}

	public ArrayMap<String, DownloadEntity> getEntryMap(String name) {
		return gameMap.get(name);
	}

	public void putStatus(String url, String status) {
		statusMap.put(url, status);
	}

	public String getStatus(String url) {
		return statusMap.get(url);
	}

	public void sendMessageDelayed(Message msg, long delayMillis) {
		handler.sendMessageDelayed(msg, delayMillis);
	}

	public static DownloadManager getInstance(Context context) {
		if (mInstance == null) {
			mInstance = new DownloadManager(context.getApplicationContext());
		}
		return mInstance;
	}

	private Intent getIntent(DownloadEntity entry, DownloadStatus status) {
		Intent service = new Intent(context, DownloadService.class);
		service.putExtra(Constants.KEY_DOWNLOAD_ENTRY, entry);
		service.putExtra(Constants.KEY_DOWNLOAD_ACTION, status.name());
		return service;
	}

	/**
	 * 根据url到本地sqlite数据库中查找并获取该文件的保存路径， 并检查改路径下文件是否存在,不存在则删除该条无效记录
	 * 
	 * @param url 下载任务的标识url
	 */
	private boolean checkDownloadEntryRecordValidate(String url) {
		DownloadEntity entry = get(url);
		if (entry != null && ((int)entry.getPercent()) != 0) {
			File file = new File(entry.getPath());
			if (!file.exists()) {
				DownloadDao.getInstance(context).delete(url);
				Utils.log(DownloadManager.class.getSimpleName(), "文件不存在,删除该条无效数据库记录!");
				return true;
			}
		}
		return false;
	}

	/**
	 * 检查任务是否已经下载完成
	 * 
	 * @param url
	 * @return
	 */
	public boolean isFileCompleted(String url) {
		DownloadEntity entry = get(url);

		if (entry != null) {
			if (entry.getPercent() == 100) {
				Utils.log(DownloadManager.class.getSimpleName(), "文件已经下载完成!");
				return true;
			}
		}

		return false;
	}

	public boolean isTaskDownloading(String url) {
		if (DataChanger.getInstance().getDownloadingTasks().get(url) != null) {
			Utils.log(DownloadManager.class.getSimpleName(), url + "正在下载!");
			return true;
		}
		return false;
	}

	/**
	 * 添加一个下载任务
	 * 
	 * @param downloadEntity
	 */
	public void add(DownloadEntity downloadEntity) {
		if (downloadEntity != null) {
			String url = downloadEntity.getUrl();
			checkDownloadEntryRecordValidate(url);
			if (!isFileCompleted(url) && !isTaskDownloading(url)) {
				context.startService(getIntent(downloadEntity, DownloadStatus.add));
			}
		}
		Utils.log(DownloadManager.class.getSimpleName(), "add");
	}

	public static void createDownload(Context context,
	                                  GameEntity gameEntity,
	                                  String method,
	                                  String entrance,
	                                  String location) {
		createDownload(context, gameEntity.getApk().get(0), gameEntity, method, entrance, location);
	}

	public static void createDownload(Context context,
	                                  ApkEntity apkEntity,
	                                  GameEntity gameEntity,
	                                  String method,
	                                  String entrance,
	                                  String location) {

		DownloadEntity downloadEntity = new DownloadEntity();
		downloadEntity.setUrl(apkEntity.getUrl());
		downloadEntity.setName(gameEntity.getName());
		downloadEntity.setPath(FileUtils.getDownloadPath(context,
				MD5Utils.getContentMD5(gameEntity.getName() + "_" + System.currentTimeMillis()) + ".apk"));
		downloadEntity.setETag(apkEntity.getEtag());
		downloadEntity.setIcon(gameEntity.getIcon());
		downloadEntity.setPlatform(apkEntity.getPlatform());
		downloadEntity.setPackageName(apkEntity.getPackageName());
		downloadEntity.setGameId(gameEntity.getId());
		downloadEntity.setEntrance(entrance);
		downloadEntity.setLocation(location);
		if (method.equals("更新")) {
			downloadEntity.setUpdate(true);
		} else if (method.equals("插件化")) {
			downloadEntity.setPluggable(true);
		}
		downloadEntity.setPlugin(gameEntity.getTag() != null && gameEntity.getTag().size() != 0);
		DownloadManager.getInstance(context.getApplicationContext()).add(downloadEntity);
	}

	/**
	 * 根据任务url暂停下载
	 * 
	 * @param url
	 */
	public void pause(String url) {
		checkDownloadEntryRecordValidate(url);
		DownloadEntity entry = DataChanger.getInstance().getDownloadEntries()
				.get(url);
		if (entry != null) {
			context.startService(getIntent(entry, DownloadStatus.pause));
		}
		Utils.log(DownloadManager.class.getSimpleName(), "pause");
	}

	/**
	 * 根据url恢复下载
	 * 
	 * @param url
	 */
	public void resume(String url) {
		DownloadEntity entry = get(url);

		// 暂停任务后，把文件删除，然后点继续，文件不存在，需要重新加入下载队列进行下载
		if (checkDownloadEntryRecordValidate(url)) {
			Toast.makeText(context, "文件不存在！已重新加入下载队列", Toast.LENGTH_SHORT)
					.show();
			add(entry);
		} else {
			if (entry != null) {
				if (!isFileCompleted(url) && !isTaskDownloading(url)) {
					context.startService(getIntent(entry, DownloadStatus.resume));
				}
			}
		}
		Utils.log(DownloadManager.class.getSimpleName(), "resume");
	}

	/**
	 * 根据url取消下载，并删除已下载的文件
	 * 
	 * @param url
	 */
	public void cancel(String url) {
		cancel(url, true);
	}
	
	public void cancel(String url, boolean isDeleteFile) {
		DownloadEntity entry = DownloadDao.getInstance(context).get(url);
		if (entry != null) {
			if (isDeleteFile) {
				FileUtils.deleteFile(entry.getPath());
			}
			DownloadDao.getInstance(context).delete(url);
			Utils.log(DownloadManager.class.getSimpleName(), "cancle==>file and record were deleted!");
		}
		if (entry != null) {
			context.startService(getIntent(entry, DownloadStatus.cancel));
			Utils.log(DownloadManager.class.getSimpleName(), "cancel");
		}
	}

	/**
	 * 取消并删除所有下载任务(包括下载中、等待、暂停状态的任务)
	 */
	public void cancleAll() {
		for (Entry<String, DownloadEntity> entry : DataChanger.getInstance()
				.getDownloadEntries().entrySet()) {
			cancel(entry.getValue().getUrl(), true);
		}
		Utils.log(DownloadManager.class.getSimpleName(), "cancel all");
	}

	/**
	 * 开始所有下载任务
	 */
	public void startAll() {
		for (Entry<String, DownloadEntity> entry : DataChanger.getInstance()
				.getDownloadEntries().entrySet()) {
			add(entry.getValue());
		}
		Utils.log(DownloadManager.class.getSimpleName(), "start all");
	}

	/**
	 * 暂停所有正在下载的任务
	 */
	public void pauseAll() {
		for (Entry<String, DownloadEntity> entry : DataChanger.getInstance().getDownloadEntries().entrySet()) {
			if (entry.getValue().getStatus() == DownloadStatus.downloading) {
				pause(entry.getValue().getUrl());
			}
		}
		Utils.log(DownloadManager.class.getSimpleName(), "pause all");
	}

	/**
	 * 根据url获取某一个下载任务
	 * 
	 * @param url
	 * @return null表示下载列表中不存在该任务，否则返回下载任务
	 */
	public DownloadEntity get(String url) {
		return DownloadDao.getInstance(context).get(url);
	}

	/**
	 * 获取所有下载列表中的任务
	 * 
	 * @return null表示没有下载任务
	 */
	public List<DownloadEntity> getAll() {
		Utils.log(DownloadManager.class.getSimpleName(), "getAll");
		return DownloadDao.getInstance(context).getAll();
	}

	/**
	 * 检查数据库中当前是下载状态，但并未在下载进程中的下载数据
	 */
	public void checkAll() {
		List<String> urlList = new ArrayList<>();
		for (Entry<String, DownloadTask> entry : DataChanger.getInstance()
				.getDownloadingTasks().entrySet()) {
			urlList.add(entry.getValue().getEntry().getUrl());
		}
		for (DownloadEntity downloadEntity : getAll()) {
			if (!urlList.contains(downloadEntity.getUrl())
					&& downloadEntity.getStatus().equals(DownloadStatus.downloading)) {
				downloadEntity.setStatus(DownloadStatus.pause);
				DownloadDao.getInstance(context).newOrUpdate(downloadEntity);
				DataChanger.getInstance().notifyDataChanged(downloadEntity);
			}
		}
	}

	public void addObserver(DataWatcher dataWatcher) {
		DataChanger.getInstance().addObserver(dataWatcher);
		Utils.log(DownloadManager.class.getSimpleName(), "addObserver");
	}

	public void removeObserver(DataWatcher dataWatcher) {
		DataChanger.getInstance().deleteObserver(dataWatcher);
		Utils.log(DownloadManager.class.getSimpleName(), "removeObserver");
	}

	public void removeObservers() {
		DataChanger.getInstance().deleteObservers();
		Utils.log(DownloadManager.class.getSimpleName(), "removeObserver");
	}

}
