package com.xhpc.pp.server;

import com.xhpc.pp.logic.FieldLogic;
import com.xhpc.pp.utils.HexUtils;
import org.quickserver.net.server.ClientHandler;
import org.quickserver.net.server.DataMode;
import org.quickserver.net.server.DataType;
import org.quickserver.net.server.QuickServer;
import org.quickserver.util.xmlreader.DefaultDataMode;
import org.quickserver.util.xmlreader.QuickServerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static com.xhpc.common.data.redis.StaticBeanUtil.ORDER_SVC;
import static com.xhpc.common.data.redis.StaticBeanUtil.REDIS;
import static com.xhpc.pp.logic.RegisterLogic.DISCONNECTED;


/**
 * 充电桩服务器
 */
@Lazy(false)
@Component
public class ChargingPileServer {

    public static final String default_version = "0A";
    private static final Logger log = LoggerFactory.getLogger(ChargingPileServer.class);
    private static final Map<String, ClientHandler> handlerMap = new HashMap<>();
    private static final Map<String, String> versionMapper = new HashMap<>();
    private static final Map<String, String> pileMap = new HashMap<>();
    private QuickServer server;

    @Autowired
    private FieldLogic fieldLogic;

    @Autowired
    public ChargingPileServer(@Value("${ppsvc.server}") String host, @Value("${ppsvc.port}") int port) {

        try {
            QuickServerConfig config;
            server = new QuickServer();
            server.setDefaultDataMode(DataMode.BINARY, DataType.IN);
            config = new QuickServerConfig();
            DefaultDataMode mode = new DefaultDataMode();
            mode.setDataMode(DataMode.BINARY, DataType.IN);
            mode.setDataMode(DataMode.BINARY, DataType.OUT);
            config.setDefaultDataMode(mode);
            config.setClientEventHandler(ChargingPileEventHandler.class.getName());
            config.setClientCommandHandler(ChargingPileCommandHandler.class.getName());
            config.setClientBinaryHandler(ChargingPileBinaryHandler.class.getName());
            config.getServerMode().setBlocking(true);
            config.setPort(port);
            config.setBindAddr(host);
            config.setTimeout(90 * 1000);
            server.initService(config);
            server.startServer();
            log.debug("pp svc started at {}:{} ....", host, port);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("pp svc start error: " + e);
        }
    }

    public static void putHandler(String pileNo, ClientHandler handler) {
        System.out.println("=========ChargingPileServer============pileNo==="+pileNo+"==============");
        handlerMap.put(pileNo, handler);
        pileMap.put(handler.getName(), pileNo);
    }

    //断开桩连接
    public static void disconnPileNGuns(String pileNo) {
        System.out.println("=========disconnPileNGuns============pileNo==="+pileNo+"==============");
        ClientHandler handler = handlerMap.remove(pileNo);
        if(handler!=null) {
            handler.closeConnection();
            log.debug("handler [{}] for ({}) close connection", handler.getName(), pileNo);
        }
        String pkey = "pile:".concat(pileNo);
        Map<String, Object> cachePile = REDIS.getCacheMap(pkey);
        putemDisconn(pileNo, cachePile);
    }

    private static void putemDisconn(String pileNo, Map<String, Object> cachePile) {
        String stationTermStatusKey = "stationTerminalStatus:".concat(cachePile.get("stationId").toString());
        for (int i = 1; i <= (int) cachePile.get("gunNum"); i++) {
            String gunId = pileNo.concat(String.format("%02d", i));
            String gunkey = "gun:".concat(gunId);
            Map<String, Object> cacheGun = REDIS.getCacheMap(gunkey);
            if (!cacheGun.isEmpty()) {
                cacheGun.put("status", DISCONNECTED);
                REDIS.setCacheMap(gunkey, cacheGun);
                Map<String, Object> cacheTerminalStatusMap = REDIS.getCacheMap(stationTermStatusKey);
                cacheTerminalStatusMap.put(gunId, DISCONNECTED);
                REDIS.setCacheMap(stationTermStatusKey, cacheTerminalStatusMap);
                String orderkey = (String) cacheGun.get("orderkey");
                if (orderkey != null) {
                    Map<String, Object> cacheOrder = REDIS.getCacheMap(orderkey);
                    cacheOrder.put("lordiss", "true");
                    REDIS.setCacheMap(orderkey, cacheOrder);
                    String orderNo = orderkey.replace("order:", "");
                    ORDER_SVC.pileStop(orderNo, 3, "充电桩离线,订单实时数据可能中断");
                }
            }
        }
    }

    public static void removeHandler(String pileNo) {

        ClientHandler handler = handlerMap.remove(pileNo);
        String pkey = "pile:".concat(pileNo);
        Map<String, Object> cachePile = REDIS.getCacheMap(pkey);
        cachePile.put("status", DISCONNECTED);
        REDIS.setCacheMap(pkey, cachePile);
        putemDisconn(pileNo, cachePile);
        if (handler != null) {
//        handler.closeConnection();
//        log.debug("handler [{}] for ({}) close connection", handler.getName(), pileNo);
            log.debug("remove handler [{}] for ({}), now try to close conn..", handler.getName(), pileNo);
            handler.closeConnection();
            pileMap.remove(handler.getName());
            versionMapper.remove(handler.getName());
        }
    }

    public static void sendClientMsg(String pileNo, byte[] msg) {

        log.debug("server send msg >>>> ({}) |{}|", pileNo, HexUtils.toHex(msg));
        if (pileNo.length() < 14) {
            pileNo = "0000000000000000" + pileNo;
            pileNo = pileNo.substring(pileNo.length() - 14);
        }
        ClientHandler handler = handlerMap.get(pileNo);
        if (handler == null) {
            return;
        }
        if (!handler.isOpen()) {
            log.error("send message failed. [{}]({}) connection lost", handler.getName(), pileNo);
            removeHandler(pileNo);
        }
        try {
            handler.sendClientBinary(msg);
        } catch (IOException e) {
            log.error("send message failed. " + e.getMessage(), e);
        }
    }

    public static void putVersion(String handler, String version) {

        versionMapper.put(handler, version);
    }

    public static String getVersion(String handler) {

        String version = versionMapper.get(handler);
        if (version == null)
            version = default_version;
        return version;
    }

    public static ClientHandler getHandler(String pile) {

        return handlerMap.get(pile);
    }

    public static String getPileNo(ClientHandler handler) {

        return pileMap.get(handler.getName());
    }

    public void shutDown() {

        try {
            if (server != null)
                server.stopServer();
        } catch (Exception e) {
            log.error("Server could not stop: " + e);
        }
    }

}
