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

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.uas.search.b2b.model.SPage;
import com.uas.search.b2b.service.SearchService.Table_name;
import com.uas.search.console.b2b.core.util.ContextUtils;
import com.uas.search.console.b2b.jms.AQListener;
import com.uas.search.console.b2b.schedule.model.DailyTaskInformation;
import com.uas.search.console.b2b.schedule.service.Executable;
import com.uas.search.console.b2b.schedule.service.TaskService;
import com.uas.search.console.b2b.service.IndexService;
import com.uas.search.console.b2b.service.InnerSearchService;
import com.uas.search.console.b2b.service.UpdateVirtualColumnService;
import com.uas.search.console.b2b.util.ClassAndTableNameUtils;
import com.uas.search.console.b2b.util.SearchUtils;

/**
 * @author sunyj
 * @since 2016年12月12日 下午5:40:42
 */
@Service
public class UpdateVirtualColumnServiceImpl implements UpdateVirtualColumnService {

	/**
	 * 默认的页码
	 */
	private static final int PAGE_INDEX = 1;

	/**
	 * 默认每页的大小
	 */
	private static final int PAGE_SIZE = 1000;

	@Autowired
	private TaskService taskService;

	@Autowired
	private IndexService indexService;

	@Autowired
	private AQListener aqListener;

	private InnerSearchService innerSearchService = ContextUtils.getApplicationContext().getBean("searchServiceImpl",
			InnerSearchService.class);

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

	/**
	 * 更新指定实体类的overdue虚拟列的索引
	 * 
	 * @param <T>
	 * 
	 * @param clazz
	 *            实体类
	 */
	private <T> void updateOverdue(Class<T> clazz) {
		// 不能边更新索引边分页获取索引中的数据，因为索引更新后，分页顺序可能也会变化，
		// 所以要先把数据保存到本地，等待全部获取之后重建索引
		Long startTime = new Date().getTime();
		Table_name tableName = ClassAndTableNameUtils.toTableName(clazz);

		int page = PAGE_INDEX;
		SPage<T> sPage = innerSearchService.getAllObjects(clazz, page, PAGE_SIZE);

		// 数据库中数据的总数目
		long totalElements = sPage.getTotalElement();
		logger.info("发现数据：" + totalElements + "条");
		int fileIndex = 1;
		PrintWriter printWriter = null;
		int count = 0;
		try {
			File file = new File(SearchUtils.getDataPath(tableName));
			if (!file.exists()) {
				file.mkdirs();
			}
			printWriter = new PrintWriter(SearchUtils.getDataPath(tableName) + "/" + fileIndex + ".txt");
			while (true) {
				// 一个文件存放100000条数据，一旦超过，写入新的文件
				if (count > IndexServiceImpl.SINGLE_FILE_MAX_SIZE) {
					count = 1;
					printWriter.flush();
					printWriter.close();
					fileIndex++;
					printWriter = new PrintWriter(SearchUtils.getDataPath(tableName) + "/" + fileIndex + ".txt");
				}
				List<T> content = sPage.getContent();
				for (T element : content) {
					Method getOverdueMethod = clazz.getMethod("getOverdue");
					Method setOverdueMethod = clazz.getMethod("setOverdue", Short.class);
					setOverdueMethod.invoke(element, getOverdueMethod.invoke(element));
					printWriter.println(JSONObject.toJSONString(element));
					count++;
				}
				logger.info(String.format(tableName.value() + "...................%.2f%%",
						(page - 1) * PAGE_SIZE * 100.0 / totalElements));

				if (++page > sPage.getTotalPage()) {
					break;
				}
				sPage = innerSearchService.getAllObjects(clazz, page, PAGE_SIZE);
			}
			printWriter.flush();
			printWriter.close();
		} catch (FileNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException
				| IllegalArgumentException | InvocationTargetException e) {
			e.printStackTrace();
		}
		Long endTime = new Date().getTime();
		logger.info(String.format("修改数据%s条，耗时%.2fs\n ", totalElements, (endTime - startTime) / 1000.0));
		indexService.createIndexes(Arrays.asList(tableName), true);
		if (!aqListener.isRunning()) {
			aqListener.start(null);
		}
	}

	@Override
	public <T> DailyTaskInformation newUpdateOverdueDailyTask(final Class<T> clazz, Integer hour, Integer minute,
			Integer second) {
		if (hour == null || minute == null || second == null) {
			throw new NullPointerException();
		}

		String title = "更新虚拟列索引overdue：" + ClassAndTableNameUtils.toTableName(clazz).value().toLowerCase();
		Executable command = new Executable() {
			@Override
			public String execute() {
				updateOverdue(clazz);
				return "success";
			}
		};
		DailyTaskInformation dailyTaskInformation = new DailyTaskInformation(title, command, hour, minute, second);
		taskService.newTask(dailyTaskInformation);
		return dailyTaskInformation;
	}

}
