package nc.bs.bi.service;

import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import nc.bs.framework.common.InvocationInfoProxy;
import nc.bs.framework.common.NCLocator;
import nc.bs.framework.common.RuntimeEnv;
import nc.bs.framework.component.ServiceComponent;
import nc.bs.framework.execute.Executor;
import nc.bs.pub.bap.toolkit.AppExecutor;
import nc.itf.bi.IPivotService;
import nc.pub.bap.context.BapContext;
import nc.pub.bi.pivot.search.PivotDataCrawler;
import nc.pub.bi.pivot.search.PivotIndexProcessor;
import nc.pub.bi.pivot.search.PivotRawStructData;
import nc.pub.bi.pivot.search.PivotSearchManager;
import nc.pub.bi.pivot.search.PivotSearchProcessor;
import nc.pub.bi.pivot.search.PivotSearchResult;
import nc.pub.pivot.cache.PivotDefCache;
import nc.pub.pivot.exception.PivotException;
import nc.pub.pivot.model.PivotData;
import nc.pub.pivot.request.PivotRequest;
import nc.pub.pivot.request.PivotTableRequest;
import nc.pub.pivot.result.PivotResult;
import nc.pub.pivot.setting.TableSetting;
import nc.pub.pivot.tableexec.PivotTableExecUtil;
import nc.pub.pivot.util.PvtOlapElementTools;
import nc.pub.smart.data.DbTable;
import nc.pub.smart.util.SmartUtilities;
import nc.pubitf.bdsearch.IBDSearcher;
import nc.pubitf.bdsearch.ISearchResult;
import nc.vo.bdsearch.IndexPaginalResult;
import nc.vo.bdsearch.PageIndex;
import nc.vo.bdsearch.PageVO;
import nc.vo.pivot.PivotReportDefVO;
import nc.vo.pub.BusinessException;

import org.apache.commons.collections4.CollectionUtils;
import nccloud.commons.lang.StringUtils;

import uap.itf.bq.pub.IBQOlapQueryService;
import uap.vo.bq.pub.analysis.model.field.olap.OlapDimension;

import com.ufida.ba.image.thumbnail.SerializableImageData;
import com.ufida.ba.util.ScreenImageUtil;
import com.ufida.bap.model.OlapConstant;
import com.ufida.iufo.pub.tools.AppDebug;
import com.ufida.zior.exception.MessageException;
import com.ufida.zior.perfwatch.PerfWatch;
import com.ufsoft.script.base.UfoVal;
import com.ufsoft.table.CellsModel;

/**
 * 多维模型服务实现
 *
 * @author liuyy
 *
 */
public class PivotService implements IPivotService, ServiceComponent {

	/**
	 * 索引名称常量
	 */
	private final String BI_PIVOT_SEARCH = "bi_pivot_search";

	/**
	 * 透视表缩略图存放路径
	 */
	private final String IMAGE_ADDRESS = "/hotwebs/portal/images/bap/";

	/**
	 * 服务组件是否启动
	 */
	private boolean m_started = false;

	/**
	 * 透视表执行请求 包括mdx执行、展开/折叠等
	 *
	 * @param req
	 * @return
	 */
	@Override
	public PivotData pivotRequest(PivotRequest req) throws PivotException {
		try {
			return NCLocator.getInstance().lookup(IBQOlapQueryService.class).execMdx(req);
		} catch (Exception e) {
			throw new PivotException(e);
		}
	}

	public DbTable drillThrough(PivotRequest req) throws PivotException {
		try {
			return NCLocator.getInstance().lookup(IBQOlapQueryService.class).drillThrough(req);
//			return PivotExecutor.drillThrough(req);
		} catch (Exception e) {
			throw new PivotException(e);
		}
	}

