package net.northking.cctp.upperComputer.driver.adb;

/**
 * 由Adb Server负责的数据传输隧道记录<br>
 * 端口转发<br>
 * 多种方式的端口监听<br>
 * 上位机到设备或设备到上位机<br>
 * 对应adb forward、adb reverse相关命令
 */
public class Tunnel {
    protected static final String REVERSE_RECORD_PREFIX = "(reverse)";

    /**
     * Adb监听端口的协议
     */
    private ListenType serverListenType = ListenType.TCP;

    /**
     * Adb应该监听的端口<br>
     * 可能是数字端口，可能是文件路径
     */
    private String serverListenName = null;

    /**
     * 转发到的目标端口监听协议
     */
    private ListenType targetListenType = ListenType.TCP;

    /**
     * 转发到的目标端口<br>
     * 可能是数字端口，可能是文件路径
     */
    private String targetListenName = null;

    /**
     * Adb在设备监听<br>
     * 在设备监听，即设备上的程序请求本地端口访问上位机上的端口<br>
     * 在上位机监听，即上位机上的程序请求本地端口访问设备上的端口
     */
    public boolean listenOnDevice = false;

    public Tunnel() {

    }

    /**
     * 从Adb Server返回结果中创建
     *
     * @param recordLine Adb Server查询转发结果的单行记录
     * @throws IllegalArgumentException 发生异常时，丢弃此数据
     */
    public Tunnel(String recordLine) throws IllegalArgumentException {
        if (recordLine == null || recordLine.isEmpty())
            throw new IllegalArgumentException("无效的记录数据：[" + recordLine + "]");
        String[] contentGroup = recordLine.trim().split(" ");
        if (contentGroup.length == 3) {
            if (REVERSE_RECORD_PREFIX.equals(contentGroup[0])) {
                listenOnDevice = true;
            }
            String firstText = contentGroup[1];
            String secondText = contentGroup[2];
            if (firstText.isEmpty()
                    || secondText.isEmpty()
                    || !firstText.contains(":")
                    || !secondText.contains(":")
            ) {
                throw new IllegalArgumentException("无法处理的记录数据：[" + recordLine + "]，缺少信息");
            }
            String[] firstGroup = firstText.split(":");
            if (firstGroup.length != 2) {
                throw new IllegalArgumentException("无法解析数据[" + firstText + "]");
            }
            String[] secondGroup = secondText.split(":");
            if (secondGroup.length != 2) {
                throw new IllegalArgumentException("无法解析数据[" + firstText + "]");
            }
            if (listenOnDevice) {
                serverListenType = ListenType.fromString(secondGroup[0]);
                serverListenName = secondGroup[1];
                targetListenType = ListenType.fromString(firstGroup[0]);
                targetListenName = firstGroup[1];
            } else {
                serverListenType = ListenType.fromString(firstGroup[0]);
                serverListenName = firstGroup[1];
                targetListenType = ListenType.fromString(secondGroup[0]);
                targetListenName = secondGroup[1];
            }

        } else {
            throw new IllegalArgumentException("无法处理的记录数据：[" + recordLine + "]，缺少成分");
        }
    }

    /**
     * 生成创建转发隧道的命令语句
     *
     * @param adbDevice 相关设备，如果是反向转发，则为null
     * @return 命令语句
     */
    public String createCommandText(AdbDevice adbDevice) {
        StringBuilder commandBuilder = new StringBuilder();
        if (listenOnDevice) {
            commandBuilder.append("reverse:");
        } else {
            commandBuilder.append("host-serial:");
            commandBuilder.append(adbDevice.getSerial());
            commandBuilder.append(":");
        }
        commandBuilder.append("forward:");
        if (listenOnDevice) {
            commandBuilder.append(targetListenType.value);
            commandBuilder.append(":");
            commandBuilder.append(targetListenName);
        } else {
            commandBuilder.append(serverListenType.value);
            commandBuilder.append(":");
            commandBuilder.append(serverListenName);
        }
        commandBuilder.append(";");
        if (listenOnDevice) {
            commandBuilder.append(serverListenType.value);
            commandBuilder.append(":");
            commandBuilder.append(serverListenName);
        } else {
            commandBuilder.append(targetListenType.value);
            commandBuilder.append(":");
            commandBuilder.append(targetListenName);
        }
        return commandBuilder.toString();
    }

    /**
     * 生成移除转发隧道的命令语句
     *
     * @param adbDevice 相关设备，如果是反向转发，则为nll
     * @return 命令语句
     */
    public String removeCommandText(AdbDevice adbDevice) {
        StringBuilder commandBuilder = new StringBuilder();

        if (listenOnDevice) {
            commandBuilder.append("reverse:killforward:");
        } else {
            commandBuilder.append("host-serial:");
            commandBuilder.append(adbDevice.getSerial());
            commandBuilder.append(":killforward:");
        }

        commandBuilder.append(serverListenName);
        return commandBuilder.toString();
    }

    @Override
    public String toString() {
        return "Tunnel{" +
                "serverListenType=" + serverListenType +
                ", serverListenName='" + serverListenName + '\'' +
                ", targetListenType=" + targetListenType +
                ", targetListenName='" + targetListenName + '\'' +
                ", listenOnDevice=" + listenOnDevice +
                '}';
    }

    /**
     * 端口监听方式
     */
    public enum ListenType {
        TCP("tcp"),
        LOCAL_ABSTRACT("localabstract"),
        LOCAL("local"),
        JDWP("jdwp");

        private final String value;

        ListenType(String value) {
            this.value = value;
        }

        /**
         * 将对应值的字符串转为ListenType
         *
         * @param text 枚举具体值
         * @return ListenType枚举
         */
        static ListenType fromString(String text) {
            if (TCP.value.equals(text)) return TCP;
            if (LOCAL_ABSTRACT.value.equals(text)) return LOCAL_ABSTRACT;
            if (LOCAL.value.equals(text)) return LOCAL;
            if (JDWP.value.equals(text)) return JDWP;
            throw new IllegalArgumentException("无法将[" + text + "]转变为ListenType");
        }

        @Override
        public String toString() {
            return value;
        }
    }
}
