package cn.myapps.support.weixin;

import cn.myapps.authtime.common.dao.PersistenceUtils;
import cn.myapps.authtime.common.service.AuthTimeServiceManager;
import cn.myapps.authtime.department.model.DepartmentVO;
import cn.myapps.authtime.department.service.DepartmentProcess;
import cn.myapps.authtime.domain.model.DomainVO;
import cn.myapps.authtime.domain.service.DomainProcess;
import cn.myapps.authtime.fieldextends.model.FieldExtendsVO;
import cn.myapps.authtime.fieldextends.service.FieldExtendsProcess;
import cn.myapps.authtime.logger.model.LogVO;
import cn.myapps.authtime.user.model.UserDepartmentRoleSet;
import cn.myapps.authtime.user.model.UserVO;
import cn.myapps.authtime.user.service.UserProcess;
import cn.myapps.authtime.workcalendar.calendar.model.CalendarVO;
import cn.myapps.authtime.workcalendar.calendar.service.CalendarProcess;
import cn.myapps.base.web.WebUser;
import cn.myapps.common.Environment;
import cn.myapps.common.exception.OBPMValidateException;
import cn.myapps.common.model.application.Application;
import cn.myapps.common.model.role.Role;
import cn.myapps.common.util.Security;
import cn.myapps.common.util.StringUtil;
import cn.myapps.designtime.role.service.RoleDesignTimeService;
import cn.myapps.runtime.dynaform.document.ejb.Document;
import cn.myapps.runtime.logger.service.LogHelper;
import cn.myapps.runtime.logger.service.LogProcess;
import cn.myapps.support.weixin.model.*;
import cn.myapps.support.weixin.service.EventCallbackService;
import cn.myapps.support.weixin.service.MediaService;
import cn.myapps.support.weixin.service.MessageService;
import cn.myapps.support.weixin.service.QyApiService;
import cn.myapps.support.weixin.util.ImageUtil;
import cn.myapps.support.weixin.util.JsapiTicketSignUtil;
import cn.myapps.support.weixin.util.WeixinHttpsRequestUtil;
import cn.myapps.support.weixin.util.WeixinSecretCache;
import cn.myapps.support.weixin.util.WeixinSecretCache.WeixinSecret;
import cn.myapps.support.weixin.util.aes.WXBizMsgCrypt;
import cn.myapps.util.ProcessFactory;
import cn.myapps.util.sequence.Sequence;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.*;

public class WeixinService {
	
