package com.judong.chuanyiserver.util;

import com.alibaba.fastjson.JSONObject;
import com.judong.chuanyiserver.config.OpcServerDaPoolFactory;
import com.judong.chuanyiserver.entity.ServerInformation;
import com.judong.chuanyiserver.enums.ResultEnum;
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.core.JIVariant;
import org.openscada.opc.dcom.da.OPCSERVERSTATE;
import org.openscada.opc.lib.da.Group;
import org.openscada.opc.lib.da.Item;
import org.openscada.opc.lib.da.Server;
import org.openscada.opc.lib.da.browser.Branch;
import org.openscada.opc.lib.da.browser.Leaf;
import org.openscada.opc.lib.da.browser.TreeBrowser;

import java.net.UnknownHostException;
import java.util.*;

/**
 * OPCDa协议工具类
 */
public class OpcServerDaUtil {

    /**
     * 通过ip，user，password生成对应的连接池键
     *
     * @param ip
     * @param user
     * @param password
     * @return
     */
    public static String generateOpcPoolKey(String ip, String user, String password) {
        StringBuffer buffer = new StringBuffer("");
        buffer.append("{\"ip\":\"");
        buffer.append(ip + "\",\"user\":\"");
        buffer.append(user + "\",\"password\":\"");
        buffer.append(password + "\"}");
        return buffer.toString();
    }

    /**
     * 判断传入的键是否符合OPCserver池对象规则
     *
     * @param key
     * @return
     */
    public static Boolean validationKey(String key) {
        if (Blank.isEmpty(key)) {
            return false;
        }
        JSONObject jsonObject = (JSONObject) JSONObject.parse(key);
        String ip = (String) jsonObject.get("ip");
        String user = (String) jsonObject.get("user");
        String password = (String) jsonObject.get("password");
        if (Blank.isEmpty(ip) || Blank.isEmpty(user) || Blank.isEmpty(password)) {
            return false;
        }
        return true;
    }

    /**
     * 通过键获取OPCserver
     * 如果没有这个对象，则会创建这个对象
     *
     * @param key
     * @return
     * @throws Exception
     */
    public static Server getServer(String key) throws Exception {
        return OpcServerDaPoolFactory.getServer(key);
    }

    /**
     * 返回Server给连接池
     */
    public static void returnServer(String key, Server server) throws Exception {
        OpcServerDaPoolFactory.returnServer(key, server);
    }

    /**
     * 查看连接池中所有的连接
     *
     * @return
     */
    public static GenericKeyedObjectPool<String, Server> getPool() throws Exception {
        GenericKeyedObjectPool<String, Server> pool = OpcServerDaPoolFactory.getPool();
//        System.out.println(pool.);
        return OpcServerDaPoolFactory.getPool();
    }