	@Override
	public int getSearchResultCount(String searchString)
			throws BusinessException {
		int totalCount = 0;
		if (StringUtils.isEmpty(searchString)) {
			return totalCount;
		}
		IBDSearcher searcher = NCLocator.getInstance()
				.lookup(IBDSearcher.class);
		if (searcher == null) {
			throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl
					.getNCLangRes().getStrByID("8001005_0", "08001005-0550") /*
																			 * @res
																			 * "无法加载搜索服务"
																			 */);
		}
		String dsName = SmartUtilities.getDefDsName();
		String usrDataSource = InvocationInfoProxy.getInstance()
				.getUserDataSource();
		try {
			InvocationInfoProxy.getInstance().setUserDataSource(dsName);
			PivotSearchManager searchManager = PivotSearchManager
					.getInstance(PivotRawStructData.class);
			totalCount = searcher.getCount(searchManager.getIndexDocName(),
					searchString);
		} finally {
			InvocationInfoProxy.getInstance().setUserDataSource(usrDataSource);
		}
		return totalCount;
	}

	@Override
	public PivotSearchResult[] search(String searchString, int startIndex,
			int countPerPage) throws BusinessException {
		List<PivotSearchResult> results = new ArrayList<PivotSearchResult>();
		if (StringUtils.isEmpty(searchString)) {
			return (PivotSearchResult[]) results
					.toArray(new PivotSearchResult[0]);
		}

		IBDSearcher searcher = NCLocator.getInstance()
				.lookup(IBDSearcher.class);
		if (searcher == null) {
			throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl
					.getNCLangRes().getStrByID("8001005_0", "08001005-0550") /*
																			 * @res
																			 * "无法加载搜索服务"
																			 */);
		}
		String dsName = SmartUtilities.getDefDsName();
		String usrDataSource = InvocationInfoProxy.getInstance()
				.getUserDataSource();
		try {
			// 设置用户数据源为定义数据源
			InvocationInfoProxy.getInstance().setUserDataSource(dsName);

			PageIndex pageIndex = createPageIndex(startIndex, countPerPage,
					dsName);

			/*
			 * IndexPaginalResult为分页结果集
			 * LuceneIndexSearcher的searchPKFromGeneralIndex返回PKs
			 * 通过nc.pub.bi.pivot.search.PivotSearchProcessor处理
			 */
			IndexPaginalResult indexPaginalResult = searcher
					.searchWithProcessor(new String[1], searchString,
							pageIndex, (String[]) Arrays.asList(dsName)
									.toArray());

			List<ISearchResult> resultList = indexPaginalResult
					.getSearchResult();
			if (CollectionUtils.isEmpty(resultList)) {
				return (PivotSearchResult[]) results
						.toArray(new PivotSearchResult[0]);
			}

			for (ISearchResult searchResult : resultList) {
				results.add((PivotSearchResult) searchResult.getParam().get(
						PivotSearchProcessor.TAG_SEARCH_RESULT));
			}
		} finally {
			// 恢复系统原有数据源
			InvocationInfoProxy.getInstance().setUserDataSource(usrDataSource);
		}

		return results.toArray(new PivotSearchResult[0]);
	}

	private PageIndex createPageIndex(int startIndex, int countPerPage,
			String dsName) {
		PageVO pageVO = new PageVO();
		pageVO.setDataSource(dsName);
		pageVO.setIndexName(BI_PIVOT_SEARCH);
		pageVO.setPageNum(startIndex);
		pageVO.setPageSize(countPerPage);
		PageIndex pageIndex = new PageIndex(countPerPage);
		pageIndex.setNextPage(Arrays.asList(pageVO));
		return pageIndex;
	}

	@Override
	public void refreshDataIndex(boolean removeIndex, final String... repPks)
			throws BusinessException {
		if (removeIndex) {
			// 删除索引
			PivotIndexProcessor proc = new PivotIndexProcessor() {
				private static final long serialVersionUID = 8593342894440200858L;

				@Override
				protected List<String> getPkList() {
					return Arrays.asList(repPks);
				}
			};
			IBDSearcher searcher = NCLocator.getInstance().lookup(
					IBDSearcher.class);
			searcher.fireChange(
					PivotSearchManager.getInstance(PivotRawStructData.class)
							.getIndexDocName(), proc);
			return;
		}
		// 调用数据抓取任务
		final PivotDataCrawler crawler = new PivotDataCrawler();
		crawler.setPivotIds(repPks);

		try {
			new AppExecutor() {
				@Override
				public void execute() {
					try {
						crawler.execute();
					} catch (Exception e) {
						AppDebug.error(e);
						throw MessageException.handle(e);
					}
				}
			}.start();
		} catch (Exception e) {
			AppDebug.error(e);
			throw new BusinessException(nc.vo.ml.NCLangRes4VoTransl
					.getNCLangRes().getStrByID("8001005_0", "08001005-0551") /*
																			 * @res
																			 * "刷新索引失败:"
																			 */
					+ e.getMessage());
		}
	}

