package com.its.op.service.its.cctv;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@RequiredArgsConstructor
@Service
public class CctvControlZenoService {

    Map<String, ZenoCommand> startCmd = new HashMap<>();
    Map<String, ZenoCommand> stopCmd = new HashMap<>();
    Map<String, ZenoCommand> presetCmd = new HashMap<>();

    @PostConstruct
    void init() {
        this.startCmd.put("tilt-up",   new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00,       0x08, 0x00,       0x28, 0x31 }));
        this.startCmd.put("tilt-down", new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00,       0x10, 0x00,       0x28, 0x31 }));
        this.startCmd.put("pan-left",  new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00,       0x04, 0x00,       0x28, 0x31 }));
        this.startCmd.put("pan-right", new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00,       0x02, 0x00,       0x28, 0x31 }));
        this.startCmd.put("zoom-in",   new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x00,       0x20, 0x00, (byte)0xFF, 0x31 }));
        this.startCmd.put("zoom-out",  new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x00,       0x08, 0x00, (byte)0xFF, 0x31 }));
        this.startCmd.put("focus-in",  new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x00, (byte)0x80, 0x00, (byte)0xFF, 0x31 }));
        this.startCmd.put("focus-out", new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x01,       0x00, 0x00, (byte)0xFF, 0x31 }));

        this.stopCmd.put("tilt-up",   new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00, 0x00, 0x00,       0x00, 0x01 }));
        this.stopCmd.put("tilt-down", new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00, 0x00, 0x00,       0x00, 0x01 }));
        this.stopCmd.put("pan-left",  new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00, 0x00, 0x00,       0x00, 0x01 }));
        this.stopCmd.put("pan-right", new ZenoCommand(new byte[]{ 0x10, (byte)0xFF, 0x01, 0x00, 0x00, 0x00,       0x00, 0x01 }));
        this.stopCmd.put("zoom-in",   new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x00, 0x00, 0x00, (byte)0xFF, 0x01 }));
        this.stopCmd.put("zoom-out",  new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x00, 0x00, 0x00, (byte)0xFF, 0x01 }));
        this.stopCmd.put("focus-in",  new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x00, 0x08, 0x00, (byte)0xFF, 0x31 }));
        this.stopCmd.put("focus-out", new ZenoCommand(new byte[]{ 0x50, (byte)0xFF, 0x01, 0x00, 0x08, 0x00, (byte)0xFF, 0x31 }));

        this.presetCmd.put("call",    new ZenoCommand(new byte[]{ 0x41, (byte)0xFF, 0x01, 0x00, 0x00 }));
        this.presetCmd.put("save",    new ZenoCommand(new byte[]{ 0x32, (byte)0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
                                                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }));
        this.presetCmd.put("delete",  new ZenoCommand(new byte[]{ 0x32, (byte)0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }));
    }

    public byte[] getPtzCmd(String control, String action, int value) {
        if (StringUtils.equalsIgnoreCase("start", action)) {
            ZenoCommand command = this.startCmd.get(control);
            if (command != null) {
                return command.getCmd();
            }
        } else if (StringUtils.equalsIgnoreCase("stop", action)) {
            ZenoCommand command = this.stopCmd.get(control);
            if (command != null) {
                return command.getCmd();
            }
        }
        return null;
    }

    public byte[] getPresetCmd(String action, Integer psetNmbr, Integer speed, Integer time, String name) {
        ZenoCommand command = this.presetCmd.get(action);
        if (command != null) {
            byte[] cmd = command.getCmd();
            int cmdPsetNmbr = Math.min(psetNmbr, 0xFF);
            cmd[4] = (byte)cmdPsetNmbr;
            if (StringUtils.equalsIgnoreCase("save", action)) {
                int cmdSpeed = Math.min(speed, 0x3F);
                int cmdTime = Math.min(time, 60);
                cmd[6] = (byte)cmdSpeed;
                cmd[8] = (byte)cmdTime;
                String psetName = "preset " + cmdPsetNmbr;
                byte[] byteName = psetName.getBytes();
                System.arraycopy(byteName, 0, cmd, 10, byteName.length);
            }
            return cmd;
        }
        return null;
    }

    public static class ZenoCommand {
        private byte[] cmd;
        public ZenoCommand(byte[] cmd) {
            if (cmd != null && cmd.length > 0) {
                this.cmd = new byte[cmd.length];
                System.arraycopy(cmd, 0, this.cmd, 0, cmd.length);
            }
        }
        public byte[] getCmd() {
            if (this.cmd == null) {
                return null;
            }
            byte[] cmd = new byte[this.cmd.length];
            System.arraycopy(this.cmd, 0, cmd, 0, this.cmd.length);

            int cs = 0;
            for (int ii = 2; ii < cmd.length-2; ii++) {
                cs += cmd[ii];
            }
            cmd[cmd.length-1] = (byte)cs;
            return cmd;
        }
    }

}