    /**
     * 通过服务器信息读取服务器树item
     *
     * @param serverInformation
     * @return
     * @throws Exception
     */
    public static Result opcDaReadItemTree(ServerInformation serverInformation) throws Exception {
        String opcServerDaPoolKey = OpcServerDaUtil.generateOpcPoolKey(serverInformation.getIpAddress(), serverInformation.getIpUserName(), serverInformation.getIpPassword());
        if (OpcServerDaUtil.validationKey(opcServerDaPoolKey)) {
            Server server = OpcServerDaUtil.getServer(opcServerDaPoolKey);
            if (null == server.getServerState()) {
                return Result.no(ResultEnum.NOT_FOUND.getRespCode(), "连接失败");
            }
            if (OPCSERVERSTATE.OPC_STATUS_RUNNING == server.getServerState().getServerState()) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("tree", OpcServerDaUtil.generOpcDaTree(server));
                OpcServerDaUtil.returnServer(opcServerDaPoolKey, server);
                return Result.ok(jsonObject);
            }
        }
        return Result.no(ResultEnum.SERVER_ERROR.getRespCode(), ResultEnum.SERVER_ERROR.getRespMsg());
    }

    /**
     * 通过服务器信息和标签名称读取响应的数据
     *
     * @param serverInformation
     * @param itemName
     * @return
     * @throws Exception
     */
    public static Result opcDaReadItemValue(ServerInformation serverInformation, String itemName) throws Exception {
        String opcServerDaPoolKey = OpcServerDaUtil.generateOpcPoolKey(serverInformation.getIpAddress(), serverInformation.getIpUserName(), serverInformation.getIpPassword());
        if (OpcServerDaUtil.validationKey(opcServerDaPoolKey)) {
            Server server = OpcServerDaUtil.getServer(opcServerDaPoolKey);
            if (null == server.getServerState()) {
                return Result.no(ResultEnum.NOT_FOUND.getRespCode(), "连接失败");
            }
            if (OPCSERVERSTATE.OPC_STATUS_RUNNING == server.getServerState().getServerState()) {
                JSONObject jsonObject = new JSONObject();
                Group group = server.addGroup();
                Item item = group.addItem(itemName);
                Map<String, Object> value = getVal(item.read(true).getValue());
                jsonObject.put("javaType", value.get("javaType"));
                jsonObject.put("value", value);
                OpcServerDaUtil.returnServer(opcServerDaPoolKey, server);
                return Result.ok(jsonObject);
            }
        }
        return Result.no(ResultEnum.SERVER_ERROR.getRespCode(), ResultEnum.SERVER_ERROR.getRespMsg());
    }

    /**
     * 获取OPCDA服务器的tree
     *
     * @return
     */
    public static List<JSONObject> generOpcDaTree(Server server) throws JIException, UnknownHostException {
        List<JSONObject> jsonList = new ArrayList<>();
        //获取服务器下所有ITEM列表,树形展示
        TreeBrowser treeBrowser = server.getTreeBrowser();
        Branch browse = treeBrowser.browse();
        Collection<Branch> branches = browse.getBranches();
        for (Branch branch : branches) {
//            Collection<Leaf> leaves = branch.getLeaves();
            if (Blank.isNotEmpty(branch.getBranches())) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("label", branch.getName());
                jsonObject.put("children", recursionChildren(branch.getBranches()));
                jsonList.add(jsonObject);
            }
        }
        return jsonList;
    }

    public static List<JSONObject> recursionChildren(Collection<Branch> branchCollection) {
        List<JSONObject> jsonList = new ArrayList<>();
        for (Branch branch : branchCollection) {
            if (Blank.isNotEmpty(branch.getBranches())) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("label", branch.getName());
                jsonObject.put("children", recursionChildren(branch.getBranches()));
                jsonList.add(jsonObject);
            } else {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("label", branch.getName());
                jsonObject.put("children", generLeaf(branch.getLeaves()));
                jsonList.add(jsonObject);
            }
        }
        return jsonList;
    }

    public static List<JSONObject> generLeaf(Collection<Leaf> leaves) {
        List<JSONObject> jsonObjectList = new ArrayList<>();
        for (Leaf leaf : leaves) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("label", leaf.getName());
            jsonObjectList.add(jsonObject);
        }
        return jsonObjectList;
    }

    /**
     * 通过itemid获取响应的值
     *
     * @param var
     * @return
     * @throws JIException
     */
    public static Map<String, Object> getVal(JIVariant var) throws JIException {
        Map<String, Object> map = new HashMap<>();
        Object value;
        int type = var.getType();
        String javaType;
        switch (type) {
            case JIVariant.VT_I2://读到short类型
                javaType = "short";
                value = var.getObjectAsShort();
                break;
            case JIVariant.VT_I4://读到int类型
                javaType = "int";
                value = var.getObjectAsInt();
                break;
            case JIVariant.VT_I8://读到long类型
                javaType = "long";
                value = var.getObjectAsLong();
                break;
            case JIVariant.VT_R4://读到float类型值
                javaType = "float";
                value = var.getObjectAsFloat();
                break;
            case JIVariant.VT_R8://读到double类型
                javaType = "double";
                value = var.getObjectAsDouble();
                break;
            case JIVariant.VT_BSTR://读到String类型值
                javaType = "String";
                value = var.getObjectAsString();
                break;
            case JIVariant.VT_BOOL://读到boolean类型
                javaType = "boolean";
                value = var.getObjectAsBoolean();
                break;
            case JIVariant.VT_DATE://读到date类型
                javaType = "date";
                value = var.getObjectAsDate();
                break;
            case JIVariant.VT_UI2://读到word类型（无符号整数）
                javaType = "word";//无符号类型
                value = var.getObjectAsUnsigned().getValue();
                break;
            case JIVariant.VT_UI4://读到DWORD类型（无符号整数）
                javaType = "word";//无符号类型
                value = var.getObjectAsUnsigned().getValue();
                break;
//            case JIVariant.VT_EMPTY:
//                throw new JIException(JIErrorCodes.JI_VARIANT_IS_NULL, "Variant is Empty.");
//            case JIVariant.VT_NULL:
//                throw new JIException(JIErrorCodes.JI_VARIANT_IS_NULL, "Variant is null.");
//            default:
//                throw new JIException(JIErrorCodes.JI_VARIANT_IS_NULL, "Unknown Type.");
            default:
                javaType = "";
                value = null;
                break;
        }
        map.put("javaType", javaType);
        map.put("value", value);
        return map;
    }
}