//	@Override
//	public IPivotResult pivotOpenRequest(PivotTableRequest tableReq)
//			throws PivotException {
//		return PivotTableExecUtil.pivotOpenRequest(tableReq);
//	}

	/**
	 * 链接执行 包括oba、portal请求 处理合并
	 *
	 * @param tableReq
	 * @return
	 */
//	private PivotResult linkRequest(PivotTableRequest tableReq)
//			throws PivotException {
//
//		BapContext context = tableReq.getContext();
//
//		CellsModel newCellsModel = tableReq.getCellsModel();
//		ContextUdfModel contextModel = ContextUdfModel.getInstance(newCellsModel);
//
//		// 处理TableLink：合并到ContextModel
//		TableLink tableLink = (TableLink) context
//				.getAttribute(OlapConstant.BAP_LINK);
//		if (tableLink != null) {
//			QueryDesc[] linkDescs = tableLink.getQueryDescs();
//			if (!ArrayUtils.isEmpty(linkDescs)) {
//				context.addQueryDesc(linkDescs);
//			}
//
//			if(tableLink.isRelatedDestiContext()){
//				ContextBuilderProxy.getInstance(contextModel).unionDesc(context);
//			}
//
//			// TableLinkContextHandler handler = new
//			// TableLinkContextHandler(contextModel);
//			// handler.unionTableLink(context);
//			// 不能在此处理参数：参数在前台弹出参数设置面板来处理
//		}
//		// 处理外部传入的过滤描述器，合并到ContextModel，删除已经合并过的描述器数组
//		// link过来的才走此逻辑
////		contextModel.unionItvDesc(context);
//
//
//		return pivotTableRequest(tableReq);
//	}

	/**
	 * 根据整表请求加载整表数据 不处理link 不处理合并
	 */
	@Override
	public PivotResult pivotTableRequest(PivotTableRequest tableReq)
			throws PivotException {
		return PivotTableExecUtil.pivotTableRequest(tableReq);
	}

//	@Override
//	public PivotResult pivotAreaRequest(PivotAreaRequest areaReq)
//			throws PivotException {
//		return null;
//	}

	/**
	 * 透视表联动执行
	 *
	 * @param sourceId
	 *            联动源id 可以为区域 或 透视图
	 * @param cellsModel
	 * @param context
	 *            执行context，包含描述器
	 * @return 执行填充后的cellsModel
	 */
