package com.platform.modules.trtc.socket;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import org.springframework.stereotype.Component;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.platform.common.utils.SpringContextUtils;
import com.platform.modules.trtc.service.TrtcService;

import net.sf.json.JSONObject;

/**
 * 
 * 虽然@Component默认是单例模式的，但是spring boot
 * 还是会为每个websocket连接初始化一个bean,所以这里使用一个静态的set保存spring boot
 * 
 * 创建的bean--MyWebSocket.
 * 
 * @author weiyan
 * @date 2019-07-27
 */
@ServerEndpoint(value = "/websocket2/{uid}") // websocket连接点映射.
@Component
public class WebSocket2 {

	// 用来存储每个客户端对应的MyWebSocket对象.
	private static CopyOnWriteArraySet<WebSocket2> webSocketSet = new CopyOnWriteArraySet<WebSocket2>();
	// 用来记录userId和该session之间的绑定关系.
	private static Map<Long, List<Session>> map = new HashMap<Long, List<Session>>();
	
	private Session session;// 当前会话的session.
	private Long userId;// 用户ID
	
	private TrtcService trtcService; 

	/**
	 * 成功建立连接调用的方法.
	 */
	@OnOpen
	public void onOpen(Session session, @PathParam("uid") String uid) {
		if(uid=="" || uid.equals("") || uid==null || uid.equals(null) || uid=="null" || uid.equals("null") || uid=="undefined" || uid.equals("undefined")){
			return;
		}
		this.session = session;
		this.userId = Long.valueOf(uid);
		this.trtcService = (TrtcService) SpringContextUtils.getBean("trtcService");
		
//		List<Session> list = map.get(userId);
//		if (list == null) {
//			list = new ArrayList<Session>();
//		}
//		list.add(session);
//		map.put(this.userId, list);
//		webSocketSet.add(this);// 加入set中.
//		SocketMsg socketMsg = new SocketMsg();
//		socketMsg.setFromUserId(this.userId);
//		socketMsg.setType(10010);
//		trtcService.updateReporterStatusRedisById(this.userId, 1);
//		broadcast(socketMsg, this.userId);
//		Integer state = trtcService.getReporterOnLineRedisById(userId);
//		SocketMsg socketMsg = new SocketMsg();
//		socketMsg.setFromUserId(this.userId);
//		if(state!=0){
//			synchronized(session){
//				try {
//					socketMsg.setType(99997);
//					session.getBasicRemote().sendText(JSONObject.fromObject(socketMsg).toString());
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
//			}
//		}else{
//			List<Session> list = map.get(userId);
//			if (list == null) {
//				list = new ArrayList<Session>();
//			}
//			list.add(session);
//			map.put(userId, list);
//			webSocketSet.add(this);// 加入set中.
//			trtcService.updateReporterStatusRedisById(userId, 1);
//			socketMsg.setType(10010);
//			broadcast(socketMsg, userId);
//		}
	}

	/**
	 * 连接关闭调用的方法.
	 */
	@OnClose
	public void onClose(Session session, @PathParam("uid") String uid) {
		webSocketSet.remove(this);// 从set中移除.
//		if(userId!=null){
//			SocketMsg socketMsg = new SocketMsg();
//			socketMsg.setFromUserId(userId);
//			socketMsg.setType(10011);
//			broadcast(socketMsg, userId);
//			trtcService.deleteReporterStatusRedisById(userId);
//		}
//		if(map!=null && map.size()>0){
//			Iterator<Long> iterator = map.keySet().iterator();
//		    while (iterator.hasNext()) {
//		    	Long key = iterator.next();
//		    	List<Session> sessionList = new ArrayList<Session>();
//				List<Session> sessions = map.get(key);
//				if(sessions!=null && sessions.size()>0){
//					for(Session s : sessions){
//						if(s!=null && s.getId()!=null && (s.getId()!=session.getId() && !s.getId().equals(session.getId()))){
//							sessionList.add(s);
//						}
//					}
//					if(sessionList==null || sessionList.size()==0){
//						iterator.remove(); 
//						map.remove(key);
//					}else{
//						map.put(key, sessionList);
//					}
//				}else{
//					iterator.remove();        //添加该行代码
//					map.remove(key);
//				}
//		    }
//		}
		if(uid=="" || uid.equals("") || uid==null || uid.equals(null) || uid=="null" || uid.equals("null") || uid=="undefined" || uid.equals("undefined")){
			return;
		}
		this.userId = Long.valueOf(uid);
		if(uid=="" || uid.equals("") || uid==null || uid.equals(null) || uid=="null" || uid.equals("null") || uid=="undefined" || uid.equals("undefined")){
			return;
		}
		this.userId = Long.valueOf(uid);
		List<Session> sessionList = map.get(this.userId);// 用于处理接收者打开多个窗口
		List<Session> list = new ArrayList<Session>();// 用于处理接收者打开多个窗口
		if (sessionList != null && sessionList.size() > 0) {
			for(Session s : sessionList){
				if(s.getId()==session.getId()){
					list.add(s);
				}
			}
			sessionList.retainAll(list);
			map.put(this.userId, sessionList);
		}
		webSocketSet.remove(session);
//		try {
//			session.close();
//			webSocketSet.remove(session);
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
	}