	public static JSONObject synchFromWeixin(DomainVO domain) throws Exception {
		
		JSONObject result = new JSONObject();
		JSONArray errors = new JSONArray();
		int USER_ADD_SUCCESS = 0 ;
		int DEPT_ADD_SUCCESS = 0;
		int USER_ADD_FAIL = 0;
		int DEPT_ADD_FAIL = 0;
		
		if(!validLicenseAuth()) return result;
		try {
			//1.同步部门
			//PersistenceUtils.beginTransaction();
			String access_token = QyApiService.getAccessToken(WeixinSecretCache.get(domain.getId()));
			List<Department> wxDepts = QyApiService.getDepartmentList(access_token);
		
			if(wxDepts.isEmpty()) throw new OBPMValidateException("微信企业号部门为空");
			
			Map<Integer,DepartmentVO> deptMapping = new HashMap<Integer, DepartmentVO>();
			DepartmentProcess deptProcess = AuthTimeServiceManager.departmentRuntimeService();
			for (Iterator<Department> iterator = wxDepts.iterator(); iterator.hasNext();) {
				Department department = (Department) iterator.next();
				JSONObject deptInfo = new JSONObject();
				boolean DEPT_ADD_RESULT = false ;
				if(department.getLevel() == 0){ //根部门
					List<DepartmentVO> roots = (List<DepartmentVO>) deptProcess.getDepartmentByLevel(0,domain.getId());
					DepartmentVO root = roots.get(0);
					if(!root.getName().equals(department.getName())){
						root.setName(department.getName());
						root.setWeixinDeptId(String.valueOf(department.getId()));
						try {
							deptProcess.doUpdate(root);
							DEPT_ADD_RESULT = true ;
						} catch (Exception e) {
							deptInfo.put("NAME", root.getName());
							deptInfo.put("ERROR", "部门插入数据库失败");
							deptInfo.put("TIP", e.getMessage());
							e.printStackTrace();
						}
					}else{
						DEPT_ADD_RESULT = true;
					}
					deptMapping.put(department.getId(), root);
				}
				
				if(department.getLevel() != 0 ){ // 非根部门
//					String hql = "FROM " + DepartmentVO.class.getName() + " vo where vo.weixinDeptId = :departmentId  and vo.domain.id = :domainId";
//					Map<String,Object> sqlParameterMap = new HashMap<String,Object>();
//					sqlParameterMap.put("departmentId", String.valueOf(department.getId()));
//					sqlParameterMap.put("domainId", domain.getId());
					Collection<DepartmentVO> vos = deptProcess.doQueryByDomainAndWeixinDept(String.valueOf(department.getId()), domain.getId());
					if(vos.isEmpty()){ // 部门不存在
						DepartmentVO vo1 = deptProcess.getDepartmentByNameAndLevel(department.getName(), department.getLevel(), domain.getId());
						if(vo1 != null){ //在obpm端能找到同名同层级的部门，则更新weixinid字段
							vo1.setWeixinDeptId(String.valueOf(department.getId()));
							try {
								deptProcess.doUpdate(vo1);
								DEPT_ADD_RESULT = true ;
							} catch (Exception e) {
								deptInfo.put("NAME", vo1.getName());
								deptInfo.put("ERROR", "部门插入数据库失败");
								deptInfo.put("TIP", e.getMessage());
								e.printStackTrace();
							}
							deptMapping.put(department.getId(), vo1);
						}else{ //不存在对应部门 ，新建部门
							DepartmentVO d = new DepartmentVO();
							d.setName(department.getName());
							d.setLevel(department.getLevel());
							d.setDomain(domain);
							d.setDomainid(domain.getId());
							d.setSuperior(deptMapping.get(department.getParentid()));
							d.setWeixinDeptId(String.valueOf(department.getId()));
							try {
								deptProcess.doCreate(d);
								DEPT_ADD_RESULT = true ;
							} catch (Exception e) {
								deptInfo.put("NAME", d.getName());
								deptInfo.put("ERROR", "部门插入数据库失败");
								deptInfo.put("TIP", e.getMessage());
								e.printStackTrace();
							}
							deptMapping.put(department.getId(), d);
						}
					}else{//可以根据微信部门id找到部门对象，则可能需更新名称、层级、上级部门
						DepartmentVO vo2 = vos.iterator().next();
						boolean needUpdate = false;
						if(!vo2.getName().equals(department.getName())){
							vo2.setName(department.getName());
							needUpdate = true;
						}
						if(vo2.getLevel()!=department.getLevel()){
							vo2.setLevel(department.getLevel());
							vo2.setSuperior(deptMapping.get(department.getParentid()));
							needUpdate = true;
						}
						if(needUpdate){
							try {
								deptProcess.doUpdate(vo2);
								DEPT_ADD_RESULT = true ;
							} catch (Exception e) {
								deptInfo.put("NAME", vo2.getName());
								deptInfo.put("ERROR", "部门插入数据库失败");
								deptInfo.put("TIP", e.getMessage());
								e.printStackTrace();
							}
						}else{
							DEPT_ADD_RESULT = true ;
						}
						deptMapping.put(department.getId(), vo2);
					}
				}
				//更新结果集数量
				if(DEPT_ADD_RESULT){
					DEPT_ADD_SUCCESS ++ ;
				}else{
					DEPT_ADD_FAIL ++ ;
				}
				//添加错误数据
				if(!deptInfo.isEmpty()){
					errors.add(deptInfo);
				}
			}
			
			//2.同步用户
			
			//默认角色
			RoleDesignTimeService rp = AuthTimeServiceManager.roleRuntimeService();
//			RoleDesignTimeService rp = (RoleDesignTimeService) ProcessFactory.createProcess(RoleProcess.class);
			Collection<Application> apps = domain.getApplications();
//			Collection<RoleVO> roles = new ArrayList();
			Collection<Role> roles = new ArrayList<Role>();
			if(!apps.isEmpty()){
				for(Iterator<Application> app_its = apps.iterator(); app_its.hasNext();){
					Application app = app_its.next();
					if(app.isActivated()){
						roles.addAll(rp.getDefaultRolesByApplication(app.getId()));
					}
				}
			}
			
			//扩展字段
			FieldExtendsProcess fieldExtendsProcess = (FieldExtendsProcess) ProcessFactory.createProcess(FieldExtendsProcess.class);
			List<FieldExtendsVO> fieldExtendses = fieldExtendsProcess.queryFieldExtendsByTable(domain.getId(), FieldExtendsVO.TABLE_USER);
			List<FieldExtendsVO> fes = new ArrayList<FieldExtendsVO>();
			for(int i=0;i<fieldExtendses.size();i++){
				FieldExtendsVO fevo = fieldExtendses.get(i);
				if(fevo != null && fevo.getEnabel()){
					fes.add(fevo);
				}
			}
			
			//默认日历
			CalendarProcess calendarProcess = (CalendarProcess)ProcessFactory.createProcess(CalendarProcess.class);
//			String calendarHql = "from "+CalendarVO.class.getName()+" vo where vo.name=:standardCalendar and vo.domainid = :domainid ";
//			Map<String,Object> calendarSqlParameterMap = new HashMap<String,Object>();
//			calendarSqlParameterMap.put("standardCalendar", "标准日历");
//			calendarSqlParameterMap.put("domainid", domain.getId());
			List<CalendarVO> calendars = (List<CalendarVO>) calendarProcess.doQueryByNameAndDomain("Standard_Calendar",domain.getId(),1, 1);
			CalendarVO calendar = calendars.isEmpty()? null : calendars.get(0);
			
			//默认密码
			String defaultPassword = "123456";
			
			Map<String,UserVO> userMapping = new HashMap<String, UserVO>();
			UserProcess userProcess = AuthTimeServiceManager.userRuntimeService();
			
			for (Iterator<Department> iterator = wxDepts.iterator(); iterator.hasNext();) {
				Department department2 = (Department) iterator.next();
				List<User> wxUsers = QyApiService.getUsersByDepartment(access_token, String.valueOf(department2.getId()), "0", "0");
				for (Iterator<User> iterator2 = wxUsers.iterator(); iterator2.hasNext();) {
					JSONObject userInfo = new JSONObject();
					User user = iterator2.next();
					
					if(userMapping.get(user.getUserid()) != null ) {
						if(user.getDepartment() == null || user.getDepartment().length == 1){
							USER_ADD_FAIL ++ ;
							userInfo.put("NAME", user.getName());
							userInfo.put("ERROR", "数据库存在相同账号");
							userInfo.put("TIP", "");
						    errors.add(userInfo);
						}
						continue;
					}
					
					UserVO userVO = userProcess.getUserByLoginno(user.getUserid(), domain.getId());
					boolean USER_ADD_RESULT = false ;
					if(userVO == null){
						//创建用户
						userVO = new UserVO();
						userVO.setId(Sequence.getSequence());
						userVO.setLoginno(user.getUserid());
						userVO.setLoginpwd(defaultPassword);
						userVO.setDomainid(domain.getId());
						userVO.setEmail(user.getEmail());
						userVO.setName(user.getName());
						userVO.setTelephone(user.getMobile());
						userVO.setDefaultDepartment(deptMapping.get(department2.getId()).getId());
						userVO.setCalendarType(calendar !=null? calendar.getId() : null);
						userVO.setStatus(UserVO.ONJOB);
						//设置头像
						if(!StringUtil.isBlank(user.getAvatar())){
							JSONObject json = new JSONObject();
							json.put("url", user.getAvatar());
							String Base64String = ImageUtil.transformImage2Base64String(user.getAvatar(),userVO.getId());
							json.put("data", StringUtil.isBlank(Base64String)?"":Base64String);
							if(!StringUtil.isBlank(Base64String)){
								json.put("isCompress", true);
							}else{
								json.put("isCompress", false);
							}							
							userVO.setAvatar(json.toString());
						}
						
						//设置部门
						Collection<DepartmentVO> departments = new ArrayList<DepartmentVO>();
						for (int i = 0; i < user.getDepartment().length; i++) {
							/*UserDepartmentRoleSet userDepartmentSet = new UserDepartmentRoleSet(userVO.getId(), deptMapping.get(user.getDepartment()[i]).getId(),"");
							userVO.getUserDepartmentRoleSets().add(userDepartmentSet);*/
							departments.add(deptMapping.get(user.getDepartment()[i]));
							//设置默认角色
							if(roles != null && roles.size() > 0 ){
								for(Iterator<Role> it = roles.iterator(); it.hasNext();){
									Role role = it.next();
									UserDepartmentRoleSet set = new UserDepartmentRoleSet(userVO.getId(),deptMapping.get(user.getDepartment()[i]).getId(), role.getId());
									userVO.getUserDepartmentRoleSets().add(set);
								}
							}else{//没有默认角色，则更新用户部门
								UserDepartmentRoleSet set = new UserDepartmentRoleSet(userVO.getId(),deptMapping.get(user.getDepartment()[i]).getId(),null);
								userVO.getUserDepartmentRoleSets().add(set);
							}
						}
						userVO.setDepartments(departments);
						//设置扩展字段
						if(!fes.isEmpty()){
							JSONObject extattr = JSONObject.fromObject(user.getExtattr());
							JSONArray attrs = extattr.getJSONArray("attrs");
							for (Iterator<FieldExtendsVO> iterator3 = fes.iterator(); iterator3
									.hasNext();) {
								FieldExtendsVO fe = iterator3.next();
								String name = fe.getLabel();
								for (Iterator<JSONObject> iterator4 = attrs.iterator(); iterator4
										.hasNext();) {
									JSONObject attr = iterator4.next();
									if(name.equals(attr.getString("name"))){
										String fieldName = fe.getName();
										fieldName = fieldName.replaceFirst("f","F");
										Method method = UserVO.class.getMethod("set" + fieldName,String.class);
										method.invoke(userVO,attr.get("value"));
										break;
									}
								}
							}
						}
						
						try {
							userProcess.doCreate(userVO);
							//设置KM默认角色
							/*if(KmEnable){
								nUserRoleSetProcess.doUpdateUserRoleSet(userVO.getId(), KM_RoleId);
								//创建KM个人网盘
								NDiskProcess ndiskProcess = new NDiskProcessBean();
								ndiskProcess.createByUser(userVO.getId(), userVO.getDomainid());
							}*/
							USER_ADD_RESULT = true ;
						} catch (Exception e) {
							userInfo.put("NAME", userVO.getName());
							userInfo.put("ERROR", "请校验用户账号、电话、邮箱等数据的规范性");
							userInfo.put("TIP", e.getMessage());
							e.printStackTrace();
						}
					}else{
						boolean needUpdate = isUpdateUserFromWeiXin(userVO, user, deptMapping, fes);
						if(needUpdate){
							try {
								//更新用户部门默认角色
								updateUser(deptMapping, roles, user, userVO);
								userProcess.doUpdate(userVO);
								USER_ADD_RESULT = true ;
							} catch (Exception e) {
								userInfo.put("NAME", userVO.getName());
								userInfo.put("ERROR", "请校验用户账号、电话、邮箱等数据的规范性");
								userInfo.put("TIP", e.getMessage());
								e.printStackTrace();
							}
						}else{
							USER_ADD_RESULT = true ;
						}
					}
					//更新结果集数量
					if(USER_ADD_RESULT){
						USER_ADD_SUCCESS ++ ;
					}else{
						USER_ADD_FAIL ++ ;
					}
					userMapping.put(user.getUserid(), userVO);
					//更新错误数据
					if(!userInfo.isEmpty()){
						errors.add(userInfo);
					}
				}
				
			}
			//PersistenceUtils.commitTransaction();
			//对结果数据进行统计
			result.put("USER_ADD_SUCCESS",USER_ADD_SUCCESS);
			result.put("DEPT_ADD_SUCCESS",DEPT_ADD_SUCCESS);
			result.put("USER_ADD_FAIL", USER_ADD_FAIL);
			result.put("DEPT_ADD_FAIL", DEPT_ADD_FAIL);
			result.put("ERRORS", errors);
		} catch (Exception e) {
			e.printStackTrace();
			try {
				PersistenceUtils.rollbackTransaction();
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			if(e instanceof WeixinHandleException){
				e = new OBPMValidateException(e.getLocalizedMessage(), e);
			}
			throw e;
		}
		return result;
	}
	//更新平台部门用户默认角色
	private static void updateUser(Map<Integer, DepartmentVO> deptMapping, Collection<Role> roles, User user,
			UserVO userVO) {
		Collection<UserDepartmentRoleSet> userDepartmentRoleSets = userVO.getUserDepartmentRoleSets();
		Collection<DepartmentVO> userDepartments = userVO.getDepartments();
		List<String> departmentIds=new ArrayList<String>();
		List<String> departmentIdsFromWeixin=new ArrayList<String>();
		int[] departments = user.getDepartment();
		//拿取微信下该用户的部门id集合
		for (int department : departments) {
			departmentIdsFromWeixin.add(deptMapping.get(department).getId());
		}
		//拿取平台该用户的部门id集合
		for (DepartmentVO departmentVO : userDepartments) {
			departmentIds.add(departmentVO.getId());
		}
		//更新是否还在部门，不存在则移除
		Iterator<DepartmentVO> userDepartmentsTemp=userDepartments.iterator();
		while(userDepartmentsTemp.hasNext()){
			DepartmentVO department = userDepartmentsTemp.next();
			if(!departmentIdsFromWeixin.contains(department.getId())){
				userDepartmentsTemp.remove();
			}
		}
		//获取用户部门角色集合,不存在该部门则,则用户角色移除
		Iterator<UserDepartmentRoleSet> userDepartmentRoleSetsTemp = userDepartmentRoleSets.iterator();
		while(userDepartmentRoleSetsTemp.hasNext()) {
			UserDepartmentRoleSet userDepartmentRoleSet = userDepartmentRoleSetsTemp.next();
			if(!departmentIdsFromWeixin.contains(userDepartmentRoleSet.getDepartmentId())){
				userDepartmentRoleSetsTemp.remove();
			}
		}
		//跟新该用户加入的部门默认角色集合
		for (String departmentId : departmentIdsFromWeixin) {
			if(!departmentIds.contains(departmentId)){
				//设置默认角色
				if(roles != null && roles.size() > 0 ){
					for(Iterator<Role> it = roles.iterator(); it.hasNext();){
						Role role = it.next();
						UserDepartmentRoleSet set = new UserDepartmentRoleSet(userVO.getId(),departmentId, role.getId());
						userDepartmentRoleSets.add(set);
					}
				}
			}
		}
		userVO.setDepartments(userDepartments);
		userVO.setUserDepartmentRoleSets(userDepartmentRoleSets);
	}
	
	/**
	 * 用户登录时，从微信更新数据到本地数据库
	 * @param userId
	 * @return
	 * @throws Exception
	 */
	public static UserVO updateUserFromWeixin(String userId) throws Exception {
		
		UserProcess userProcess = AuthTimeServiceManager.userRuntimeService();
		UserVO userVO = (UserVO) userProcess.doView(userId);
		if(!validLicenseAuth()) return userVO;
		
		String domainId = userVO.getDomainid();
		String site_id = getSiteId(domainId);
		
		//2.同步用户
		try {
			User user = null ;
			if(site_id != null){  //云托管模式
				JSONObject wxUser = Weioa365WeixinService.getUser(userVO.getLoginno(), site_id);
				if(wxUser != null){
					user = new User();
					user.setAvatar(wxUser.getString("avatar"));
					JSONArray dept = wxUser.getJSONArray("department");
					int[] depts = new int[dept.size()];
					for(int index =0 ; index < dept.size(); index++){
						int deptId = ((Integer)dept.getInt(index)).intValue();
						depts[index] = deptId;
					}
					user.setDepartment(depts);
					user.setEmail(wxUser.getString("email"));
					user.setEnable(wxUser.getInt("enable"));
					user.setExtattr(wxUser.getString("extattr"));
					user.setMobile(wxUser.getString("mobile"));
					user.setName(wxUser.getString("name"));
					user.setUserid(wxUser.getString("userid"));
					user.setWeixinid(wxUser.getString("weixinid"));
					user.setPosition(wxUser.getString("position"));
				}
			}else{   //本地模式
				String access_token = QyApiService.getAccessToken(WeixinSecretCache.get(domainId));
				//access_token为空则直接返回该用户
				if(StringUtils.isBlank(access_token)) {
					return userVO;
				}
			    user = QyApiService.getUser(access_token, userVO.getLoginno());
			}
			
			if(user == null){ //微信企业号不存在该用户
				return userVO;
			}
			
			boolean needUpdate = isUpdateUserFromWeiXin(userVO,user);
			if(needUpdate){
				userProcess.doUpdate(userVO);
			}
		} catch (Exception e) {
			e.printStackTrace();
			try {
				PersistenceUtils.rollbackTransaction();
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			if(e instanceof WeixinHandleException){
				e = new OBPMValidateException(e.getLocalizedMessage(), e);
			}
			throw e;
		}
		return userVO;
	}
	
	/**
	 * 修改系统后台用户数据时，更新数据到微信
	 * @param user
	 * @throws Exception
	 */
	public static void createOrUpdateUser2Weixin(UserVO userVO)throws Exception {
		
		if(!validLicenseAuth()) return;
		String domainId = userVO.getDomainid();
		String site_id = getSiteId(domainId);
		
		//判断云托管/本地模式
		if(site_id != null){
			 Weioa365WeixinService.createOrUpdateUser2Weixin(userVO.getLoginno(), domainId, site_id);
			 return;
		}
		
		try {
			String access_token = QyApiService.getAccessToken(WeixinSecretCache.get(domainId));
			List<Department> wxDepts = QyApiService.getDepartmentList(access_token);
			
			//获取根节点
			Department root = null ;
			for(Department d : wxDepts){
				if(d.getParentid() == 0){
					root = d ;
					break;
				}
			}
			
			User wxUser = null;
			try {
				wxUser = QyApiService.getUser(access_token, userVO.getLoginno());
			} catch (Exception e) {
				//System.out.println("获取用户失败： user:"+userVO.getName() +"loginno:"+userVO.getLoginno()+" access_token:"+access_token);
			}
			//扩展字段
			FieldExtendsProcess fieldExtendsProcess = (FieldExtendsProcess) ProcessFactory.createProcess(FieldExtendsProcess.class);
			List<FieldExtendsVO> fieldExtendses = fieldExtendsProcess.queryFieldExtendsByTable(domainId, FieldExtendsVO.TABLE_USER);
			
			if(wxUser != null){
				boolean needUpdate = isUpdateUserToWeiXin(userVO, wxUser, root, fieldExtendses);
				if(needUpdate){
					try {
						QyApiService.updateUser(access_token, wxUser);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}else{
				if(userVO.getStatus() !=1) {
					return;
				}
				if(StringUtil.isBlank(userVO.getTelephone()) && StringUtil.isBlank(userVO.getEmail())){//用户邮箱和手机都为空则不同步
					return;
				}
				User u = createUser2WeiXin(userVO, new User(), root, fieldExtendses);
				try {
					QyApiService.createUser(access_token, u);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			try {
				PersistenceUtils.rollbackTransaction();
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			if(e instanceof WeixinHandleException){
				e = new OBPMValidateException(e.getLocalizedMessage(), e);
			}
			throw e;
		}
	}
	
	public static JSONObject synch2Weixin(DomainVO domain) throws Exception {
		
		JSONObject result = new JSONObject();
		JSONArray errors = new JSONArray();
		int USER_ADD_SUCCESS = 0 ;
		int DEPT_ADD_SUCCESS = 0;
		int USER_ADD_FAIL = 0;
		int DEPT_ADD_FAIL = 0;
		
		
		if(!validLicenseAuth()) return result;
		try {
			//1.同步部门
			String access_token = QyApiService.getAccessToken(WeixinSecretCache.get(domain.getId()));
			//System.out.println("----------------------------access_token:" + access_token);
			List<Department> wxDepts = QyApiService.getDepartmentList(access_token);
			Map<String,Department> deptMapping = new HashMap<String, Department>();//已完成同步的部门
			DepartmentProcess deptProcess = AuthTimeServiceManager.departmentRuntimeService();
			DepartmentVO topDeptVO = null;
//			Map<String,Object> sqlParameterMap = new HashMap<String,Object>();
//			String hql = "from "+DepartmentVO.class.getName()+" vo where vo.domain.id = :domainid and vo.valid = 1 order by vo.level asc ";
//			sqlParameterMap.put("domainid", domain.getId());
//			List<DepartmentVO> departments = (List<DepartmentVO>) deptProcess.doQueryByHQL(hql, 1, Integer.MAX_VALUE,sqlParameterMap);
			List<DepartmentVO> departments = (List<DepartmentVO>) deptProcess.doQueryByDomainAndValid(domain.getId(), 1);
			Department root = null ;
			
			if(!departments.isEmpty()){
				for (Iterator<DepartmentVO> iterator = departments.iterator(); iterator.hasNext();) {
					DepartmentVO departmentVO = (DepartmentVO) iterator.next();
					//同步部门数据错误信息
					JSONObject deptInfo = new JSONObject();
					
					if(departmentVO.getValid()==0){
						DEPT_ADD_FAIL++;
						deptInfo.put("NAME",departmentVO.getName() );
						deptInfo.put("ERROR","部门失效" );
						deptInfo.put("TIP","" );
						errors.add(deptInfo);
						continue;
					} 
					
					boolean DEPT_ADD_RESULT = false ;
					if(departmentVO.getLevel() == 0){//顶级部门
						topDeptVO = departmentVO;
						Department dept ;
						if(wxDepts.isEmpty()){ //创建根部门
							dept = new Department();
							dept.setName(departmentVO.getName());
							dept.setParentid(0);
							try {
								int wxdeptId = QyApiService.createDepartment(access_token, dept);
								dept.setId(wxdeptId);
								departmentVO.setWeixinDeptId(String.valueOf(wxdeptId));
								deptProcess.doUpdate(departmentVO);
								DEPT_ADD_RESULT = true ;
							} catch (Exception e) {
								deptInfo.put("NAME",departmentVO.getName() );
								deptInfo.put("ERROR","同步部门到微信端失败" );
								deptInfo.put("TIP",e.getMessage());
								e.printStackTrace();
							}
						}else{ //更新根部门
							dept = wxDepts.get(0);
							dept.setName(departmentVO.getName());
							try {
								QyApiService.updateDepartment(access_token, dept);
								departmentVO.setWeixinDeptId(String.valueOf(dept.getId()));
								deptProcess.doUpdate(departmentVO);
								DEPT_ADD_RESULT = true ;
							} catch (Exception e) {
								deptInfo.put("NAME",departmentVO.getName() );
								deptInfo.put("ERROR","同步部门到微信端失败" );
								deptInfo.put("TIP",e.getMessage());
								e.printStackTrace();
							}
						}
						root = dept ;
						//更新结果集数量
						if(DEPT_ADD_RESULT){
							DEPT_ADD_SUCCESS ++ ;
						}else{
							DEPT_ADD_FAIL++;
						}
						
						//更新错误列表
						if(!deptInfo.isEmpty()){
							errors.add(deptInfo);
						}
						
						deptMapping.put(departmentVO.getId(), dept);
						continue;
					}
					
					boolean isSynch = false;
					for (Iterator<Department> iterator2 = wxDepts.iterator(); iterator2.hasNext();) {
						Department wxdept = iterator2.next();
						if(!StringUtil.isBlank(departmentVO.getWeixinDeptId())){
							if(String.valueOf(wxdept.getId()).equals(departmentVO.getWeixinDeptId())){
								if(!wxdept.getName().equals(departmentVO.getName())){
									wxdept.setName(departmentVO.getName());
									try {
										QyApiService.updateDepartment(access_token, wxdept);
										DEPT_ADD_RESULT = true ;
									} catch (Exception e) {
										deptInfo.put("NAME",departmentVO.getName() );
										deptInfo.put("ERROR","同步部门到微信端失败" );
										deptInfo.put("TIP",e.getMessage());
										e.printStackTrace();
									}
									
								}else{
									DEPT_ADD_RESULT = true ;
								}
								deptMapping.put(departmentVO.getId(), wxdept);
								isSynch = true;
								break;
							}
						}else{
							if(wxdept.getLevel()==departmentVO.getLevel() && wxdept.getName().equals(departmentVO.getName()) && deptMapping.get(departmentVO.getSuperior().getId())!=null && deptMapping.get(departmentVO.getSuperior().getId()).getId()==wxdept.getParentid()){
								departmentVO.setWeixinDeptId(String.valueOf(wxdept.getId()));
								try {
									deptProcess.doUpdate(departmentVO);
									DEPT_ADD_RESULT = true ;
								} catch (Exception e) {
									deptInfo.put("NAME",departmentVO.getName() );
									deptInfo.put("ERROR","同步部门到微信端失败" );
									deptInfo.put("TIP",e.getMessage());
									e.printStackTrace();
								}
								deptMapping.put(departmentVO.getId(), wxdept);
								isSynch = true;
								break;
							}
					}
				 }
					if(!isSynch){
						//在微信端创建部门
						Department dept = new Department();
						dept.setName(departmentVO.getName());
						if(departmentVO.getSuperior()==null){
							dept.setParentid(0);
						}else{
							Department wd = deptMapping.get(departmentVO.getSuperior().getId());
							if(wd !=null){
								dept.setParentid(wd.getId());
							}else{
								dept.setParentid(0);
							}
							
						}
						try {
							int wxdeptId = QyApiService.createDepartment(access_token, dept);
							departmentVO.setWeixinDeptId(String.valueOf(wxdeptId));
							dept.setId(wxdeptId);
							deptProcess.doUpdate(departmentVO);
							DEPT_ADD_RESULT = true ;
						} catch (Exception e) {
							deptInfo.put("NAME",departmentVO.getName() );
							deptInfo.put("ERROR","同步部门到微信端失败" );
							deptInfo.put("TIP",e.getMessage());
							e.printStackTrace();
						}
						deptMapping.put(departmentVO.getId(), dept);
					}
					
					//更新结果集数量
					if(DEPT_ADD_RESULT){
						DEPT_ADD_SUCCESS ++ ;
					}else{
						DEPT_ADD_FAIL++;
					}
				
					//更新错误列表
					if(!deptInfo.isEmpty()){
						errors.add(deptInfo);
					}
				}
			}
			
			//2.同步用户
			UserProcess userProcess = AuthTimeServiceManager.userRuntimeService();
			List<UserVO> users = (List<UserVO>) userProcess.queryByDomain(domain.getId());
			
			//扩展字段
			FieldExtendsProcess fieldExtendsProcess = (FieldExtendsProcess) ProcessFactory.createProcess(FieldExtendsProcess.class);
			List<FieldExtendsVO> fieldExtendses = fieldExtendsProcess.queryFieldExtendsByTable(domain.getId(), FieldExtendsVO.TABLE_USER);
			
			if(!users.isEmpty()){
				for (Iterator<UserVO> iterator = users.iterator(); iterator.hasNext();) {
					UserVO userVO = iterator.next();
					JSONObject userInfo = new JSONObject();
					User wxUser = null;
					try {
						wxUser = QyApiService.getUser(access_token, userVO.getLoginno());
					} catch (Exception e) {
						//System.out.println("user:"+userVO.getName() +"loginno:"+userVO.getLoginno()+" access_token:"+access_token);
					}
					
					boolean USER_ADD_RESULT =false ;
					
					if(wxUser != null){
						boolean needUpdate = isUpdateUserToWeiXin(userVO, wxUser, root,fieldExtendses);
						
						if(needUpdate){
							try {
								QyApiService.updateUser(access_token, wxUser);
								USER_ADD_RESULT = true ;
							} catch (Exception e) {
								userInfo.put("NAME", wxUser.getName());
								userInfo.put("ERROR", "请校验用户账号、电话、邮箱等数据的规范性");
								userInfo.put("TIP", e.getMessage());
								e.printStackTrace();
							}
						}else{
							USER_ADD_RESULT = true ;
						}
					}else{
						boolean needCreate = true;
						
						if(userVO.getStatus() != 1){
							 userInfo.put("NAME", userVO.getName());
							 userInfo.put("ERROR", "用户状态失效");
							 userInfo.put("TIP", "");
							 needCreate = false ;
						}
						if(StringUtil.isBlank(userVO.getTelephone()) && StringUtil.isBlank(userVO.getEmail())){//用户邮箱和手机都为空则不同步
							userInfo.put("NAME", userVO.getName());
							userInfo.put("ERROR", "用户邮箱和手机都为空");
							userInfo.put("TIP", "");
							needCreate = false ;
						}
						
						if(needCreate){
							User u = createUser2WeiXin(userVO, new User(), root, fieldExtendses);
							try {
								QyApiService.createUser(access_token, u);
								USER_ADD_RESULT = true ;
							} catch (Exception e) {
								userInfo.put("NAME", userVO.getName());
								userInfo.put("ERROR", "请校验用户账号、电话、邮箱等数据的规范性");
								userInfo.put("TIP", e.getMessage());
								e.printStackTrace();
							}
						}
					}
					//更新结果集数量
					if(USER_ADD_RESULT){
						USER_ADD_SUCCESS ++ ;
					}else{
						USER_ADD_FAIL++;
					}
				
					//更新错误列表
					if(!userInfo.isEmpty()){
						errors.add(userInfo);
					}
				}
			}
			//对结果数据进行统计
			result.put("USER_ADD_SUCCESS",USER_ADD_SUCCESS);
			result.put("DEPT_ADD_SUCCESS",DEPT_ADD_SUCCESS);
			result.put("USER_ADD_FAIL", USER_ADD_FAIL);
			result.put("DEPT_ADD_FAIL", DEPT_ADD_FAIL);
			result.put("ERRORS", errors);
		} catch (Exception e) {
			e.printStackTrace();
			try {
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			if(e instanceof WeixinHandleException){
				e = new OBPMValidateException(e.getLocalizedMessage(), e);
			}
			throw e;
		}
		return result;
		
	}
	
	/**
	 * 创建微信用户
	 * @param weixinCorpID
	 * 		企业号id
	 * @param weixinCorpSecret
	 * 		企业号开发凭据
	 * @param name
	 * 		用户名
	 * @param userid
	 * 		账号
	 * @param mobile
	 * 		手机
	 * @param email
	 * 		邮件
	 * @param dept
	 * 		部门id
	 * @return
	 * @throws Exception
	 */
	public static boolean createUser(String domainId,String name,String userid,String mobile,String email,Integer[] dept)  throws Exception{
		try {
			
			String access_token = QyApiService.getAccessToken(WeixinSecretCache.get(domainId));
			
			User u = new User();
			u.setUserid(userid);
			u.setName(name);
			u.setMobile(mobile);
			u.setEmail(email);
			int depts[] = new int[dept.length];
			for (int i = 0; i < dept.length; i++) {
				depts[i] = dept[i];
			}
			u.setDepartment(depts);
			
			QyApiService.createUser(access_token, u);
			return true;
		} catch (Exception e) {
			throw new OBPMValidateException(e.getLocalizedMessage(),e);
			
		}
	}
	
	public static boolean updateUser(String domainId,String name,String userid,String mobile,String email,Integer[] dept)  throws Exception{
		try {
			
			String access_token = QyApiService.getAccessToken(WeixinSecretCache.get(domainId));
			
			User u = new User();
			u.setUserid(userid);
			u.setName(name);
			u.setMobile(mobile);
			u.setEmail(email);
			int depts[] = new int[dept.length];
			for (int i = 0; i < dept.length; i++) {
				depts[i] = dept[i];
			}
			u.setDepartment(depts);
			QyApiService.updateUser(access_token, u);
			return true;
		} catch (Exception e) {
			throw new OBPMValidateException(e.getLocalizedMessage(),e);
			
		}
	}
	
	public static boolean deleteUser(String domainId,String userid)  throws Exception{
		try {
			
			String access_token = QyApiService.getAccessToken(WeixinSecretCache.get(domainId));
			
			QyApiService.deleteUser(access_token, userid);
			return true;
		} catch (Exception e) {
			throw new OBPMValidateException(e.getLocalizedMessage(),e);
			
		}
	}
	
	public static int createDepartment(String domainId,String name,Integer parentId)  throws Exception{
		try {
			String access_token = QyApiService.getAccessToken(WeixinSecretCache.get(domainId));
			
			Department d = new Department();
			d.setName(name);
			d.setParentid(parentId);
			
			return QyApiService.createDepartment(access_token, d);
			
		} catch (Exception e) {
			throw new OBPMValidateException(e.getLocalizedMessage(),e);
		}
		
	}
	
	public static void updateDepartment(String domainId,Integer id,String name,Integer parentId)  throws Exception{
		try {
			String access_token = QyApiService.getAccessToken(WeixinSecretCache.get(domainId));
			
			Department d = new Department();
			d.setId(id);
			d.setName(name);
			d.setParentid(parentId);
			
			QyApiService.updateDepartment(access_token, d);
			
		} catch (Exception e) {
			throw new OBPMValidateException(e.getLocalizedMessage(),e);
		}
		
	}
	
	public static void deleteDepartment(String domainId,String id)  throws Exception{
		try {
			String access_token = QyApiService.getAccessToken(WeixinSecretCache.get(domainId));
			
			QyApiService.deleteDepartment(access_token, id);
			
		} catch (Exception e) {
			throw new OBPMValidateException(e.getLocalizedMessage(),e);
		}
		
	}
	
	/**
	 * 删除部门下的所有用户
	 * @param weixinCorpID
	 * @param weixinCorpSecret
	 * @param deptid
	 * @throws Exception
	 */
	public static void clearDeptUsers(String corpID,String corpSecret,String deptid)  throws Exception{
		try {
			String access_token = getAccessToken(corpID, corpSecret);
			List<User> users = QyApiService.getUsersByDepartment(access_token, deptid, "1", "0");
			if(!users.isEmpty()){
				for (Iterator<User> iterator = users.iterator(); iterator.hasNext();) {
					User user = iterator.next();
					QyApiService.deleteUser(access_token, user.getUserid());
				}
			}
			
		} catch (Exception e) {
			throw new OBPMValidateException(e.getLocalizedMessage(),e);
		}
	}
	
	/**
	 * 删除部门下的所有用户
	 * @param weixinCorpID
	 * @param weixinCorpSecret
	 * @param deptid
	 * @throws Exception
	 */
	public static void clearDeptUsers(WeixinSecret weixinSecret,String deptid)  throws Exception{
		try {
			String access_token = QyApiService.getAccessToken(weixinSecret);
			List<User> users = QyApiService.getUsersByDepartment(access_token, deptid, "1", "0");
			if(!users.isEmpty()){
				for (Iterator<User> iterator = users.iterator(); iterator.hasNext();) {
					User user = iterator.next();
					QyApiService.deleteUser(access_token, user.getUserid());
				}
			}
			
		} catch (Exception e) {
			throw new OBPMValidateException(e.getLocalizedMessage(),e);
		}
	}
	
	/**
	 * 获取access_token
	 * @param corpid 企业Id
	 * @param corpsecret 管理组的凭证密钥
	 * @return
	 * @throws WeixinHandleException
	 */
	public static String getAccessToken(String corpid, String corpsecret) throws Exception{
		WeixinSecret weixinSecret = new WeixinSecret(corpid, corpsecret, "0", "", "", "");
		return  getAccessToken(weixinSecret);
	}
	
	/**
	 * 获取access_token
	 * @param corpid 企业Id
	 * @param corpsecret 管理组的凭证密钥
	 * @return
	 * @throws WeixinHandleException
	 */
	public static String getAccessToken(WeixinSecret weixinSecret) throws Exception{
		if(!validLicenseAuth()) return null;
		try {
			return QyApiService.getAccessToken(weixinSecret);
		} catch (Exception e) {
			throw e;
		}
	}
	
	/**
	 * 微信oauth2登录验证
	 * @param request
	 * @param response
	 * @param chain
	 * @throws Exception
	 */
	public static void auth(HttpServletRequest request, HttpServletResponse response,FilterChain chain) throws Exception{
		
		if(!validLicenseAuth()) return;
		
		String code = request.getParameter("code");
        String domainId = request.getParameter("state");
        String applicationId = StringUtil.isBlank(request.getParameter("application"))? request.getParameter("applicationId") : request.getParameter("application");

		String site_id = getSiteId(domainId);
		if(site_id !=null){
			authFromWeioa365(site_id,request, response,chain);
		}else{
			WeixinSecret info = WeixinSecretCache.get(domainId, applicationId);
			if(info ==null){
				return;
			}
			
			String access_token = QyApiService.getAccessToken(info);
			
			String userId = QyApiService.getUserId(access_token,code, info.getAgentId());
			
			if(!StringUtil.isBlank(userId)){
				UserProcess userProcess = AuthTimeServiceManager.userRuntimeService();
				DomainProcess domainProcess = AuthTimeServiceManager.domainRuntimeService();
				UserVO user = (UserVO) userProcess.getUserByLoginno(userId, domainId);
				if(user == null) {
					user = (UserVO) userProcess.findByTelephone(userId, domainId);
					if(user == null) {
						user = (UserVO) userProcess.findByEmail(userId, domainId);
					}
				}
				if(user !=null && user.getStatus()==1){
					User u = QyApiService.getUser(access_token, userId);
						if(!StringUtil.isBlank(u.getAvatar())){
							JSONObject json = new JSONObject();
							json.put("url", u.getAvatar());
							String Base64String = ImageUtil.transformImage2Base64String(u.getAvatar(),user.getId());
							json.put("data", StringUtil.isBlank(Base64String)?"":Base64String);
							if(!StringUtil.isBlank(Base64String)){
								json.put("isCompress", true);
							}else{
								json.put("isCompress", false);
							}							
							user.setAvatar(json.toString());
							userProcess.doUpdateWithCache(user);
					}
 					HttpSession session = request.getSession();
					
					WebUser webUser = new WebUser(user);
					DomainVO domain = (DomainVO) domainProcess.doView(domainId);
					webUser.setRecordLog(domain.getLog().booleanValue());
//					webUser.setUserSetup(user.getUserSetup());
					webUser.setServerAddr(request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+"/");
					//登录KM系统
					webUser.setEquipment(WebUser.EQUIPMENT_PHONE);
					WebUser.setWebUser(webUser, request);
					String token = Security.getToken(user.getId());
					// 存放到cookie
					Cookie cookie = new Cookie(Security.ACCESS_TOKEN, token);
					cookie.setPath("/");
					response.addCookie(cookie);
					session.setAttribute("SKINTYPE", "phone");
					session.setAttribute("visit_from_weixin", "true");
					
					LogProcess logProcess = (LogProcess) ProcessFactory.createProcess(LogProcess.class);
					try {
						if (webUser != null && webUser.isRecordLog()) {
							String ip = LogHelper.getRequestIp(request);
							LogVO log = LogVO.valueOf(webUser, "登录", "登录系统", ip);
							logProcess.doCreate(log);
						}
					} catch (Exception e) {
						throw e;
					}
				}else{
					request.getRequestDispatcher("/login/weixinnouser.html").forward(request, response);
				}
			}
		}
		
		
	
		
		
	}
	
	/**
	 * 从云端验证
	 * @param site_id
	 * @param request
	 * @param response
	 * @param chain
	 * @throws Exception
	 */
	private static void authFromWeioa365(String site_id,
			HttpServletRequest request, HttpServletResponse response,
			FilterChain chain) throws Exception {
		String code = request.getParameter("code");
		String domainId = request.getParameter("state");
		
		String userId = Weioa365WeixinService.getUserId(code, site_id);
		
		if(!StringUtil.isBlank(userId)){
			UserProcess userProcess = AuthTimeServiceManager.userRuntimeService();
			DomainProcess domainProcess = AuthTimeServiceManager.domainRuntimeService();
			UserVO user = (UserVO) userProcess.getUserByLoginno(userId, domainId);
			if(user !=null && user.getStatus()==1){
				/**
				User u = QyApiService.getUser(access_token, userId);
					if(!StringUtil.isBlank(u.getAvatar())){
					JSONObject json = new JSONObject();
					json.put("url", u.getAvatar());
					json.put("data", ImageUtil.transformImage2Base64String(u.getAvatar()+"64"));
					user.setAvatar(json.toString());
					userProcess.doUpdateWithCache(user);
				**/
				}
				HttpSession session = request.getSession();
				
				WebUser webUser = new WebUser(user);
				DomainVO domain = (DomainVO) domainProcess.doView(domainId);
				webUser.setRecordLog(domain.getLog().booleanValue());
//				webUser.setUserSetup(user.getUserSetup());
				webUser.setServerAddr(request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+"/");
				webUser.setEquipment(WebUser.EQUIPMENT_PHONE);
				WebUser.setWebUser(webUser, request);
				session.setAttribute("SKINTYPE", "phone");
				session.setAttribute("visit_from_weixin", "true");
				
				LogProcess logProcess = (LogProcess) ProcessFactory.createProcess(LogProcess.class);
				try {
					if (webUser != null && webUser.isRecordLog()) {
						String ip = LogHelper.getRequestIp(request);
						LogVO log = LogVO.valueOf(webUser, "登录", "登录系统", ip);
						logProcess.doCreate(log);
					}
				} catch (Exception e) {
					throw e;
				}
				
				chain.doFilter(request, response);
			}else{
				request.getRequestDispatcher("/login/weixinnouser.html").forward(request, response);
			}
	}

	/**
	 * 发送消息
	 * @param title 标题
	 * @param discription 描述
	 * @param touser 接收用户账号
	 * @param doc 文档对象
	 * @return
	 * @throws Exception
	 */
	public static boolean send(String title,String description,String touser,Document doc) throws Exception {
		
		if(!validLicenseAuth()) return false;
		
		String site_id = getSiteId(doc.getDomainid());
		if(!StringUtils.isBlank(site_id)){
			Weioa365WeixinService.send(site_id, doc.getDomainid(),title,description,touser,doc);
			return true;
		}
		
		WeixinSecret secret = WeixinSecretCache.get(doc.getDomainid(), doc.getApplicationid());
		if(secret == null) return false;

		//http://localhost:8080/obpm/mobile/index.html#/open?linkType=00&actionContent=tImmL1Qqjp1AeTWn0tp&docId=PkKtNEVCuLxRNVwHoxM
		String redirect_uri = URLEncoder.encode(secret.getServerHost()+"/mobile/index.html?application="+doc.getApplicationid()+"#/open?linkType=00&actionContent="+doc.getFormid()+"&docId="+doc.getId(),"utf-8");
		
		StringBuilder url = new StringBuilder("https://open.weixin.qq.com/connect/oauth2/authorize?appid=");

		url.append(secret.getCorpID())
        .append("&response_type=code&scope=snsapi_base&state=").append(doc.getDomainid())
		.append("&redirect_uri=").append(redirect_uri)
		.append("#wechat_redirect");
		
		String agentId = secret.getAgentId();
		
		NewsMessage message = new NewsMessage();
		message.setTouser(touser);
		message.setAgentid(agentId);
		New n = new New(title, description, url.toString());
		//n.setPicurl(secret.getServerHost()+"/resource/weixin/images/WeChat_pending.jpg");
		message.putNew(n);
		
		
		String access_token = QyApiService.getAccessToken(secret);
		return MessageService.send(access_token, message);
	}
	
	
	/**
	 * 发送图文消息
	 * @param touser
	 * 		用户账号列表（消息接收者，多个接收者用‘|’分隔）。特殊情况：指定为@all，则向关注该企业应用的全部成员发送
	 * @param title
	 * 		消息标题
	 * @param description
	 * 		消息描述
	 * @param url
	 * 		消息url
	 * @param picUrl
	 * 		图片url
	 * @param domainId
	 * 		企业域id
	 * @param applicationid
	 * 		发送目标软件id（null 表示发送到企业小助手）
	 * @return
	 * @throws Exception
	 */
	public static boolean sendRichTextMessage(String touser,String title,String description,String url,String picUrl,String domainId,String applicationid)  throws Exception{
		
		if(!validLicenseAuth()) return false;
		
		
		String agentId = "0";
        
		NewsMessage message = new NewsMessage();
		message.setTouser(touser);
		message.setAgentid(agentId);
		New n = new New(title, description, url.toString());
		if(!StringUtil.isBlank(picUrl)){
			n.setPicurl(picUrl);
		}
		message.putNew(n);
		
		String site_id = getSiteId(domainId);
		if(!StringUtils.isBlank(site_id)){
            // 将 applicationid 转为 云端发消息对应的 app_id
            if ("11de-f053-df18d577-aeb6-19a7865cfdb6".equals(applicationid)) {// 行政办公
                applicationid = "1";
            } else if("11e6-429d-dd7a3284-86a2-074015f7cc96".equals(applicationid)){// 客户管理
                applicationid = "6";
            } else if("11e6-292e-6f72aed4-9a78-9b801f3f5251".equals(applicationid)){// 项目管理
                applicationid = "11";
            }
			return Weioa365WeixinService.sendMessage(site_id, domainId, message.toJson(),applicationid);
		}else{
	        WeixinSecret secret = WeixinSecretCache.get(domainId, applicationid);
			if(secret == null) return false;
			message.setAgentid(secret.getAgentId());
			String access_token = QyApiService.getAccessToken(secret);
			return MessageService.send(access_token, message);
		}
		
	}
	
	/**
	 * 发送文本消息
	 * @param touser
	 * 		用户账号列表（消息接收者，多个接收者用‘|’分隔）。特殊情况：指定为@all，则向关注该企业应用的全部成员发送
	 * @param content
	 * 		消息内容
	 * @param domainId
	 * 		企业域id
	 * @param applicationid
	 * 		发送目标软件id（null 表示发送到企业小助手）
	 * @return
	 * @throws Exception
	 */
	public static boolean sendTextMessage(String touser,String content,String domainId,String applicationid)  throws Exception{
		
		if(!validLicenseAuth()) return false;
		
		String agentId = "0";
//		ApplicationProcess appProcess = (ApplicationProcess) ProcessFactory.createProcess(ApplicationProcess.class);
//		if(StringUtil.isBlank(applicationid)){
//			DomainApplicationSet domainApplicationSet = appProcess.findDomainApplicationSet(domainId, applicationid);
//			agentId = domainApplicationSet !=null && StringUtil.isBlank(domainApplicationSet.getWeixinAgentId())? "0" : domainApplicationSet.getWeixinAgentId();
//		}
		
		TextMessage message = new TextMessage(touser, content);
		message.setAgentid(agentId);
		
		String site_id = getSiteId(domainId);
		if(!StringUtils.isBlank(site_id)){
		    // 将 applicationid 转为 云端发消息对应的 app_id
            if ("11de-f053-df18d577-aeb6-19a7865cfdb6".equals(applicationid)) {// 行政办公
                applicationid = "1";
            } else if("11e6-429d-dd7a3284-86a2-074015f7cc96".equals(applicationid)){// 客户管理
                applicationid = "6";
            } else if("11e6-292e-6f72aed4-9a78-9b801f3f5251".equals(applicationid)){// 项目管理
                applicationid = "11";
            }
			return Weioa365WeixinService.sendMessage(site_id, domainId, message.toJson(),applicationid);
		}else{
		    WeixinSecret secret = null;
		    if("3".equals(applicationid)){
		        secret = WeixinSecretCache.get(domainId, "pm");
		    } else if("12".equals(applicationid)){
                secret = WeixinSecretCache.get(domainId, "qm");
		    } else {
		        secret = WeixinSecretCache.get(domainId, applicationid);
		    }
			if(secret == null) return false;
			message.setAgentid(secret.getAgentId());
			String access_token = QyApiService.getAccessToken(secret);
			return MessageService.send(access_token, message);
		}
	}
	
	/**
	 * 发送微信消息
	 * @param json
	 * 		微信消息(JSON格式 参考微信平台API文档)
	 * @param domainId
	 * 		企业域id
	 * @return
	 * @throws Exception
	 */
	public static boolean sendMessage(String json,String domainId)  throws Exception{
		if(!validLicenseAuth()) return false;
		String site_id = getSiteId(domainId);
		if(!StringUtils.isBlank(site_id)){
			return Weioa365WeixinService.sendMessage(site_id, domainId,json,"");
		}else{
			WeixinSecret secret = WeixinSecretCache.get(domainId);
			if(secret == null) return false;
			
			String access_token = QyApiService.getAccessToken(secret);
			return MessageService.send(access_token, json);
		}
	}
	
	/**
	 * 验证微信回调URL
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public static void validWeixinUrl(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setCharacterEncoding("UTF-8");//设置Response的编码方式为UTF-8
	    response.setHeader("Content-type","text/html;charset=UTF-8");
		PrintWriter out = response.getWriter();  
		if(!validLicenseAuth()) {
			
			out.write("您的License没有对微信企业号功能进行授权，相关接口调用失败！");
			return;
		}
		// 微信加密签名  
        String msg_signature = request.getParameter("msg_signature");  
        // 时间戳  
        String timestamp = request.getParameter("timestamp");  
        // 随机数  
        String nonce = request.getParameter("nonce");  
        // 加密的随机字符串，以msg_encrypt格式提供。需要解密并返回echostr明文，解密后有random、msg_len、msg、$CorpID四个字段，其中msg即为echostr明文
        String echostr = request.getParameter("echostr");  
        
        String domain = request.getParameter("domain");
  
    	try {
			WeixinSecret wxSecret = WeixinSecretCache.get(domain);
			if(wxSecret == null) {
				out.write("您的企业域还没有绑定微信企业号！");
				return;
			}
			String token = wxSecret.getToken();
			String encodingAESKey = wxSecret.getEncodingAESKey();
			String corpId = wxSecret.getCorpID();
			
			WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpId);
	
			String result = wxcpt.VerifyURL(msg_signature, timestamp, nonce, echostr);
			out.write(result);
			//System.out.println("result--->"+result);
		} catch (Exception e) {
			out.write("解码阶段发生异常："+e.getMessage());
		}
    	out.flush();
    	out.close();  
	}
	
	/**
	 * 处理微信事件回调业务
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public static void handelWeixinCallbackEvent(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		if(!validLicenseAuth()) return;
		// 微信加密签名  
        String msg_signature = request.getParameter("msg_signature");  
        // 时间戳  
        String timestamp = request.getParameter("timestamp");  
        // 随机数  
        String nonce = request.getParameter("nonce");  
        //post请求的密文数据
        String postData = WeixinHttpsRequestUtil.getHttpPostDataAsString(request);
        
        String domain = request.getParameter("domain");
        
        String eventXML = null;
        WeixinSecret wxSecret = null;
        try {
			wxSecret = WeixinSecretCache.get(domain);
			if(wxSecret == null) return;
			String token = wxSecret.getToken();
			String encodingAESKey = wxSecret.getEncodingAESKey();
			String corpId = wxSecret.getCorpID();
			WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpId);
			
			eventXML = wxcpt.DecryptMsg(msg_signature, timestamp, nonce, postData);
			//System.out.println("postData--->"+eventXML);
		} catch (Exception e) {
			
		}
			
        if(eventXML ==null) return;
        
        try {
        	org.dom4j.Document doc = DocumentHelper.parseText(eventXML);
			Element root =  doc.getRootElement();
			String msgType = root.elementText("MsgType");
			
			if(msgType.equals("event")){//事件消息
				EventCallbackService.handleEvent(eventXML, domain);
			}
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        response.setStatus(200);
	}
	
	/**
	 * 获取微信js接口授权配置
	 * @param url
	 * @param domainId
	 * @return
	 * @throws Exception
	 */
	public static Map<String,String> getJsapiConfig(String url,String domainId) throws Exception{
		try {
			String site_id = getSiteId(domainId);
			if(!StringUtils.isBlank(site_id)){
				return Weioa365WeixinService.getJsapiConfig(url, site_id, domainId);
			}
			
			WeixinSecret secret = WeixinSecretCache.get(domainId);
			if(secret == null) return null;
			
			String access_token = QyApiService.getAccessToken(secret);
			String jsapi_ticket = QyApiService.getJsapiTicket(access_token, secret.getCorpID());
			
			Map<String, String> config = JsapiTicketSignUtil.sign(jsapi_ticket, url);
			config.put("appId", secret.getCorpID());
			return config;
			/**
			String key = url+"|"+domainId;
			JsapiSignature jsapiSignature = JsapiSignatureCache.get(key);
			if(jsapiSignature != null){
				return jsapiSignature.getConfig();
			}
			**/
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}
	
	
	/**
	 * 下载微信多媒体资源文件
	 * @param domainId
	 * 		企业域id
	 * @param media_id
	 * 		媒体资源id
	 * @param fileName
	 * 		下载到本地服务器的完整文件名
	 * @throws Exception
	 */
	public static void downloadMedia(String domainId,String media_id,String fileName) throws Exception{
		try{
			String site_id = getSiteId(domainId);
			if(!StringUtils.isBlank(site_id)){
				Weioa365WeixinService.downloadMedia(site_id, domainId,media_id,fileName);
				return;
			}
			
			WeixinSecret secret = WeixinSecretCache.get(domainId);
			if(secret == null) return ;
			
			String access_token = QyApiService.getAccessToken(secret);
			
			MediaService.downloadMedia(access_token, media_id, fileName);
			
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}
	
	/**
	 * 获取企业号id
	 * @param site_id
	 * 		客户端唯一标示
	 * @param domainId
	 * 		企业域id
	 * @return
	 * @throws WeixinHandleException
	 */
	public static String getCorpId(String site_id,String domainId) throws Exception {
		return Weioa365WeixinService.getCorpId(site_id, domainId);
	}
	
	private static String getSiteId(String domainId){
		try {
			DomainProcess process = AuthTimeServiceManager.domainRuntimeService();
			DomainVO vo = (DomainVO) process.doView(domainId);
			if(vo!=null && DomainVO.WEIXIN_PROXY_TYPE_CLOUD.equals(vo.getWeixinProxyType())) {
				return Environment.getMACAddress();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	
	
	/**
	 * 清空微信配置信息缓存
	 * @throws Exception
	 */
	public static void cleanWeixinSecretCache() throws Exception{
		WeixinSecretCache.clear();
		QyApiService.clearAccessToken();
	} 
	
	private static boolean validLicenseAuth() {
		boolean falg = false;
		falg = true;
//		falg = WarpProcessFactory.isWeixinEnable();
		if(!falg){
			System.err.println("您的License没有对微信企业号功能进行授权，相关接口调用失败！");
		}
		
		return falg;
	}
/**
 * 微信端创建用户
 * @param userVO
 * 			客户端用户对象
 * @param wxUser
 * 			微信端对象
 * @param root
 * 			根部门
 * @param fieldExtendses
 * 			扩展字段集合
 * @return
 */
private static User createUser2WeiXin(UserVO userVO,User wxUser, Department root , List<FieldExtendsVO> fieldExtendses){
	
	//基础数据
	wxUser.setUserid(userVO.getLoginno());
	wxUser.setName(userVO.getName());
	wxUser.setMobile(userVO.getTelephone() != null && userVO.getTelephone().trim().length()==11? userVO.getTelephone().trim() : null);
	wxUser.setEmail(userVO.getEmail() != null ? userVO.getEmail().trim() : "");
	
	//部门字段
	int[] depts ;
	Collection<DepartmentVO> departments = userVO.getDepartments();
	if(!departments.isEmpty()){
		depts = new int[departments.size()];
		int index = 0 ;
		for(DepartmentVO dept : departments){
			String weixinDeptId = dept.getWeixinDeptId();
			if(!StringUtil.isBlank(weixinDeptId)){
				depts[index++] = Integer.parseInt(weixinDeptId);
			}
		}
	}else{
		depts = new int[1];
		depts[0] = root.getId();
	}
	wxUser.setDepartment(depts);
	
	//扩展字段
	JSONObject extattr = new JSONObject();
	JSONArray attrs = new JSONArray();
	
	for(int i = 0;i < fieldExtendses.size(); i++){
		FieldExtendsVO fevo = fieldExtendses.get(i);
		JSONObject attr = new JSONObject();
		if(fevo != null && fevo.getEnabel()){
			String value = fevo.getValue(userVO);
			if(StringUtil.isBlank(value)){
				attr.put("name", fevo.getLabel());
				attr.put("value", "");
			}else{
				attr.put("name", fevo.getLabel());
				attr.put("value", fevo.getValue(userVO));
			}
			attrs.add(attr);
		}
	}
	extattr.put("attrs", attrs);
	wxUser.setExtattr(extattr.toString());
	
	return wxUser;
	
}
/**
 * 本地同步数据至微信端：详细信息校验(基本信息，根部门，扩展字段)	
 * @param userVO
 * 				客户端对象
 * @param wxUser
 * 				微信端对象
 * @param root
 * 				根部门
 * @param fieldExtendMapping
 * 				扩展字段集合
 * @return
 */
private static boolean isUpdateUserToWeiXin(UserVO userVO,User wxUser, Department root , List<FieldExtendsVO> fieldExtendses){
		boolean isUpdateUser = false ;
		//基本信息
		if(userVO.getStatus() == 0 && wxUser.getEnable() == 1){
			wxUser.setEnable(0);
			isUpdateUser = true;
		}
		if(!wxUser.getName().equals(userVO.getName()) || 
				(!StringUtil.isBlank(userVO.getTelephone()) && !userVO.getTelephone().trim().equals(wxUser.getMobile())) || 
				(!StringUtil.isBlank(userVO.getEmail()) && !userVO.getEmail().equals(wxUser.getEmail())) ){
			wxUser.setName(userVO.getName());
			wxUser.setMobile(!StringUtil.isBlank(userVO.getTelephone())?userVO.getTelephone().trim():wxUser.getMobile());
			wxUser.setEmail(!StringUtil.isBlank(userVO.getEmail())?userVO.getEmail().trim():wxUser.getEmail());
			isUpdateUser = true;
		}
		
		//扩展字段
		JSONObject extattr = new JSONObject();
		JSONArray attrs = new JSONArray();
		for(int index = 0; index < fieldExtendses.size(); index++){
			FieldExtendsVO fevo = fieldExtendses.get(index);
			JSONObject attr = new JSONObject();
			if(fevo != null && fevo.getEnabel()){
				String value = fevo.getValue(userVO);
				if(StringUtil.isBlank(value)){
					attr.put("name", fevo.getLabel());
					attr.put("value", "");
				}else{
					attr.put("name", fevo.getLabel());
					attr.put("value", fevo.getValue(userVO));
				}
				attrs.add(attr);
			}
		}
		extattr.put("attrs", attrs);
		JSONObject wxExtattr = JSONObject.fromObject(wxUser.getExtattr());
		JSONArray wxAttrs = (JSONArray) wxExtattr.get("attrs");
		if(wxAttrs.isEmpty() && attrs.size() > 0){
			wxUser.setExtattr(extattr.toString());
			isUpdateUser = true;
		}else{
			attr:for( int attrIndex = 0 ; attrIndex < attrs.size() ; attrIndex ++ ){
				JSONObject attr = attrs.getJSONObject(attrIndex);
				for(int wxAttrIndex = 0 ; wxAttrIndex < wxAttrs.size() ; wxAttrIndex ++ ){
					JSONObject wxAttr =wxAttrs.getJSONObject(wxAttrIndex);
					if(wxAttr.get("name").equals(attr.get("name"))){
						if(!wxAttr.get("value").equals(attr.get("value"))){
							wxUser.setExtattr(extattr.toString());
							isUpdateUser = true;
							break attr;
						}
					}
				}
			}
		}
		
		//部门字段
		int[] depts ;
		Collection<DepartmentVO> departments = userVO.getDepartments();
		if(departments.size() > 0 ){
			depts = new int[departments.size()];
			int index = 0 ;
			for(DepartmentVO dept : departments){
				String weixinDeptId = dept.getWeixinDeptId();
				if(!StringUtil.isBlank(weixinDeptId)){
					depts[index++] = Integer.parseInt(weixinDeptId);
				}
			}
		}else{
			depts = new int[1];
			depts[0] = root.getId();
		}
		
		if(wxUser.getDepartment() != depts){
			wxUser.setDepartment(depts);
			isUpdateUser = true;
		}
	
		return isUpdateUser;
}
	
/**
 * 微信端同步数据到本地：基本信息校验(基本信息，头像)
 * @param userVO
 * 			客户端对象
 * @param wxUser
 * 			微信端对象
 * @return
 */
private static boolean isUpdateUserFromWeiXin(UserVO userVO,User wxUser){
	return isUpdateUserFromWeiXin(userVO,wxUser,null,null);
}
/**
 * 微信端同步数据到本地：详细信息校验(基本信息，头像，部门，扩展字段)	
 * @param userVO
 * 				客户端对象
 * @param wxUser
 * 				微信端对象
 * @param deptMapping
 * 				部门映射MAP<微信部门id,客户端部门对象>
 * @param fieldExtendMapping
 * 				扩展字段集合
 * @return
 */
private static boolean isUpdateUserFromWeiXin(UserVO userVO,User wxUser, Map<Integer, DepartmentVO> deptMapping ,List<FieldExtendsVO> fieldExtendMapping){
		boolean isUpdateUser = false ;
		//基本信息
		if(!userVO.getName().equals(wxUser.getName()) || 
				(userVO.getTelephone() !=null && !userVO.getTelephone().equals(wxUser.getMobile())) || 
				(userVO.getEmail() !=null && !userVO.getEmail().equals(wxUser.getEmail()))  || 
				(wxUser.getMobile() !=null && !wxUser.getMobile().equals(userVO.getTelephone())) || 
				(wxUser.getEmail() !=null && !wxUser.getEmail().equals(userVO.getEmail()))){
			userVO.setName(wxUser.getName());
			userVO.setTelephone(wxUser.getMobile());
			userVO.setEmail(wxUser.getEmail());
			isUpdateUser = true;
		}
		
		//头像
		if(!StringUtil.isBlank(userVO.getAvatarUri()) && !StringUtil.isBlank(wxUser.getAvatar()) && !userVO.getAvatarUri().equals(wxUser.getAvatar())){
			if(!StringUtil.isBlank(wxUser.getAvatar())){
				JSONObject json = new JSONObject();
				json.put("url", wxUser.getAvatar());
				String Base64String = ImageUtil.transformImage2Base64String(wxUser.getAvatar(),userVO.getId());
				json.put("data", StringUtil.isBlank(Base64String)?"":Base64String);
				if(!StringUtil.isBlank(Base64String)){
					json.put("isCompress", true);
				}else{
					json.put("isCompress", false);
				}
				userVO.setAvatar(json.toString());
				isUpdateUser = true;
			}
		}
		
		//所属部门
		if(deptMapping != null && !deptMapping.isEmpty()){
			for (int i = 0; i < wxUser.getDepartment().length; i++) {
				boolean isExist = false;
				String deptId = deptMapping.get(wxUser.getDepartment()[i]).getId();
				DepartmentVO dept = null ;
				for(DepartmentVO _dept : userVO.getDepartments()){
					dept = _dept ;
					if(dept.getId().equals(deptId)){
						isExist = true ;
						break;
					}
				}
				if(!isExist){
					UserDepartmentRoleSet userDepartmentSet = new UserDepartmentRoleSet(userVO.getId(), deptId,"");
					userVO.getUserDepartmentRoleSets().add(userDepartmentSet);
					userVO.getDepartments().add(dept);
					isUpdateUser = true;
				}
			}
		}
		
		//扩展字段
		if(fieldExtendMapping != null && !fieldExtendMapping.isEmpty()){
			try {
				JSONObject extattr = JSONObject.fromObject(wxUser.getExtattr());
				JSONArray attrs  = extattr.getJSONArray("attrs");
				for(FieldExtendsVO fieldExtend : fieldExtendMapping){
					String name = fieldExtend.getLabel();
					for(int index = 0 ; index < attrs.size() ; index ++){
						JSONObject attr = attrs.getJSONObject(index);
						if(name.equals(attr.getString("name"))){
							String fieldName = fieldExtend.getName();
							fieldName = fieldName.replaceFirst("f","F");
							Method gmethod = UserVO.class.getMethod("get" + fieldName);
							String v = (String) gmethod.invoke(userVO);
							if(!attr.get("value").equals(v)){//更新扩展字段值
								Method method = UserVO.class.getMethod("set" + fieldName,String.class);
								method.invoke(userVO,attr.get("value"));
								isUpdateUser = true;
								break;
							}
						}
					}
				}
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
		return isUpdateUser;
	}
	
}