//	@Override
//	public PvtLinkageResult execLinkage(String sourceId, CellsModel cellsModel,
//			BapContext context) throws PivotException {
//		// 找到联动源
//
//		// 找到所有联动目标区域
//
//		// 循环调用各区域、图 执行、填充
//		PvtLinkageExecutor exector = new PvtLinkageExecutor();
//		return exector.exec(sourceId, cellsModel, context);
//	}

	// @Override
	// public ChartResult pivotChartRequest(PivotChartRequest chartReq) {
	// try {
	// //TODO xietf 考虑是否需要宏变量、报表变量处理
	//
	// IChartModel chartModel = chartReq.getChartModel();
	// PageDimModel pageDimModel = chartReq.getContextModel();
	//
	// CellsModel cellsModel = CellsModel.getInstance(null, true);
	// cellsModel.putExtProp(ContextModel.class.getName(), pageDimModel);
	// AbstractAreaModel areaChartModel = (AbstractAreaModel) chartModel;
	//
	// // areaChartModel.setAttribute(CubeFilterCondition.class.getName(),
	// // chartReq.getCondition());
	// ChartUtil.setFilter(areaChartModel, chartReq.getDescs());
	//
	// areaChartModel.setAttribute(ChartThrough.class.getName(),
	// chartReq.getChartThrough());
	//
	// areaChartModel.setCellsModel(cellsModel);
	// IChartValue createChartValue = chartModel.getChartValueProvider()
	// .createChartValue(chartModel);
	// ChartResult result = new ChartResult(createChartValue);
	// Object displayTitle =
	// chartModel.getChartVo().getAttribute(ChartConstants.CHART_DISPLAY_TITLE);
	// if (displayTitle != null) {
	// result.setCharAttribute(ChartConstants.CHART_DISPLAY_TITLE,
	// displayTitle);
	// }
	// Object displaySubtitle =
	// chartModel.getChartVo().getAttribute(ChartConstants.CHART_DISPLAY_SUBTITLE);
	// if (displaySubtitle != null) {
	// result.setCharAttribute(ChartConstants.CHART_DISPLAY_SUBTITLE,
	// displaySubtitle);
	// }
	// return result;
	// } catch (Exception e) {
	// try {
	// clearCache();
	// } catch (BusinessException e1) {
	// AppDebug.debug(e1);
	// }
	// AppDebug.debug(e);
	// throw new MessageException(nc.vo.ml.NCLangRes4VoTransl
	// .getNCLangRes().getStrByID("8001005_0", "08001005-0554") /*
	// * @res
	// * "记载图表数据出错:"
	// */
	// + e.getMessage(), e);
	// }
	// }

	@Override
	public void createThumbnail(SerializableImageData imageData)
			throws BusinessException {
		try {
			String homeUrl = RuntimeEnv.getInstance().getNCHome();
			String imagePath = homeUrl + IMAGE_ADDRESS;
			File imageFile = new File(imagePath);
			if (!imageFile.exists()) {
				imageFile.mkdirs();
			}
			// 图片反序列化
			BufferedImage image = imageData.deserializeImage();
			ScreenImageUtil.writeImage(image, imagePath + imageData.getName()
					+ ".png");
		} catch (Exception e) {
			AppDebug.error(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes()
					.getStrByID("8001005_0", "08001005-0981") + " " /*
																	 * @res
																	 * "生成缩略图失败:"
																	 */
					+ e.getMessage());
			throw new BusinessException(e);
		}

	}

	@Override
	public boolean isStarted() {
		return m_started;
	}

	@Override
	public void start() throws Exception {
		try{
			UfoVal.createVal(new Double(0));
		}catch(Exception e){
			AppDebug.debug(e);
		}
		new Executor(new Runnable() {
			@Override
			public void run() {
				// 需要异步执行
//				UdfFunRegistry.getInstance();
			}
		}).start();

		m_started = true;
	}

	@Override
	public void stop() throws Exception {

	}

//	@Override
//	public DataSet execAdhocModel(CellsModel cellsModel, AdhocModel adhocModel,
//			IContext context) throws AdhocException {
//		initContextVarEnv(cellsModel, context);
//		return new AdhocExecutor(cellsModel, adhocModel).exec(context);
//	}

//	@Override
//	public DataSet getDistinctValue(CellsModel cellsModel,
//			AdhocModel adhocModel, String fieldName, IContext context)
//			throws AdhocException {
//		initContextVarEnv(cellsModel, context);
//		return new AdhocExecutor(cellsModel, adhocModel).getDistinctValue(
//				context, fieldName);
//	}

	/**
	 * 初始化报表变量
	 *
	 * @param cellsModel
	 * @param context
	 */
