package com.blueland.bpm.engine.core.service.impl;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

import com.blueland.bpm.common.page.Page;
import com.blueland.bpm.common.util.ServiceResponse;
import com.blueland.bpm.common.util.StringUtils;
import com.blueland.bpm.engine.config.dao.User2roleDao;
import com.blueland.bpm.engine.config.model.ActivityInfoConfig;
import com.blueland.bpm.engine.config.model.ActivityOperatePower;
import com.blueland.bpm.engine.config.model.ActivityRule;
import com.blueland.bpm.engine.config.model.DataObject;
import com.blueland.bpm.engine.config.model.DataObjectRelation;
import com.blueland.bpm.engine.config.model.ProcessInfoConfig;
import com.blueland.bpm.engine.config.model.Role;
import com.blueland.bpm.engine.config.model.User2role;
import com.blueland.bpm.engine.config.service.ActivityInfoConfigManager;
import com.blueland.bpm.engine.config.service.ActivityOperatePowerManager;
import com.blueland.bpm.engine.config.service.ActivityRuleManager;
import com.blueland.bpm.engine.config.service.DataObjectManager;
import com.blueland.bpm.engine.config.service.DataObjectRelationManager;
import com.blueland.bpm.engine.config.service.ProcessInfoConfigManager;
import com.blueland.bpm.engine.config.service.RoleManager;
import com.blueland.bpm.engine.core.model.ProcessDefinitionModel;
import com.blueland.bpm.engine.core.power.ActivityOperatePowerHandler;
import com.blueland.bpm.engine.core.service.AbstractServiceHelper;
import com.blueland.bpm.engine.core.service.ProcessConfigService;
import com.blueland.bpm.engine.core.service.ProcessDefinitionService;
import com.blueland.bpm.engine.util.WorkFlowException;
import com.thoughtworks.xstream.XStream;
/**
 * 流程管理配置Service
 * @version:  1.0
 * @author lw 
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = false)
public class ProcessConfigServiceImpl  extends AbstractServiceHelper implements ProcessConfigService{
protected Logger logger = LoggerFactory.getLogger(getClass());
	@Autowired
	private ProcessDefinitionService processDefinitionService;
	@Autowired
	private ProcessInfoConfigManager processInfoConfigManager;
	@Autowired
	private ActivityInfoConfigManager activityInfoConfigManager;
	@Autowired
	private DataObjectRelationManager dataObjectRelationManager;
	@Autowired
	private DataObjectManager dataObjectManager;
	@Autowired
	private ActivityOperatePowerManager activityOperatePowerManager;
	@Autowired
	private ActivityRuleManager activityRuleManager;
	@Autowired
	private RoleManager roleManager;
	@Autowired
	private User2roleDao user2roleDao;
	/**
	 * 获取流程绑定的界面路径
	 * 获取界面路径的优先级为：1:环节,2:流程
	 * @param processDefId
	 * @param activityDefId
	 * @param version
	 * @return
	 * @throws WorkFlowException
	 */
	public String getWorkflowPage(String processDefId,String activityDefId) throws WorkFlowException{
		String pageUrl="";
		ActivityInfoConfig apcParams=new ActivityInfoConfig();
		apcParams.setProcessDefId(processDefId);
		apcParams.setActivityDefId(activityDefId);
		ActivityInfoConfig activityPageConfig=activityInfoConfigManager.getByEntity(apcParams);
		//获取环节表单URL
		if(activityPageConfig!=null){
			if(StringUtils.isNotBlank(activityPageConfig.getActivityPageUrl())){
				pageUrl=activityPageConfig.getActivityPageUrl();
			}
		}
		//获取流程表单URL
		if(StringUtils.isEmpty(pageUrl)){
			ProcessInfoConfig ppcParams=new ProcessInfoConfig();
			ppcParams.setProcessDefId(processDefId);
			ProcessInfoConfig processPageConfig=processInfoConfigManager.getByEntity(ppcParams);
			if(processPageConfig!=null){
				if(StringUtils.isNotBlank(processPageConfig.getProcessPageUrl())){
					pageUrl=processPageConfig.getProcessPageUrl();
				}else if(StringUtils.isNotBlank(processPageConfig.getProcessPageInfo())){
					pageUrl=processPageConfig.getProcessPageInfo();
				}
			}
		}
		/*if(StringUtils.isEmpty(pageUrl)){
			throw new WorkFlowException("没有在processPageConfig或activityPageConfig表中配置流程绑定的页面");
		}*/
		return pageUrl;
	}
	
	
	public Map<String,String> getPortalPage(String processDefId,String activityDefId) throws WorkFlowException{
		Map<String,String> url=new HashMap<String,String>();
		String cUrl="";
		String cprotocol="";
		String mUrl="";
		String mprotocol="";
		String mreadonly="";
		ActivityInfoConfig apcParams=new ActivityInfoConfig();
		apcParams.setProcessDefId(processDefId);
		apcParams.setActivityDefId(activityDefId);
		ActivityInfoConfig activityPageConfig=activityInfoConfigManager.getByEntity(apcParams);
		//获取环节手机端表单URL
		if(activityPageConfig!=null){
			if(StringUtils.isNotBlank(activityPageConfig.getActivityPageUrl())){
				cUrl=activityPageConfig.getActivityPageUrl();
			}if(StringUtils.isNotBlank(activityPageConfig.getCprotocol())){
				cprotocol=activityPageConfig.getCprotocol();
			}
			if(StringUtils.isNotBlank(activityPageConfig.getMurl())){
				mUrl=activityPageConfig.getMurl();
			}if(StringUtils.isNotBlank(activityPageConfig.getMprotocol())){
				mprotocol=activityPageConfig.getMprotocol();
			}if(StringUtils.isNotBlank(activityPageConfig.getOtherSysDealStatus())){
				mreadonly=activityPageConfig.getOtherSysDealStatus();
			}
		}
		//获取流程手机端表单URL
		ProcessInfoConfig ppcParams=new ProcessInfoConfig();
		ppcParams.setProcessDefId(processDefId);
		ProcessInfoConfig processPageConfig=processInfoConfigManager.getByEntity(ppcParams);
		if(processPageConfig!=null){
			if(StringUtils.isEmpty(cUrl)&&StringUtils.isNotBlank(processPageConfig.getProcessPageUrl())){
				cUrl=processPageConfig.getProcessPageUrl();
			}if(StringUtils.isEmpty(cprotocol)&&StringUtils.isNotBlank(processPageConfig.getCprotocol())){
				cprotocol=processPageConfig.getCprotocol();
			}if(StringUtils.isEmpty(mUrl)&&StringUtils.isNotBlank(processPageConfig.getMurl())){
				mUrl=processPageConfig.getMurl();
			}if(StringUtils.isEmpty(mprotocol)&&StringUtils.isNotBlank(processPageConfig.getMprotocol())){
				mprotocol=processPageConfig.getMprotocol();
			}
			if(StringUtils.isEmpty(mreadonly)&&StringUtils.isNotBlank(processPageConfig.getOtherSysDealStatus())){
				mreadonly=processPageConfig.getOtherSysDealStatus();
			}
		}
		
		/*if(StringUtils.isEmpty(pageUrl)){
			throw new WorkFlowException("没有在processPageConfig或activityPageConfig表中配置流程绑定的页面");
		}*/
		url.put("curl", cUrl);
		url.put("cprotocol", cprotocol);
		url.put("murl", mUrl);
		url.put("mprotocol", mprotocol);
		url.put("mreadonly", mreadonly);
		return url;
	}
	
	
	@Override
	public List<ProcessInfoConfig> findProcessInfoConfigs(ProcessInfoConfig params)
			throws WorkFlowException {
		if(params==null){
			params=new ProcessInfoConfig();
		}
		params.setProcessStartIsshow(ProcessInfoConfig.PROCESS_START_ISSHOW_YES);
		params.setProcessMgrState(ProcessInfoConfig.PROCESS_MGR_STATE_RELEASE);
		params.setProcessMgrIsshow(ProcessInfoConfig.PROCESS_MGR_ISSHOW_Y);
		return processInfoConfigManager.findByExample(params);
	}
	@Override
	public Page<List<ProcessInfoConfig>> findProcessInfoConfigsPage(ProcessInfoConfig params)
			throws WorkFlowException {
		params.setProcessMgrIsshow(ProcessInfoConfig.PROCESS_MGR_ISSHOW_Y);
		return processInfoConfigManager.findConfigPage(params);
	}

	/**
	 * 获取所有满足要求的procDefId以供导出zip
	 * @param params
	 * @return
	 */
	@Override
	public List<String> getAllProcessIdForExport(ProcessInfoConfig params){
		params.setProcessMgrIsshow(ProcessInfoConfig.PROCESS_MGR_ISSHOW_Y);
		return processInfoConfigManager.getAllProcessIdForExport(params);
	}
	
	@Override
	public ActivityInfoConfig getActivityInfoConfig(String processDefId,
			String activityDefId,String opScope,Map pageDetailVaribale) throws WorkFlowException {
		// TODO Auto-generated method stub
		String tenantId = processDefinitionService.getProcessDef(processDefId).getTenantId();
		ActivityInfoConfig activityInfoConfig=activityInfoConfigManager.getActivityInfoConfig(processDefId,activityDefId);
		if(activityInfoConfig==null)
			 activityInfoConfig=new ActivityInfoConfig();
		List<ActivityOperatePower> wfOperatePower=activityOperatePowerManager.findWfButton(opScope, tenantId);
		List<ActivityOperatePower> bizOperatePower=activityOperatePowerManager.findActivityOperatePowerByIds(activityInfoConfig.convertActivityOperationRoleid(),"",opScope);
		if(wfOperatePower!=null&&bizOperatePower!=null)
			wfOperatePower.addAll(bizOperatePower);
		filterActivityOperatePower(wfOperatePower,pageDetailVaribale);
		activityInfoConfig.setActivityOperatePowers(wfOperatePower);
		
		List<DataObjectRelation> dataObjectRelations = dataObjectRelationManager
				.findDataObjectRelationsByActivityDefId(processDefId, activityDefId);
			List<DataObject> dataObjects=new ArrayList<DataObject>();
			for (DataObjectRelation dataObjectRelation : dataObjectRelations) {
				dataObjects.add(dataObjectRelation.getDataObject());
			}
			activityInfoConfig.setDataObjects(dataObjects);
		return activityInfoConfig;
	}
	
	
	@Override
	public ActivityInfoConfig getActivityInfoConfigByLocal(String processDefId,
			String activityDefId) throws WorkFlowException {
		// TODO Auto-generated method stub
		ActivityInfoConfig activityInfoConfig = activityInfoConfigManager
				.getActivityInfoConfig(processDefId, activityDefId);
		if (activityInfoConfig == null)
			activityInfoConfig = new ActivityInfoConfig();
		return activityInfoConfig;
	}
	
	@Override
	public ActivityInfoConfig getActivityInfoConfig(String processDefId,
			String activityDefId) throws WorkFlowException {
		// TODO Auto-generated method stub
		ActivityInfoConfig activityInfoConfig = activityInfoConfigManager
				.getActivityInfoConfig(processDefId, activityDefId);
		if (activityInfoConfig == null)
			activityInfoConfig = new ActivityInfoConfig();

		List<DataObjectRelation> dataObjectRelations = dataObjectRelationManager
				.findDataObjectRelationsByActivityDefId(processDefId,
						activityDefId);
		List<DataObject> dataObjects = new ArrayList<DataObject>();
		for (DataObjectRelation dataObjectRelation : dataObjectRelations) {
			dataObjects.add(dataObjectRelation.getDataObject());
		}
		activityInfoConfig.setDataObjects(dataObjects);
		return activityInfoConfig;
	}
	
	private void filterActivityOperatePower(
			List<ActivityOperatePower> wfOperatePowers, Map pageDetailVaribale) {
		if (wfOperatePowers == null || wfOperatePowers.isEmpty())
			return;
		if (pageDetailVaribale == null || pageDetailVaribale.isEmpty())
			return;
		for (int i = 0; i < wfOperatePowers.size(); i++) {
			ActivityOperatePower activityOperatePower = wfOperatePowers.get(i);
			if (StringUtils.isEmpty(activityOperatePower.getOpClassPath())) {
				continue;
			}
			try {
				Class clazz = Class.forName(activityOperatePower
						.getOpClassPath());
				Object obj = clazz.newInstance();
				if (obj instanceof ActivityOperatePowerHandler) {
					ActivityOperatePowerHandler handler = (ActivityOperatePowerHandler) obj;
					boolean isPower =false;
					try{
					 isPower = handler
							.isActivityOperatePower(pageDetailVaribale);
					}catch(Exception e){
						logger.error("isActivityOperatePower error,pageDetailVaribale:"+pageDetailVaribale, e);
					}
					if (!isPower) {
						wfOperatePowers.remove(i);
						i--;
					}
				}
			} catch (Exception e) {
				logger.error("", e);
			}

		}
	}
	@Override
	public ProcessInfoConfig getProcessInfoConfig(String processDefId)
			throws WorkFlowException {
		// TODO Auto-generated method stub
		ProcessInfoConfig processInfoConfig=processInfoConfigManager.getById(processDefId);
		List<DataObjectRelation> dataObjectRelations=dataObjectRelationManager.findDataObjectRelationsByProcessDefId(processDefId);
		List<DataObject> dataObjects=new ArrayList<DataObject>();
		for (DataObjectRelation dataObjectRelation : dataObjectRelations) {
			dataObjects.add(dataObjectRelation.getDataObject());
		}
		if(processInfoConfig!=null){
		processInfoConfig.setDataObjects(dataObjects);
		}
		return processInfoConfig;
	}
	@Transactional(propagation = Propagation.SUPPORTS,readOnly=true)
	public boolean deleteProcessInfoConfig(String processDefId) throws WorkFlowException{
		processInfoConfigManager.removeById(processDefId);
		activityInfoConfigManager.deleteActivityInfoConfigs(processDefId);
		activityRuleManager.deleteAllActivityRule(processDefId);
		return true;
	}
	@Override
	public ByteArrayOutputStream exportOneProcessData(String processDefId) {
		ProcessInfoConfig processInfoConfig = this
				.getProcessInfoConfig(processDefId);
		List<ActivityInfoConfig> activityInfoConfigs = activityInfoConfigManager
				.findActivityInfoConfigs(processInfoConfig.getProcessDefId());
		processInfoConfig.setActivityInfoConfigs(activityInfoConfigs);
		List<ActivityRule> activityRules = activityRuleManager.findActivityRules(processInfoConfig.getProcessDefId(),"");
		processInfoConfig.setActivityRules(activityRules);
		List<DataObjectRelation> dataObjectRelations=new ArrayList<DataObjectRelation>();
		for (ActivityInfoConfig activityInfoConfig : activityInfoConfigs) {
			List<ActivityOperatePower> activityOperatePowers = activityInfoConfigManager
					.findActivityOperatePower(
							processInfoConfig.getProcessDefId(),
							activityInfoConfig.getActivityDefId());
			activityInfoConfig.setActivityOperatePowers(activityOperatePowers);
			dataObjectRelations.addAll(this.dataObjectRelationManager.findDataObjectRelationsByActivityDefId(processDefId, activityInfoConfig.getActivityDefId()));
		}
		dataObjectRelations.addAll(this.dataObjectRelationManager.findDataObjectRelationsByProcessDefId(processDefId));
		processInfoConfig.setDataObjectRelations(dataObjectRelations);
		XStream xstream = new XStream();
		ByteArrayOutputStream out=new ByteArrayOutputStream();
		xstream.toXML(processInfoConfig,out);
		return out;
		
	}
	

	@Override
	@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
	public ServiceResponse<Void> importOneProcessData(String proceDefId,String tenantId,String deploymentId,String fileContent,
			String importType) {
		ServiceResponse<Void> serviceResponse = new ServiceResponse<Void>(
				new Date());
		try {
			XStream xstream = new XStream();
			ProcessInfoConfig importProcessInfoConfig = (ProcessInfoConfig) xstream
					.fromXML(fileContent);
			if(StringUtils.isNotBlank(proceDefId)){
				importProcessInfoConfig.setProcessDefId(proceDefId);
			}if(StringUtils.isNotBlank(deploymentId)){
				importProcessInfoConfig.setDeploymentId(deploymentId);
			}
			if (importProcessInfoConfig == null) {
				return serviceResponse.build(
						ServiceResponse.STATUS_PARAMS_ERROR,
						"无法将导入流程配置转换为ProcessInfoConfig对象");
			}
			ProcessDefinitionModel processDefinitionModel=null;
			try{
				processDefinitionModel=processDefinitionService.getProcessDef(importProcessInfoConfig.getProcessDefId());
			}catch(Exception e){
				e.printStackTrace();
			}
			if(processDefinitionModel==null||StringUtils.isEmpty(processDefinitionModel.getProcDefId())){
				processDefinitionModel=processDefinitionService.getProcessDefBykey(importProcessInfoConfig.getProcessDefKey());
				if(processDefinitionModel==null||StringUtils.isEmpty(processDefinitionModel.getProcDefId())){
					return serviceResponse.build(
							ServiceResponse.STATUS_PARAMS_ERROR,
							"无法找到流程定义对象,可能流程定义已被删除。导入的流程配置对象信息:"
									+ importProcessInfoConfig);
				}
				importProcessInfoConfig.setProcessDefId(processDefinitionModel.getProcDefId());
			}
			importProcessInfoConfig.setTenantId(tenantId);
			if ("0".equals(importType)) {// 覆盖
				processInfoConfigManager.removeById(importProcessInfoConfig
						.getProcessDefId());
				processInfoConfigManager.save(importProcessInfoConfig);

				if (importProcessInfoConfig.getActivityInfoConfigs() != null) {
					activityInfoConfigManager
							.deleteActivityInfoConfigs(importProcessInfoConfig
									.getProcessDefId());
					for (ActivityInfoConfig importActivityInfoConfig : importProcessInfoConfig
							.getActivityInfoConfigs()) {
						if (importActivityInfoConfig == null) {
							continue;
						}
						importActivityInfoConfig.setProcessDefId(importProcessInfoConfig.getProcessDefId());
						activityInfoConfigManager
								.save(importActivityInfoConfig);
						if (importActivityInfoConfig.getActivityOperatePowers() == null) {
							continue;
						}
						for (ActivityOperatePower importActivityOperatePower : importActivityInfoConfig
								.getActivityOperatePowers()) {
							if (importActivityOperatePower == null) {
								continue;
							}
							if (activityOperatePowerManager
									.getById(importActivityOperatePower
											.getOpId()) == null) {
								activityOperatePowerManager
										.save(importActivityOperatePower);
							} else {
								activityOperatePowerManager
										.update(importActivityOperatePower);
							}
						}
					}
				}
				if (importProcessInfoConfig.getActivityRules() != null) {
					activityRuleManager
							.deleteAllActivityRule(importProcessInfoConfig
									.getProcessDefId());
					for (ActivityRule activityRule : importProcessInfoConfig
							.getActivityRules()) {
						if (activityRule == null) {
							continue;
						}
						activityRule.setProcDefId(importProcessInfoConfig.getProcessDefId());
						activityRuleManager.save(activityRule);
					}
				}
				if (importProcessInfoConfig.getDataObjectRelations() != null) {
					try{
					dataObjectRelationManager.deleteByProcessDefId(importProcessInfoConfig.getProcessDefId());
					}catch(Exception e){
						e.printStackTrace();
					}
					for (DataObjectRelation dataObjectRelation : importProcessInfoConfig.getDataObjectRelations()) {
						//dataObjectRelationManager.removeById(dataObjectRelation.getDorId());
						dataObjectManager.removeById(dataObjectRelation.getDataObject().getObjId());
						dataObjectRelation.setProcessDefId(importProcessInfoConfig.getProcessDefId());
						dataObjectRelationManager.save(dataObjectRelation);
					}
				}
			} else if ("1".equals(importType)) {// 跳过

			}
		} catch (Exception e) {
			logger.error("",e);
		}
		serviceResponse=serviceResponse.build(
				ServiceResponse.STATUS_OP_SUCCESS,
				"导入流程配置成功！");
		return serviceResponse;
	}
	public  boolean isThroughBizAppProcess(String processDefId, String activityDefId){
		boolean isThroughFlag=false;
		ActivityInfoConfig activityInfoConfig=getActivityInfoConfig(processDefId, activityDefId);
		if(activityInfoConfig==null)
			return isThroughFlag;
		if(ActivityInfoConfig.ACTIVITY_DEF_CHILD_TYPE_THROUGH.equals(activityInfoConfig.getActivityDefChildType())){
			isThroughFlag=true; 
		}
		return isThroughFlag;
		
	}
	@Override
	public boolean hasActivityButOperatePower(String butOperateId, Map<String,Object> pageDetailVaribale) {
		ActivityOperatePower activityOperatePower=activityOperatePowerManager.getById(butOperateId);
		if(activityOperatePower==null||pageDetailVaribale==null){
			return false;
		}
		List<ActivityOperatePower> activityOperatePowers=new ArrayList<ActivityOperatePower>();
		activityOperatePowers.add(activityOperatePower);
		filterActivityOperatePower(activityOperatePowers,pageDetailVaribale);
		return activityOperatePowers.size()>0;
	}
	
	
	
	@Override
	public ByteArrayOutputStream exportAllRoleData(String appId) {
		Role params=new Role();
		params.setRoleAppId(appId);
		params.setRoleType("BIZ");
		List<Role> roles=roleManager.findRolesByParam(params);
		for (Role role : roles) {
			List<User2role> user2roles=roleManager.getUser2roleList(role.getRoleId());
			role.setUser2roles(user2roles);
		}
		XStream xstream = new XStream();
		ByteArrayOutputStream out=new ByteArrayOutputStream();
		xstream.toXML(roles,out);
		return out;
	}
	
	
	@Override
	public void importAllRoleData(String fileContent) {
		XStream xstream = new XStream();
		List<Role> newRoles = (List<Role>) xstream
				.fromXML(fileContent);
		for (Role newRole : newRoles) {
			Role oldRole = roleManager.getById(newRole.getRoleId());
		if(oldRole!=null&&StringUtils.isNotBlank(oldRole.getRoleId())){
			roleManager.update(newRole);
		}else{
			roleManager.save(newRole);
		}
		List<User2role> user2roles=newRole.getUser2roles();
		for (User2role newUser2role : user2roles) {
			User2role oldUser2role=roleManager.getUser2roleList(newUser2role.getRoleId(), newUser2role.getUserId());
			if(oldUser2role==null){
				user2roleDao.save(newUser2role);
			}else{
				user2roleDao.update(newUser2role);
			}
		}
		}
	}


	@Override
	public List<String> getPreTaskAssignee(String processInstanceId, String taskId) {
		return processInfoConfigManager.getPreTaskInstance(processInstanceId, taskId);
	}
	
	@Override
	public Page<List<ProcessInfoConfig>> findProcessConfigAndModel(ProcessInfoConfig params)
			throws WorkFlowException {
		params.setProcessMgrIsshow(ProcessInfoConfig.PROCESS_MGR_ISSHOW_Y);
		return processInfoConfigManager.findConfigAndModelPage(params);
	}
}
