package com.yfd.monitor.gdw2019.transmit.event.request.impl.message.query.cmd_parent;

import cn.hutool.core.util.StrUtil;
import com.yfd.monitor.gdw2019.bean.Device;
import com.yfd.monitor.gdw2019.bean.DeviceChannel;
import com.yfd.monitor.gdw2019.bean.ParentPlatform;
import com.yfd.monitor.gdw2019.transmit.SIPSender;
import com.yfd.monitor.gdw2019.transmit.cmd.impl.SIPCommander;
import com.yfd.monitor.gdw2019.transmit.event.request.SIPRequestProcessorParent;
import com.yfd.monitor.gdw2019.transmit.event.request.impl.message.IMessageHandler;
import com.yfd.monitor.gdw2019.transmit.event.request.impl.message.query.QueryMessageByparentHandler;
import com.yfd.monitor.storager.dao.DeviceChannelMapper;
import com.yfd.monitor.storager.dao.DeviceMapper;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.message.SIPResponse;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.FromHeader;
import java.text.ParseException;
import java.util.List;

@Component
public class Control_cameraByParentMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {

    private Logger logger = LoggerFactory.getLogger(Control_cameraByParentMessageHandler.class);
    private final String cmdType = "Control_Camera";

    @Autowired
    private QueryMessageByparentHandler queryMessageHandler;


    @Autowired
    private SIPCommander sipCommander;

    @Autowired
    private SIPSender sipSender;

    @Autowired
    private DeviceChannelMapper channelMapper;
    @Autowired
    private DeviceMapper deviceMapper;

    @Override
    public void afterPropertiesSet() throws Exception {
        queryMessageHandler.addHandler(cmdType, this);
    }

    @Override
    public void handForDevice(RequestEvent evt, Device device, Element element) {

    }

