package com.gyee.frame.netty.websocket;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.gyee.frame.common.conf.ExceptJobConfig;
import com.gyee.frame.common.conf.UserLoginContext;
import com.gyee.frame.common.quartz.SocketTaskUtil;
import com.gyee.frame.common.spring.SpringUtils;
import com.gyee.frame.netty.websocket.util.WebsocketUtil;
import com.gyee.frame.service.GyeeuserService;
import com.gyee.frame.util.StringUtils;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.net.BindException;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
/**
 *@author:Wang Jiawen
 *
 *@description: socketserver 封装类
 *
 *@createTime:2019/12/31
 *
 */

@ServerEndpoint(value = "/websocket/{userid}/{objectid}",encoders = { ServerEncoder.class })
@Component
public class WebSocketServer extends SocketTaskUtil {

	static Log log=LogFactory.get(WebSocketServer.class);
    //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
////    //功能名称与页面名称为key 举例 用户编号_对象编号>>WebSocketServer
//    private static Map<String,WebSocketServer> webSocketMap = new HashMap();

    private static ConcurrentHashMap<String, CopyOnWriteArraySet<WebSocketServer>> webSocketMapSet = new ConcurrentHashMap();

    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;
    //接收sid
    private String sid="";
    //用户编号
    private String userid="";
    //对象编号
    private String objectid="";

    //用户编号和对象编号组合key
    private String jobkey="";
   
    /**
     * 连接建立成功调用的方法*/
    @OnOpen
    public void onOpen(Session session, @PathParam("userid") String userid, @PathParam("objectid") String objectid ) {

        if(null!=session && null!=userid && null!=objectid)
        {
            log.info("有新窗口开始监听:用户编号:"+userid+",对象编号:"+objectid+",当前在线人数为" + getOnlineCount());
            //目标连接成功后注入基本信息
            this.session = session;

            this.sid=session.getId();
            this.userid=userid; //用户编号
            this.objectid=objectid;//对象编号

            StringBuilder sb=new StringBuilder();
            sb.append(userid).append("_").append(objectid);

            jobkey=String.valueOf(sb);



            //用户编号和对象编号组合 作为KEY，保存对应的set集合
            if(webSocketMapSet.containsKey(jobkey))
            {
                CopyOnWriteArraySet<WebSocketServer> set=webSocketMapSet.get(jobkey);
                set.add(this);
                webSocketMapSet.put(jobkey,set);
            }else
            {
                CopyOnWriteArraySet<WebSocketServer> set=new CopyOnWriteArraySet<>();
                set.add(this);
                webSocketMapSet.put(jobkey,set);
            }

            addOnlineCount();           //在线数加1

            log.info("连接成功");

        }



    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session, @PathParam("userid") String userid,@PathParam("objectid") String objectid ) {

        if(null!=session && null!=userid && null!=objectid)
        {
            log.info("有一连接关闭！当前在线人数为" + getOnlineCount());
            StringBuilder sb=new StringBuilder();
            sb.append(userid).append("_").append(objectid);

            jobkey=String.valueOf(sb);


            if(webSocketMapSet.containsKey(jobkey))
            {
                CopyOnWriteArraySet<WebSocketServer> set=webSocketMapSet.get(jobkey);

                for(WebSocketServer ws:set)
                {
                    if(ws.session.getId().equals(session.getId()))
                    {
                        set.remove(ws);
                        webSocketMapSet.put(jobkey,set);
                    }
                }

            }
            subOnlineCount();           //在线数减1
        }

    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(Session session,@PathParam("userid") String userid,@PathParam("objectid") String objectid,String message) {

        if(null!=session && null!=userid && null!=objectid)
        {
            log.info("收到来自:"+userid+",对象编号:"+objectid+"的信息:"+message);

            StringBuilder sb=new StringBuilder();
            sb.append(objectid).append("_").append(userid);

            jobkey=String.valueOf(sb);

            //群发消息
            if(webSocketMapSet.containsKey(jobkey))
            {
                CopyOnWriteArraySet<WebSocketServer> set=webSocketMapSet.get(jobkey);
                for (WebSocketServer item : set) {
                    try {
                        if(item.session.isOpen())
                        {
                            item.sendMessage(message);
                        }

                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }

	/**
	 * 
	 * @param session
	 * @param error
	 */
    @OnError
    public void onError(Session session, Throwable error,@PathParam("userid") String userid,@PathParam("objectid") String objectid) {

        if(null!=session && null!=userid && null!=objectid)
        {
            log.error("发生错误");
            StringBuilder sb=new StringBuilder();
            sb.append(userid).append("_").append(objectid);

            jobkey=String.valueOf(sb);


            if(webSocketMapSet.containsKey(jobkey))
            {
                CopyOnWriteArraySet<WebSocketServer> set=webSocketMapSet.get(jobkey);

                for(WebSocketServer ws:set)
                {
                    if(ws.session.getId().equals(session.getId()))
                    {
                        set.remove(ws);
                        webSocketMapSet.put(jobkey,set);
                    }
                }

            }
            subOnlineCount();           //在线数减1

            log.error(error.getMessage());
        }

    }
	/**
	 * 实现服务器主动推送
	 */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }
    /**
     *@author:Wang Jiawen
     *
     *@description:直接发送object类型消息，实现服务器主动推送，新增传输object类型消息
     *
     *@param:[message] object
     *
     *@return:void
     *
     *@createTime:2020/1/9
     *
     */
    public void sendMessage(Object message) throws IOException, EncodeException {
        this.session.getBasicRemote().sendObject(message);
    }



    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {

        if(WebSocketServer.onlineCount>0)
        {
            WebSocketServer.onlineCount--;
        }else {
            WebSocketServer.onlineCount=0;
        }
    }

    public void sendObject(Object message,@PathParam("userid") String userid,@PathParam("objectid") String objectid) throws IOException, EncodeException {
        log.info("推送消息到窗口:"+userid+",功能编码:"+objectid+"的信息:"+message);


        StringBuilder sb=new StringBuilder();
        sb.append(userid).append("_").append(objectid);



        jobkey=String.valueOf(sb);
        if(webSocketMapSet.containsKey(jobkey))
        {

            //这里可以设定只推送给这个sid的，为null则全部推送
            if(userid==null||objectid==null) {
                throw new BindException("请核对编码信息(包括页面编码以及功能编码非空)");
            }else{
                if(webSocketMapSet.containsKey(jobkey))
                {
                    CopyOnWriteArraySet<WebSocketServer> set=webSocketMapSet.get(jobkey);
                    for (WebSocketServer item : set) {
                        try {
                            item.sendMessage(message);

                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }

            }

        }

    }

}