	/**
	 * 收到客户端消息后调用的方法.
	 */
	@OnMessage
	public void onMessage(String message, Session session, @PathParam("uid") String uid) {
		// message 不是普通的string ，而是我们定义的SocketMsg json字符串.
		try {
			if(uid=="" || uid.equals("") || uid==null || uid.equals(null) || uid=="null" || uid.equals("null") || uid=="undefined" || uid.equals("undefined")){
				return;
			}
			this.userId = Long.valueOf(uid);
			
			SocketMsg socketMsg = new ObjectMapper().readValue(message, SocketMsg.class);

			// 单聊.
			if (socketMsg.getType() >= 10002 && socketMsg.getType()<=10009) {
				// 单聊：需要找到发送者和接受者即可.
				//socketMsg.setFromUserId(userId);// 发送者.
				// socketMsg.setToUser(toUser);//这个是由客户端进行设置.
				List<Session> fromSessionList = map.get(socketMsg.getFromUserId());// 用于处理发送者打开多个窗口
				List<Session> toSessionList = map.get(socketMsg.getToUserId());// 用于处理接收者打开多个窗口
				if (toSessionList != null && toSessionList.size() > 0) {
					Map<String, Integer> m = new HashMap<String, Integer>();// 用于发送者重复接受
					Map<String, Integer> tm = new HashMap<String, Integer>();// 用于接收者重复接受
					for (Session toSession : toSessionList) {
						if (toSession == null || toSession.getId()==null || toSession.getId()==this.session.getId()) {
							continue;
						}
						if (!tm.containsKey(toSession.getId())) {
//						    toSession.getAsyncRemote().sendText(JSONObject.fromObject(socketMsg).toString());
							synchronized(toSession){
								try {
									tm.put(toSession.getId(), 1);
									toSession.getBasicRemote().sendText(JSONObject.fromObject(socketMsg).toString());
								} catch (Exception e) {
									e.printStackTrace();
								}
							}
						}
						if (fromSessionList != null && fromSessionList.size() > 1) {
							for (Session fromSession : fromSessionList) {
								if (fromSession != null && fromSession.getId()!=null && fromSession.getId()!=this.session.getId()) {
									if (!m.containsKey(fromSession.getId())) {
										m.put(fromSession.getId(), 1);
										// 发送消息.
//										fromSession.getAsyncRemote().sendText(JSONObject.fromObject(socketMsg).toString());
										synchronized(fromSession){
											try {
												fromSession.getBasicRemote().sendText(JSONObject.fromObject(socketMsg).toString());
											} catch (Exception e) {
												e.printStackTrace();
											}
										}
									}
								}
							}
						}
					}
					
				} else {
					if (fromSessionList != null && fromSessionList.size() > 0) {
						for (Session fromSession : fromSessionList) {
							if (fromSession != null &&fromSession.getId()!=null) {
								socketMsg.setType(99999);
								synchronized(fromSession){
									try {
										fromSession.getBasicRemote().sendText(JSONObject.fromObject(socketMsg).toString());
									} catch (Exception e) {
										e.printStackTrace();
									}
								}
							}
						}
					}
				}
				if(socketMsg.getType() == 10004 ){
					socketMsg.setType(10012);
					broadcast(socketMsg, userId);
					trtcService.updateReporterStatusRedisById(userId, 2);
					trtcService.updateReporterStatusRedisById(socketMsg.getToUserId(), 2);
					socketMsg.setFromUserId(socketMsg.getToUserId());
					socketMsg.setFromUserName(socketMsg.getToUserName());
					socketMsg.setFromUserImg(socketMsg.getToUserImg());
					socketMsg.setToUserId(userId);
					socketMsg.setToUserName("");
					socketMsg.setToUserImg("");
					broadcast(socketMsg, socketMsg.getToUserId());
				}else if(socketMsg.getType() == 10005 || socketMsg.getType() == 10007 || socketMsg.getType() == 10008 || socketMsg.getType() == 10009){
					socketMsg.setType(10010);
					broadcast(socketMsg, userId);
					trtcService.updateReporterStatusRedisById(userId, 1);
					trtcService.updateReporterStatusRedisById(socketMsg.getToUserId(), 1);
					socketMsg.setFromUserId(socketMsg.getToUserId());
					socketMsg.setFromUserName(socketMsg.getToUserName());
					socketMsg.setFromUserImg(socketMsg.getToUserImg());
					socketMsg.setToUserId(userId);
					socketMsg.setToUserName("");
					socketMsg.setToUserImg("");
					broadcast(socketMsg, socketMsg.getToUserId());
				}
			} else if (socketMsg.getType() == 10000){//上线
				Integer state = trtcService.getReporterOnLineRedisById(userId);
				List<Session> list = map.get(userId);
				if (list == null) {
					list = new ArrayList<Session>();
				}
				list.add(session);
				map.put(userId, list);
				webSocketSet.add(this);
				if(state!=0){
					synchronized(session){
						try {
							socketMsg.setType(99997);
							session.getBasicRemote().sendText(JSONObject.fromObject(socketMsg).toString());
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}else{
					// 加入set中.
					trtcService.updateReporterStatusRedisById(userId, 1);
					socketMsg.setType(10010);
					broadcast(socketMsg, userId);
				}
			} else if (socketMsg.getType() == 10001){//下线
				List<Session> sessionList = map.get(socketMsg.getFromUserId());
				if(sessionList==null || sessionList.size()<=1){
					socketMsg.setType(10011);
					broadcast(socketMsg, userId);
					map.remove(userId);
					trtcService.deleteReporterStatusRedisById(userId);
				}else{
					List<Session> sessions = new ArrayList<Session>();
					if(sessionList!=null && sessionList.size()>0){
						for(Session s : sessionList){
							if(s!=null && s.getId()!=null && (s.getId()!=session.getId() && !s.getId().equals(session.getId()))){
								sessions.add(s);
							}
						}
						if(sessions==null || sessions.size()==0){
							map.remove(userId);
						}else{
							map.put(userId, sessions);
						}
					}else{
						map.remove(userId);
					}
				}
				session.close();
				webSocketSet.remove(session);// 从set中移除.
			} else if(socketMsg.getType() == 10010){
				List<Session> list = map.get(userId);
				if (list == null) {
					list = new ArrayList<Session>();
				}
				list.add(session);
				map.put(userId, list);
				webSocketSet.add(this);// 加入set中.
				trtcService.updateReporterStatusRedisById(userId, 1);
				socketMsg.setType(10010);
				broadcast(socketMsg, userId);
			}else if(socketMsg.getType() == 99998){//强制下线
				List<Session> sessionList = map.get(socketMsg.getFromUserId());// 用于处理接收者打开多个窗口
				List<Session> list = new ArrayList<Session>();// 用于处理接收者打开多个窗口
				if (sessionList != null && sessionList.size() > 0) {
					for(Session s : sessionList){
						if(s==null || s.getId()==null || s.getId()==session.getId()  || !s.isOpen()){
							continue;
						}
						synchronized(s){
							try {
								s.getBasicRemote().sendText(JSONObject.fromObject(socketMsg).toString());
								s.close();
								list.add(s);
								webSocketSet.remove(s);
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
					}
					sessionList.removeAll(list);
					map.put(socketMsg.getFromUserId(), sessionList);
				}
			}else{
				// 群发给每个客户端.
//				broadcast(socketMsg, userId);
			}
		} catch (JsonParseException e) {
			e.printStackTrace();
		} catch (JsonMappingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 发生错误时调用.
	 */
	@OnError
	public void onError(Session session, Throwable error, @PathParam("uid") String uid) {
		System.out.println("onError:::id=" + session.getId()+";;;;;userId:::"+uid + "的用户,连接出错,原因:" + error);
		if(uid=="" || uid.equals("") || uid==null || uid.equals(null) || uid=="null" || uid.equals("null") || uid=="undefined" || uid.equals("undefined")){
			return;
		}
		this.userId = Long.valueOf(uid);
		SocketMsg socketMsg = new SocketMsg();
		socketMsg.setFromUserId(Long.valueOf(uid));
		socketMsg.setType(11111);
		synchronized(session){
			try {
				session.getBasicRemote().sendText(JSONObject.fromObject(socketMsg).toString());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		List<Session> sessionList = map.get(this.userId);// 用于处理接收者打开多个窗口
		List<Session> list = new ArrayList<Session>();// 用于处理接收者打开多个窗口
		if (sessionList != null && sessionList.size() > 0) {
			for(Session s : sessionList){
				if(s.getId()==session.getId()){
					list.add(s);
					webSocketSet.remove(s);
				}
			}
			sessionList.removeAll(list);
			map.put(this.userId, list);
		}
		webSocketSet.remove(session);
	}

	/**
	 * 群发的方法.
	 * 
	 * @param message
	 */
	private void broadcast(SocketMsg socketMsg, Long userId) {
		for (WebSocket2 item : webSocketSet) {
			// 发送消息.
			Session s = item.session;
			if(s!=null && s.getId()!=null && s.isOpen()){
				synchronized(s){
					try {
						s.getBasicRemote().sendText(JSONObject.fromObject(socketMsg).toString());
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
}