    @Override
    public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) throws InvalidArgumentException, ParseException, SipException {
        logger.error("==================================================处理上级系统发出的设备控制指令");
        //处理上级系统发出的设备控制指令
        FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
        Element itemElement = rootElement.element("Item");
        String Code = itemElement.attributeValue("Code");
        String Command = itemElement.attributeValue("Command");
        String CommandPara1 = StrUtil.isEmpty(itemElement.attributeValue("CommandPara1")) ? "0" : itemElement.attributeValue("CommandPara1");
        String CommandPara2 = StrUtil.isEmpty(itemElement.attributeValue("CommandPara2")) ? "0" : itemElement.attributeValue("CommandPara2");
        String CommandPara3 = StrUtil.isEmpty(itemElement.attributeValue("CommandPara3")) ? "0" : itemElement.attributeValue("CommandPara3");

        String cmdString = qgdw2019CmdString(Integer.parseInt(Command), Integer.parseInt(CommandPara1), Integer.parseInt(CommandPara2), Integer.parseInt(CommandPara3));

        String channelid = Code;
        String deviceId = "";
        //获取一个默认通道
        List<DeviceChannel> channels = channelMapper.queryChannelList(Code);
        logger.error("==================================================进入云台方法"+channels.size());
        if (channels.size() > 0) {
            DeviceChannel deviceChannel = channels.get(0);
            channelid = deviceChannel.getChannelId();
            deviceId = deviceChannel.getDeviceId();
        }
        sipCommander.fronEndCmd(deviceMapper.getDeviceByDeviceId(deviceId), channelid, cmdString, null, eventResult -> {
            SIPRequest request = (SIPRequest) evt.getRequest();
            SIPResponse response = null;
            try {
                response = responseAck(request, 200);
            } catch (SipException | InvalidArgumentException | ParseException e) {
                e.printStackTrace();
            }
            try {
                sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
            } catch (SipException | ParseException e) {
                e.printStackTrace();
            }
        });

    }

    public static String qgdw2019CmdString(int Command, int CommandPara1, int CommandPara2, int CommandPara3) {
//        0x0101 转换为 257（光圈关停止）
//        0x0102 转换为 258（光圈关）
//        0x0103 转换为 259（光圈开）
//        0x0104 转换为 260（光圈开停止）
//        0x0201 转换为 513（近聚焦停止）
//        0x0202 转换为 514（近聚焦）
//        0x0203 转换为 515（远聚焦停止）
//        0x0204 转换为 516（远聚焦）
//        0x0301 转换为 769（缩小停止）
//        0x0302 转换为 770（缩小）
//        0x0303 转换为 771（放大停止）
//        0x0304 转换为 772（放大）
//        0x0401 转换为 1025（向上停止）
//        0x0402 转换为 1026（向上）
//        0x0403 转换为 1027（向下停止）
//        0x0404 转换为 1028（向下）
//        0x0501 转换为 1281（右转停止）
//        0x0502 转换为 1282（右转）
//        0x0503 转换为 1283（左转停止）
//        0x0504 转换为 1284（左转）
//        0x0601 转换为 1537（预置位保存）
//        0x0602 转换为 1538（预置位调用）
//        0x0603 转换为 1539（预置位删除）
//        0x0701 转换为 1793（左上方向运动停止）
//        0x0702 转换为 1794（左上方向运动）
//        0x0703 转换为 1795（左下方向运动停止）
//        0x0704 转换为 1796（左下方向运动）
//        0x0801 转换为 2049（右上方向运动停止）
//        0x0802 转换为 2050（右上方向运动）
//        0x0803 转换为 2051（右下方向运动停止）
//        0x0804 转换为 2052（右下方向运动）
//        0x0901 转换为 2305（停止当前动作）
//        0x0a01 转换为 2561（雨刷开）
//        0x0a02 转换为 2562（雨刷关）
//        0x0b01 转换为 2817（灯亮）
//        0x0b02 转换为 2818（灯灭）
//        0x0c01 转换为 3073（加热开）
//        0x0c02 转换为 3074（加热关）
//        0x0d01 转换为 3329（红外开）
//        0x0d02 转换为 3330（红外关）
//        0x0e01 转换为 3585（线性扫描开始）
//        0x0e02 转换为 3586（线性扫描停止）
//        0x0f01 转换为 3841（轨迹巡航开始）
//        0x0f02 转换为 3842（轨迹巡航停止）
//        0x1001 转换为 4097（预置位巡航开始）
//        0x1002 转换为 4098（预置位巡航停止）
//        0x1101 转换为 4353（云台锁定）
//        0x1102 转换为 4354（云台解锁）
        String cmdstring = "";
        switch (Command) {
            case 769://0x0301 转换为 769（缩小停止）
                cmdstring = cmdString(0, 0, 0, 0, 0, 0);
                break;
            case 770://0x0302 转换为 770（缩小）
                cmdstring = cmdString(0, 0, 1, 0, 0, 16);
                break;
            case 771://0x0303 转换为 771（放大停止）
                cmdstring = cmdString(0, 0, 0, 0, 0, 0);
                break;
            case 772://0x0304 转换为 772（放大）
                cmdstring = cmdString(0, 0, 2, 0, 0, 16);
                break;
            case 1025://0x0401 转换为 1025（向上停止）
                cmdstring = cmdString(0, 0, 0, CommandPara1, CommandPara2, 0);
                break;
            case 1026://0x0402 转换为 1026（向上）
                cmdstring = cmdString(1, 0, 0, CommandPara1, CommandPara2, 0);
                break;
            case 1027://0x0403 转换为 1027（向下停止）
                cmdstring = cmdString(0, 0, 0, CommandPara1, CommandPara2, 0);
                break;
            case 1028://0x0404 转换为 1028（向下）
                cmdstring = cmdString(2, 0, 0, CommandPara1, CommandPara2, 0);
                break;
            case 1281://0x0501 转换为 1281（右转停止）
                cmdstring = cmdString(0, 0, 0, CommandPara1, CommandPara2, 0);
                break;
            case 1282://0x0502 转换为 1282（右转）
                cmdstring = cmdString(0, 2, 0, CommandPara1, CommandPara2, 0);
                break;
            case 1283://0x0503 转换为 1283（左转停止）
                cmdstring = cmdString(0, 0, 0, CommandPara1, CommandPara2, 0);
                break;
            case 1284://0x0504 转换为 1284（左转）
                cmdstring = cmdString(0, 1, 0, CommandPara1, CommandPara2, 0);
                break;
            case 1537://0x0601 转换为 1537（预置位保存）
                cmdstring = frontEndCmdString(129, 0, CommandPara1, 0);
                break;
            case 1538://0x0602 转换为 1538（预置位调用）
                cmdstring = frontEndCmdString(130, 0, CommandPara1, 0);
                break;
            case 1539://0x0603 转换为 1539（预置位删除）
                cmdstring = frontEndCmdString(131, 0, CommandPara1, 0);
                break;
            case 1793://0x0701 转换为 1793（左上方向运动停止）
                cmdstring = cmdString(0, 0, 0, CommandPara1, CommandPara2, 0);
                break;
            case 1794://0x0702 转换为 1794（左上方向运动）
                cmdstring = cmdString(1, 1, 0, CommandPara1, CommandPara2, 0);
                break;
            case 1795://0x0703 转换为 1795（左下方向运动停止）
                cmdstring = cmdString(0, 0, 0, CommandPara1, CommandPara2, 0);
                break;
            case 1796://0x0704 转换为 1796（左下方向运动）
                cmdstring = cmdString(2, 1, 0, CommandPara1, CommandPara2, 0);
                break;
            case 2049://0x0801 转换为 2049（右上方向运动停止）
                cmdstring = cmdString(0, 0, 0, CommandPara1, CommandPara2, 0);
                break;
            case 2050://0x0802 转换为 2050（右上方向运动）
                cmdstring = cmdString(1, 2, 0, CommandPara1, CommandPara2, 0);
                break;
            case 2051://0x0803 转换为 2051（右下方向运动停止）
                cmdstring = cmdString(0, 0, 0, CommandPara1, CommandPara2, 0);
                break;
            case 2052://0x0804 转换为 2052（右下方向运动）
                cmdstring = cmdString(2, 2, 0, CommandPara1, CommandPara2, 0);
                break;
        }
        return cmdstring;
    }


    /**
     * 云台指令码计算
     *
     * @param upDown     镜头上移下移 0:停止 1:上移 2:下移
     * @param leftRight  镜头左移右移 0:停止 1:左移 2:右移
     * @param inOut      镜头放大缩小 0:停止 1:缩小 2:放大
     * @param moveSpeed1 镜头上下移动速度
     * @param moveSpeed2 镜头左右移动速度
     * @param zoomSpeed  镜头缩放速度
     */
    public static String cmdString(int upDown, int leftRight, int inOut, int moveSpeed1, int moveSpeed2, int zoomSpeed) {
        int cmdCode = 0;
        if (leftRight == 2) {
            cmdCode |= 0x01;        // 右移
        } else if (leftRight == 1) {
            cmdCode |= 0x02;        // 左移
        }
        if (upDown == 2) {
            cmdCode |= 0x04;        // 下移
        } else if (upDown == 1) {
            cmdCode |= 0x08;        // 上移
        }
        if (inOut == 2) {
            cmdCode |= 0x10;    // 放大
        } else if (inOut == 1) {
            cmdCode |= 0x20;    // 缩小
        }
        StringBuilder builder = new StringBuilder("A50F01");
        String strTmp;
        strTmp = String.format("%02X", cmdCode);
        builder.append(strTmp, 0, 2);
        strTmp = String.format("%02X", moveSpeed1 * 28);
        builder.append(strTmp, 0, 2);
        strTmp = String.format("%02X", moveSpeed2 * 28);
        builder.append(strTmp, 0, 2);
        //优化zoom低倍速下的变倍速率
        if ((zoomSpeed > 0) && (zoomSpeed < 16)) {
            zoomSpeed = 16;
        }
        strTmp = String.format("%X", zoomSpeed);
        builder.append(strTmp, 0, 1).append("0");
        //计算校验码
        int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + moveSpeed1 * 28 + moveSpeed2 * 28 + (zoomSpeed /*<< 4*/ & 0XF0)) % 0X100;
        strTmp = String.format("%02X", checkCode);
        builder.append(strTmp, 0, 2);
        return builder.toString();
    }

    /**
     * 云台指令码计算
     *
     * @param cmdCode      指令码
     * @param parameter1   数据1
     * @param parameter2   数据2
     * @param combineCode2 组合码2
     */
    public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) {
        StringBuilder builder = new StringBuilder("A50F01");
        String strTmp;
        strTmp = String.format("%02X", cmdCode);
        builder.append(strTmp, 0, 2);
        strTmp = String.format("%02X", parameter1);
        builder.append(strTmp, 0, 2);
        strTmp = String.format("%02X", parameter2);
        builder.append(strTmp, 0, 2);
        //优化zoom变倍速率
        if ((combineCode2 > 0) && (combineCode2 < 16)) {
            combineCode2 = 16;
        }
        strTmp = String.format("%X", combineCode2);
        builder.append(strTmp, 0, 1).append("0");
        //计算校验码
        int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100;
        strTmp = String.format("%02X", checkCode);
        builder.append(strTmp, 0, 2);
        return builder.toString();
    }

}
