package com.tykj.dev.rfid.service.impl;

import com.tykj.dev.device.library.service.DeviceLibraryService;
import com.tykj.dev.device.library.subject.domin.DeviceLibrary;
import com.tykj.dev.misc.exception.ApiException;
import com.tykj.dev.misc.utils.ResultUtil;
import com.tykj.dev.rfid.entity.vo.RfidCreateVo;
import com.tykj.dev.rfid.service.RfidService;
import com.zebra.sdk.comm.Connection;
import com.zebra.sdk.comm.ConnectionException;
import com.zebra.sdk.comm.TcpConnection;
import com.zebra.sdk.printer.PrinterLanguage;
import com.zebra.sdk.printer.ZebraPrinter;
import com.zebra.sdk.printer.ZebraPrinterFactory;
import com.zebra.sdk.printer.ZebraPrinterLanguageUnknownException;
import com.zebra.sdk.printer.discovery.DiscoveredUsbPrinter;
import com.zebra.sdk.printer.discovery.UsbDiscoverer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 描述：用于调用RFID打印机打印标签
 *
 * @author HuangXiahao
 * @version V1.0
 **/
@Service
@Slf4j
public class RfidServiceImpl implements RfidService {

    @Resource
    private DeviceLibraryService deviceLibraryService;

    private static final Integer DEFAULT_USB_INDEX = 0;

    private static ZebraPrinter printer;

    /**
     * 描述：设置打印机网络端口
     *
     * @param ip   IP
     * @param port 端口号
     */
    @Override
    public void setNetWorkConnection(String ip, Integer port) {
        try {
            //根据IP和PORT获取Connection
            Connection connection = new TcpConnection(ip, port);
            connection.open();
            //获取打印机实力
            printer = ZebraPrinterFactory.getInstance(connection);
        } catch (ConnectionException | ZebraPrinterLanguageUnknownException e) {
            throw new ApiException(ResultUtil.failed("未找到对应的端口，请检查网络"));
        }
    }

    /**
     * 描述：自动扫描本机的打印机接口
     */
    @Override
    public void scanUsbConnection() {
        try {
            //根据IP和PORT获取Connection
            DiscoveredUsbPrinter[] zebraUsbPrinters = UsbDiscoverer.getZebraUsbPrinters();
            Connection connection = zebraUsbPrinters[DEFAULT_USB_INDEX].getConnection();
            //获取打印机实力
            printer = ZebraPrinterFactory.getInstance(connection);
        } catch (ConnectionException | ZebraPrinterLanguageUnknownException e) {
            throw new ApiException(ResultUtil.failed("未找到对应的端口，请检查网络"));
        }
    }


    @Override
    public boolean printString(String content) {
        try {
            Connection connection = new TcpConnection("192.168.0.222", 6101);
            connection.open();
            printer = ZebraPrinterFactory.getInstance(connection);
            String demoFile = createDemoFile(printer.getPrinterControlLanguage(), content, 53, 80);
            printer.sendFileContents(demoFile);
        } catch (ConnectionException e) {
            throw new ApiException(ResultUtil.failed("未找到对应的打印机"));
        } catch (ZebraPrinterLanguageUnknownException e) {
            throw new ApiException(ResultUtil.failed("打印机内容错误"));
        } catch (IOException e) {
            throw new ApiException(ResultUtil.failed("生成打印文件失败"));
        }


        return true;
    }

    /**
     * @param pl         打印机语言
     * @param content    打印内容
     * @param marginLeft 标签左边距
     * @param marginTop  标签顶部边距
     * @return 拼接成功的打印机ZPL
     * @throws IOException IO错误
     */
    private String createDemoFile(PrinterLanguage pl, String content, int marginLeft, int marginTop) throws IOException {

        File tmpFile = File.createTempFile("TEST_ZEBRA", "LBL");
        FileOutputStream os = new FileOutputStream(tmpFile);

        byte[] configLabel = null;

        if (pl == PrinterLanguage.ZPL) {
            configLabel = ("^XA\n" +
                    "~TA000\n" +
                    "~JSN\n" +
                    "^LT0\n" +
                    "^MD30\n" +
                    "^MNW\n" +
                    "^MTT\n" +
                    "^PON\n" +
                    "^PMN\n" +
                    "^LH0,0\n" +
                    "^JMA\n" +
                    "^PR6,6\n" +
                    "~SD15\n" +
                    "^JUS\n" +
                    "^LRN\n" +
                    "^CI27\n" +
                    "^PA0,1,1,0\n" +
                    "^XZ\n" +
                    "^XA\n" +
                    "^MMT\n" +
                    "^PW428\n" +
                    "^LL264\n" +
                    "^LS0\n" +
                    "\n" +
                    "^LH" + marginLeft + "," + marginTop + "\n" +
                    "^A0N,60,25\n" +
                    "^FD" +
                    content +
                    "^FS\n" +
                    "^PQ1,0,1,Y\n" +
                    "^XZ\n" +
                    "^XZ").getBytes();
        }
        os.write(configLabel);
        os.flush();
        os.close();
        return tmpFile.getAbsolutePath();
    }

    /**
     * 描述：生成装备的RFID表面号
     *
     * @param list RFID表面号生成类
     * @return
     */
    @Override
    public List<String> getRfidNumber(List<RfidCreateVo> list) {
        List<String> strings = new ArrayList<>();
        //遍历List为每一个创建元素生成对应的RFID表面号
        for (RfidCreateVo r : list) {
            //如果传入的创建元素中不包含装备ID的话，则生成新的表面号
            //否则根据将已经装备的表面号插入LIST
            if (r.getDeviceTId() == null) {
                strings.add(makeRfidNumber(r.getPartType(), r.getDeviceNumber(), r.getProduceNumber(), r.getDeviceType()));
            } else {
                DeviceLibrary device = deviceLibraryService.getOne(r.getDeviceTId());
                strings.add(device.getRfidSurfaceId());
            }
        }
        return strings;
    }

    /**
     * 描述：生成装备的RFID表面号
     *
     * @param deviceType    装备类型 共10位
     * @param partType      配件类型 主体为0 共1位
     * @param deviceNumber  装备序列号 由用户填写
     * @param produceNumber 生产序列号 用户填写
     * @return 生成的RFID表面号
     */
    public String makeRfidNumber(String partType, String deviceNumber, String produceNumber, String deviceType) {
        //配件类型的长度只能为1
        if (partType.length() > 1) {
            throw new IllegalArgumentException("配件类型字段过长");
        }
        StringBuilder stringBuffer = new StringBuilder();
        if (deviceType.length() <= 10) {
            stringBuffer.append(deviceType);
            for (int i = 0; i < 10 - deviceType.length(); i++) {
                stringBuffer.append(" ");
            }
        } else {
            stringBuffer.append(deviceType.substring(deviceType.length() - 10));
        }
        stringBuffer.append("p");
        stringBuffer.append(partType);

        if (deviceNumber.length() < 4) {
            stringBuffer.append(deviceNumber);
            for (int i = 0; i < 4 - deviceNumber.length(); i++) {
                stringBuffer.append(" ");
            }
        } else {
            stringBuffer.append(deviceNumber.substring(deviceNumber.length() - 4));
        }

        if (produceNumber.length() < 4) {
            stringBuffer.append(produceNumber);
            for (int i = 0; i < 4 - produceNumber.length(); i++) {
                stringBuffer.append(" ");
            }
        } else {
            stringBuffer.append(produceNumber.substring(produceNumber.length() - 4));
        }
        return stringBuffer.toString();
    }

}