//	private void initContextVarEnv(CellsModel cellsModel, IContext context) {
//		ContextUdfModel contextModel = ContextUdfModel.getInstance(cellsModel);
//		// //增加上下文关联、行列维度 描述器,用于后续报表变量计算
//		PivotUtil.initContextByContextModel(contextModel, (BapContext) context);
//		PivotUtil.initContextVarEnv(cellsModel, (BapContext) context);
//	}

	/**
	 * 执行透视表 整表执行,提供portal,oba,订阅 使用
	 *
	 * context中设置过滤维度条件: BapContext.setQueryDescriptors(QueryDescriptor[])
	 *
	 * @return CellsModel
	 */
	public CellsModel executePivot(String defPk, BapContext context)
			throws PivotException {
		// TODO xietf 描述器，如果优先级为默认时设置优先级为交互级

		// 加载透视表
		PivotReportDefVO pivotDefVo = PivotDefCache.getInstance().getDefByPk(
				defPk);
		CellsModel cellsModel = pivotDefVo.getCellsModel4Multlang();
		return executePivot(cellsModel, context);
	}

	/**
	 * @param context
	 * @param cellsModel
	 * @return
	 * @throws PivotException
	 */
	public CellsModel executePivot(CellsModel cellsModel, BapContext context)
			throws PivotException {
		if (cellsModel == null) {
			cellsModel = CellsModel.getInstance(null, true);
		} else {
			// 必须clone
			cellsModel = (CellsModel) cellsModel.clone();
			PivotTableRequest request = new PivotTableRequest(cellsModel,
					context);
			PivotResult result = PivotTableExecUtil.linkRequest(request);
			result.getBuilder().buildResult();
			if (result != null) {
				cellsModel = result.getCellsModel();
			}
		}
		return cellsModel;
	}

	@Override
	@Deprecated
	public Map<String, OlapDimension[]> getMergeDimension(String[] pivotPks)
			throws Exception {
		return null;
//		String split = "_";
//
//		// 先把所有透视表中的过滤维度取出来
//		// key:pivotPk_cubeName_dimName_levelName1_levelName2...
//		Map<String, OlapDimension> tempMap = new HashMap<String, OlapDimension>();
//		for (String pivotPk : pivotPks) {
//			PivotReportDefVO vo = (PivotReportDefVO) PivotDefCache
//					.getInstance().get(pivotPk);
//			if (vo == null) {
//				continue;
//			}
//			CellsModel cellsModel = vo.getCellsModel4Multlang();
//			ContextUdfModel contextModel = ContextUdfModel.getInstance(cellsModel);
//			if (contextModel == null) {
//				continue;
//			}
//
//			IFieldElement[] filterFields = contextModel.getElements().getContextElements().getAllFields();
//			if(filterFields == null || filterFields.length ==0){
//				continue;
//			}
//
//			for(IFieldElement fe : filterFields){
//				if(!(fe instanceof OlapDimension)){
//					continue;
//				}
//
//				OlapDimension dimField = (OlapDimension) fe;
//				DimensionEntity dimEntity = (DimensionEntity) dimField.getOlapAnaEntity();
//				String cubeName = dimEntity.getCubeEntity().getName();
//
//				//TODO tiandm 此处去级别可能有问题，需后续验证
//				OlapLevel[] olapLevels = CubeTreeLoader.getAllLevels(dimField);
//
//				if (ArrayUtils.isEmpty(olapLevels)) {
//					continue;
//				}
//
//				StringBuilder sb = new StringBuilder();
//				sb.append(pivotPk);
//				sb.append(split);
//				sb.append(cubeName);
//				sb.append(split);
//				sb.append(dimEntity.getName());
//
//				for (OlapLevel ol : olapLevels) {
//					if (ol.isAll()) {
//						continue;
//					}
//					sb.append(split);
//					sb.append(ol.getName());
//				}
//				String tempKey = sb.toString();
//				tempMap.put(tempKey, dimField);
//			}
//		}
//
//		// 对一组过滤维度合并
//		Set<String> tempKeySet = tempMap.keySet();
//		// 公共的过滤维度
//		List<OlapDimension> pubList = new ArrayList<OlapDimension>();
//		// 单个透视表私有的过滤维度
//		Map<String, Set<OlapDimension>> privateMap = new HashMap<String, Set<OlapDimension>>();
//		// 维度信息集合
//		Set<String> set = new HashSet<String>();
//
//		// 1 获得公共维度集合
//		for (String tempKey : tempKeySet) {
//			// 维度信息cubeName_dimName_levelName1_levelName2...
//			String key = tempKey.substring(tempKey.indexOf(split) + 1);
//			if (set.contains(key)) {
//				// 加入到公共维度中
//				pubList.add(tempMap.get(tempKey));
//			} else {
//				set.add(key);
//			}
//		}
//
//		// 2 获得私有维度集合
//		for (String tempKey : tempKeySet) {
//			OlapDimension dimClient = tempMap.get(tempKey);
//
//			if (!pubList.contains(dimClient)) {
//				// 透视表pk
//				String pivotPk = tempKey.substring(0, tempKey.indexOf(split));
//				// 不是公共维度，则放到私有维度中
//				Set<OlapDimension> dimSet = privateMap.get(pivotPk);
//				if (dimSet == null) {
//					dimSet = new HashSet<OlapDimension>();
//					privateMap.put(pivotPk, dimSet);
//				}
//				dimSet.add(dimClient);
//			}
//		}
//
//		// 3 合并到一个集合中
//		Map<String, OlapDimension[]> map = new HashMap<String, OlapDimension[]>();
//		Set<String> keySet = privateMap.keySet();
//		for (String key : keySet) {
//			Set<OlapDimension> dimSet = privateMap.get(key);
//			map.put(key, dimSet.toArray(new OlapDimension[dimSet.size()]));
//		}
//		map.put(PivotFilter.OBA_PUB_FILTER,
//				pubList.toArray(new OlapDimension[pubList.size()]));
//
//		return map;
	}

	@Override
	public PivotData execOlapQuery(String mdx, String schemaDef,
			BapContext context) throws PivotException {
		if (StringUtils.isEmpty(mdx) || StringUtils.isEmpty(schemaDef)) {
			throw new PivotException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes()
					.getStrByID("8001005_0", "08001005-0884")/*
															 * @res
															 * "请求的mdx或者schema定义为空"
															 */);
		}
		if (context == null) {
			context = new BapContext();
		}
		PerfWatch pw = new PerfWatch(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("0502005_0","00502005-0020")/*@res "根据mdx，schema执行"*/);
		try {
			String dsName4Exec = context.getDsName4Exec();
			if (dsName4Exec == null) {
				AppDebug.debug(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes()
						.getStrByID("8001005_0", "08001005-0982") /*
																 * @res
																 * "执行数据源为null"
																 */);
				context.setDsName4Exec(SmartUtilities.getCurrentDsName());
			}
			pw.appendMessage(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes()
					.getStrByID("8001005_0", "08001005-0062")/* @res "数据源" */
					+ ": " + dsName4Exec);
			context.setAttribute(OlapConstant.CACHE_ENABLE, Boolean.TRUE);
//			String key = "schema_" + IDMaker.makeID(10);

			PivotRequest req = new PivotRequest();
			req.setContext(context.toOlapContext());
			req.setMdx(mdx);
			pw.appendMessage("mdx:" + mdx);
//			req.setCubeKey(key);

			//TODO tiandm 此处设置schemaId可能有问题
			req.setSchemaId(schemaDef);
			req.setPivotTableSetting(PvtOlapElementTools.buildPvtTableSetting(new TableSetting()));
			req.setSchemaDef(schemaDef);
			pw.appendMessage("schema:" + schemaDef);
			try {
				return NCLocator.getInstance().lookup(IBQOlapQueryService.class).execMdx(req);
			} catch (Exception e) {
				pw.appendMessage(e);
				AppDebug.error(e);
				throw new PivotException(nc.vo.ml.NCLangRes4VoTransl
						.getNCLangRes()
						.getStrByID("8001005_0", "08001005-0886")/*
																 * @res
																 * "多维查询执行错误:"
																 */
						+ e.getMessage());
			}
		} finally {
			pw.stop();
		}

	}

}
