package com.uas.search.console.b2b.schedule.service.impl;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.uas.search.util.CollectionUtils;
import com.uas.search.util.StringUtils;

import com.uas.search.b2b.exception.SearchException;
import com.uas.search.console.b2b.schedule.model.TaskInformation;
import com.uas.search.console.b2b.schedule.model.TaskLog;
import com.uas.search.console.b2b.schedule.service.Executable;
import com.uas.search.console.b2b.schedule.service.TaskService;

/**
 * 管理定时任务
 * 
 * @author sunyj
 * @since 2016年12月19日 上午10:54:43
 */
@Service
public class TaskServiceImpl implements TaskService {

	/**
	 * 存储定时任务信息
	 */
	private List<TaskInformation> taskInformations = new ArrayList<>();

	/**
	 * 定时任务调度
	 */
	private ScheduledExecutorService scheduledExecutorService;

	/**
	 * 任务执行日志文件的路径
	 */
	private static final String LOG_DIR = System.getProperty("java.io.tmpdir");

	private Logger logger = LoggerFactory.getLogger(TaskServiceImpl.class);

	@Override
	public void newTask(TaskInformation taskInformation) {
		if (taskInformation == null || StringUtils.isEmpty(taskInformation.getTitle())
				|| taskInformation.getCommand() == null) {
			throw new NullPointerException();
		}
		if (containsTask(taskInformation)) {
			throw new SearchException("任务已存在：" + taskInformation);
		}
		taskInformations.add(taskInformation);
	}

	@Override
	public List<TaskInformation> delete(List<String> titles) {
		List<TaskInformation> result = new ArrayList<>();
		if (CollectionUtils.isEmpty(titles)) {
			return result;
		}
		if (!isStopped()) {
			stop();
		}
		for (String title : titles) {
			for (int i = taskInformations.size() - 1; i >= 0; i--) {
				TaskInformation taskInformation = taskInformations.get(i);
				if (taskInformation.getTitle().equalsIgnoreCase(title)) {
					taskInformations.remove(taskInformation);
					result.add(taskInformation);
				}
			}
		}
		if (!CollectionUtils.isEmpty(taskInformations)) {
			start();
		}
		return result;
	}

	@Override
	public List<TaskInformation> deleteAll() {
		if (!isStopped()) {
			stop();
		}
		List<TaskInformation> result = taskInformations;
		taskInformations = new ArrayList<>();
		return result;
	}

	/**
	 * 判断定时任务是否已经存在
	 * 
	 * @param taskInformation
	 * @return
	 */
	private boolean containsTask(TaskInformation taskInformation) {
		if (CollectionUtils.isEmpty(taskInformations)) {
			return false;
		}
		for (TaskInformation d : taskInformations) {
			if (taskInformation.equals(d)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 保存日志到本地文件
	 * 
	 * @param log
	 */
	private void saveLog(TaskLog log) {
		if (log == null) {
			throw new NullPointerException();
		}
		FileWriter fileWriter = null;
		try {
			String logFilePath = (LOG_DIR.endsWith(File.separator) ? LOG_DIR : LOG_DIR + "/")
					+ "search-b2b-task-log.log";
			fileWriter = new FileWriter(logFilePath, true);
			fileWriter.write(log.toJSONString() + "\n");
			fileWriter.flush();
			logger.info("Saved task log:" + log.toJSONString() + " to " + logFilePath + "\n");
		} catch (IOException e) {
			logger.error("", e);
		} finally {
			if (fileWriter != null) {
				try {
					fileWriter.close();
				} catch (IOException e) {
					logger.error("", e);
				}
			}
		}
	}

	@Override
	public List<TaskInformation> all() {
		return taskInformations;
	}

	@Override
	public String start() {
		String message = "";
		if (!isStopped()) {
			message = "已存在运行的定时任务";
			logger.error(message);
			return message;
		}
		if (!CollectionUtils.isEmpty(taskInformations)) {
			// 线程数为1，以免多个创建索引的任务互相影响，导致索引创建失败
			scheduledExecutorService = Executors.newScheduledThreadPool(1);
			for (TaskInformation taskInformation : taskInformations) {
				logger.info("New task: " + taskInformation);
				scheduledExecutorService.scheduleAtFixedRate(getCommand(taskInformation),
						taskInformation.getInitialDelay(), taskInformation.getPeriod(), TimeUnit.MILLISECONDS);
			}
			message = "已开启定时任务：" + taskInformations;
			logger.info(message + "\n");
			return message;
		} else {
			message = "定时任务为空";
			logger.error(message + "\n");
			return message;
		}
	}

	/**
	 * 获取任务需执行的命令
	 * 
	 * @param taskInformation
	 * @return
	 */
	private Runnable getCommand(final TaskInformation taskInformation) {
		return new Runnable() {
			@Override
			public void run() {
				try {
					logger.info("Task run...");
					Executable command = taskInformation.getCommand();
					String result = command.execute();
					saveLog(new TaskLog(taskInformation, new Date(), result));
				} catch (Exception e) {
					saveLog(new TaskLog(taskInformation, new Date(),
							"定时任务出错" + new SearchException(e).getDetailedMessage(e)));
				}
			}
		};
	}

	@Override
	public String stop() {
		String message = "";
		if (isStopped()) {
			message = "定时任务已经停止或者未开启过";
			logger.error(message);
			return message;
		}
		logger.info("Remove old tasks...");
		scheduledExecutorService.shutdownNow();
		message = "已关闭定时任务";
		logger.info(message + "\n");
		return message;
	}

	@Override
	public boolean isStopped() {
		if (scheduledExecutorService == null) {
			return true;
		}
		return scheduledExecutorService.isShutdown() || scheduledExecutorService.isTerminated();
	}
}
