/**
 * 文件：AssetController.java 版本：1.0.0 日期： Copyright &reg; All right reserved.
 */
package com.mortals.xhx.module.asset.web;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.mortals.framework.ap.FormState;
import com.mortals.framework.ap.SysConstains;
import com.mortals.framework.common.IBaseEnum;
import com.mortals.framework.common.code.YesNo;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.Context;
import com.mortals.framework.util.StringUtils;
import com.mortals.framework.web.BaseCRUDJsonMappingController;
import com.mortals.xhx.base.system.param.service.ParamService;
import com.mortals.xhx.common.code.AssetFlowStatusEnum;
import com.mortals.xhx.common.key.Constant;
import com.mortals.xhx.common.utils.ZipUtil;
import com.mortals.xhx.module.asset.model.AssetEntity;
import com.mortals.xhx.module.asset.model.AssetQRcodeParam;
import com.mortals.xhx.module.asset.service.AssetService;
import com.mortals.xhx.module.materia.model.MateriaBomEntity;
import com.mortals.xhx.module.materia.model.MateriaBomQuery;
import com.mortals.xhx.module.materia.model.MateriaEntity;
import com.mortals.xhx.module.materia.model.MateriaQuery;
import com.mortals.xhx.module.materia.service.MateriaBomService;
import com.mortals.xhx.module.materia.service.MateriaService;
import com.mortals.xhx.module.supplier.model.SupplierEntity;
import com.mortals.xhx.module.supplier.model.SupplierQuery;
import com.mortals.xhx.module.supplier.service.SupplierService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.*;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.ImageOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * Title: 资产表
 * </p>
 * <p>
 * Description: AssetController
 * </p>
 * <p>
 * Copyright: Copyright &reg;
 * </p>
 * <p>
 * Company:
 * </p>
 * @author
 * @version 1.0.0
 */
@RestController
@RequestMapping("asset")
public class
AssetController extends BaseCRUDJsonMappingController<AssetService, AssetForm, AssetEntity, Long> {

    @Autowired
    private ParamService paramService;

    @Autowired
    private MateriaService materiaService;

    @Autowired
    private MateriaBomService materiaBomService;

    @Autowired
    private SupplierService supplierService;

    @Value("${upload.path}")
    private String filePath;


    public AssetController() {
        super.setFormClass(AssetForm.class);
        super.setModuleDesc("资产表");
    }

    @Override
    protected void init(HttpServletRequest request, HttpServletResponse response, AssetForm form,
            Map<String, Object> model, Context context) {
        this.addDict(model, "enabled", IBaseEnum.getEnumMap(YesNo.class));
        this.addDict(model, "flowStatus", paramService.getParamByFirstOrganize(Constant.Param_AssetFlowStatus,AssetFlowStatusEnum.Special_597.getValue(),Constant.Param_AssetFlowStatus,
				AssetFlowStatusEnum.Special_598.getValue(), AssetFlowStatusEnum.Special_599.getValue()));
        List<AssetEntity> list = (List<AssetEntity>) model.get(SysConstains.RESULT_KEY);
        if(list != null && list.size() >0){
            List<Long> materiaIdList = list.stream().map(AssetEntity::getMateriaId).collect(Collectors.toList());
            MateriaQuery materiaQuery = new MateriaQuery();
            materiaQuery.setIdList(materiaIdList);
            List<MateriaEntity> materiaEntities = materiaService.find(materiaQuery, null);
            Map<String, String> materiaIdDict = materiaEntities.stream().collect(Collectors.toMap(item->item.getId().toString(), v->"["+v.getCode() +"]"+v.getName()));
            this.addDict(model, "materiaId", materiaIdDict);

            List<Long> bomIdList = list.stream().map(AssetEntity::getBomId).collect(Collectors.toList());
            if(!bomIdList.isEmpty()){
                MateriaBomQuery bomQuery = new MateriaBomQuery();
                bomQuery.setIdList(bomIdList);
                List<MateriaBomEntity> bomEntities = materiaBomService.find(bomQuery, null);
                Map<String, String> bomIdDict = bomEntities.stream().collect(Collectors.toMap(item->item.getId().toString(), item ->  "[" + item.getCode() + "]" + item.getMateriaName() +"【版本： " +  item.getVersion() +"】"));
                this.addDict(model, "bomId", bomIdDict);
            }

            List<Long> producerIdList = list.stream().map(AssetEntity::getProducerId).collect(Collectors.toList());
            if(!producerIdList.isEmpty()){
                SupplierQuery supplierQuery = new SupplierQuery();
                supplierQuery.setIdList(producerIdList);
                List<SupplierEntity> supplierEntities = supplierService.find(supplierQuery, null);
                Map<String, String> producerIdDict = supplierEntities.stream().collect(Collectors.toMap(item->item.getId().toString(), SupplierEntity::getName));
                this.addDict(model, "producerId", producerIdDict);
            }




        }


        super.init(request, response, form, model, context);
    }


    @Override
    protected int editAfter(HttpServletRequest request, HttpServletResponse response, AssetForm form,
            Map<String, Object> model, AssetEntity entity, Context context) throws AppException {
        return super.editAfter(request, response, form, model, entity, context);
    }

    @Override
    protected void addAfter(HttpServletRequest request, HttpServletResponse response, AssetForm form,
            Map<String, Object> model) throws AppException {
        super.addAfter(request, response, form, model);
    }

    @Override
    protected void saveBefore(HttpServletRequest request, HttpServletResponse response, AssetForm form, Map<String, Object> model, Context context) throws AppException {
        Long bomId = form.getEntity().getBomId();
        if(bomId == null){
            throw new AppException("请选择BOM版本");
        }
        MateriaBomEntity materiaBomEntity = materiaBomService.get(bomId, this.getContext());
        form.getEntity().setMateriaId(materiaBomEntity.getMateriaId());
        form.getEntity().setMateriaCode(materiaBomEntity.getMateriaCode());
        super.saveBefore(request, response, form, model, context);
    }

    /**
     * 导入
     * @param request
     * @param response
     * @param form
     * @return
     */
    @PostMapping(value = "saveImport")
    public String saveImport(HttpServletRequest request, HttpServletResponse response, AssetForm form) {
        Map<String, Object> model = Maps.newHashMap();
        Context context = getContext();
        int code = 0;
        boolean tokenValid = true;
        String desc = "导入" + getModuleDesc();
        try {
           /* tokenValid = isTokenValid(request, response, true);
            if (!tokenValid) {
                throw new AppException("重复提交");
            }*/
            if (StringUtils.isEmpty(form.getImportFile())) {
                throw new AppException("请上传文件");
            }
            String suffix = form.getImportFile().substring(form.getImportFile().lastIndexOf(".") + 1);
            if (!"xlsx".equals(suffix)) {
                throw new AppException("文件类型错误，只支持xlsx和xls");
            }
            Map<String, Object> result = service.saveImport(form.getEntity(), form.getImportFile(), getCurUser());
            form.setExcuteResult(SysConstains.ACTI_RESULT_SUCC);
            code = VALUE_RESULT_SUCCESS;
            model.put(SysConstains.FORM_STATE, FormState.ADD);
            model.put("import", true);
            model.put(SysConstains.MESSAGE_INFO, "导入完成");
            model.put("importResult", result);
            recordSysLog(request, result.toString());

        } catch (Exception e) {
            form.setExcuteResult(SysConstains.ACTI_RESULT_FAIL);
            doException(request, desc, model, e);
            form.getEntity().setId(null);
            model.put(KEY_RESULT_ENTITY, form.getEntity());
            init(request, response, form, model, context);
            if (tokenValid) {
                saveToken(request, response);
            }
            code = saveException(request, response, form, model, context, e);
        }
        init(request, response, form, model, context);
        JSONObject ret = new JSONObject();
        ret.put(KEY_RESULT_CODE, code);
        ret.put(KEY_RESULT_MSG, model.remove(SysConstains.MESSAGE_INFO));
        ret.put(KEY_RESULT_DATA, model);
        return ret.toJSONString();

    }

    /**
     * 启用停用
     * @param request
     * @param response
     * @param form
     * @return
     */
    @PostMapping(value = "operEnabled")
    public String operEnabled(HttpServletRequest request, HttpServletResponse response, AssetForm form) {
        String busiDesc = "应用状态变更";
        try {
            AssetEntity appEntity = form.getEntity();

            AssetEntity entity = this.getService().get(form.getEntity().getId(), null);
            if(entity == null){
                throw new AppException("资产不存在");
            }
            entity.setEnabled(appEntity.getEnabled());
            entity.setUpdateTime(new Date());
            entity.setUpdateUserId(this.getCurUser().getId());
            entity.setUpdateUser(this.getCurUser().getLoginName());
            entity.setUpdateUserName(this.getCurUser().getRealName());
            this.getService().update(entity, this.getContext());

            this.recordSysLog(request, busiDesc + " 【成功】 [id:" + entity.getId() + "]");

            JSONObject ret = new JSONObject();
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_SUCCESS);
            ret.put(KEY_RESULT_MSG, "资产状态变更成功");
            ret.put(KEY_RESULT_DATA, "");
            return ret.toJSONString();


        } catch (Exception e) {

            this.doException(request, busiDesc, new HashMap<>(), e);

            JSONObject ret = new JSONObject();
            ret.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
            ret.put(KEY_RESULT_MSG, super.convertException(e));
            return ret.toJSONString();
        }
    }


    /**
     * 导出设备二维码
     *
     * @param request
     * @param response
     * @param form
     */
    @PostMapping("exportQRcode")
    public void exportQRcode(HttpServletRequest request, HttpServletResponse response, AssetForm form) {

        OutputStream os = null;
        InputStream ins = null;
        String zipPath = null;
        String qrcodePath = null;
        Context context = getContext();
        Map<String, Object> model = new HashMap<String, Object>();
        String busiDesc = "导出资产二维码" + getModuleDesc();
        try {
            doExportBefore(context, form);
            List<AssetEntity> assetEntityList = getService().find(form.getQuery(), context);
            if (assetEntityList.isEmpty()) {
                super.recordSysLog(request, busiDesc + " 【失败】 没有可导出的数据");
                response.setContentType("application/text;charset=UTF-8");
               // this.writeResponse(response, "没有可导出的数据");
                return;
            }
            if (assetEntityList.size() > 200) {
                super.recordSysLog(request, busiDesc + " 【失败】 导出数量超过上限200");
                response.setContentType("application/text;charset=UTF-8");
               // this.writeResponse(response, "导出数量超过上限200");
                return;
            }
            // 获取二维码文件夹目录
            String rootPath = this.filePath.endsWith("/") ? this.filePath : this.filePath + "/";
            qrcodePath = rootPath + "qrcode/" + System.currentTimeMillis() + "/";
            File pathDir = new File(qrcodePath);
            if (!pathDir.exists()) {
                pathDir.mkdirs();
            }
            // 设计二维码下方字体
            // Font font = getFont();
            // 生成二维码
            for (AssetEntity assetEntity : assetEntityList) {
                //展示的资产码：Z+资产码
                String showCode =  assetEntity.getAssetNum();
                File qrFile = new File(qrcodePath + showCode + ".png");

                drawLogoQRCode(qrFile, showCode, showCode, request, busiDesc, model);
            }
            // 将二维码文件进行压缩
            zipPath = rootPath + System.currentTimeMillis() + ".zip";
            ZipUtil.zip(qrcodePath, zipPath);
            File zipFile = new File(zipPath);
            ins = new BufferedInputStream(new FileInputStream(zipFile));
            byte[] fileByte = new byte[ins.available()];
            ins.read(fileByte);
            response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(zipPath, "UTF-8"));
            response.setContentType("application/octet-stream;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            os = response.getOutputStream();
            os.write(fileByte);
            os.flush();
            super.recordSysLog(request, busiDesc + " 【成功】");
        } catch (Exception e) {
            doException(request, busiDesc, model, e);
            response.setContentType("application/text;charset=UTF-8");
          //  this.writeResponse(response, this.convertException(e));
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (Exception var9) {
                    this.doException(request, busiDesc, model, var9);
                }
            }
            if (ins != null) {
                try {
                    ins.close();
                } catch (Exception var9) {
                    this.doException(request, busiDesc, model, var9);
                }
            }
            // 将生成的临时文件进行删除
            if (zipPath != null) {
                ZipUtil.deletefile(zipPath);
            }
            if (qrcodePath != null) {
                ZipUtil.deletefile(qrcodePath);
            }
        }
    }

    /**
     * 生成二维码图片
     *
     * @param codeFile 图片保存路径
     * @param qrUrl 二维码类容
     * @param note 二维码文字
     */
    private void drawLogoQRCode(File codeFile, String qrUrl, String note, HttpServletRequest request, String busiDesc,
                                Map<String, Object> model) {
        OutputStream os = null;
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        hints.put(EncodeHintType.MARGIN, 0);
        BufferedImage image = new BufferedImage(AssetQRcodeParam.WIDTH, AssetQRcodeParam.HEIGHT,
                BufferedImage.TYPE_INT_RGB);
        try {
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            // 参数顺序分别为：编码内容，编码类型，生成图片宽度，生成图片高度，设置参数
            BitMatrix bm = multiFormatWriter.encode(qrUrl, BarcodeFormat.QR_CODE, AssetQRcodeParam.WIDTH,
                    AssetQRcodeParam.HEIGHT, hints);
            // 开始利用二维码数据创建Bitmap图片，分别设为黑（0xFFFFFFFF）白（0xFF000000）两色
            for (int x = 0; x < AssetQRcodeParam.WIDTH; x++) {
                for (int y = 0; y < AssetQRcodeParam.HEIGHT; y++) {
                    image.setRGB(x, y, bm.get(x, y) ? AssetQRcodeParam.QRCOLOR : AssetQRcodeParam.BGWHITE);
                }
            }
            // 将98px图片进行压缩为76px图片
            BufferedImage img = new BufferedImage(760, 760, BufferedImage.TYPE_INT_RGB);
            Graphics2D graphicsImg = img.createGraphics();
            graphicsImg.drawImage(image, 00, 00, 760, 760, null);
            // 自定义文本描述
            if (StringUtils.isNotEmpty(note)) {
                // 新的图片，把带二维码下面加上文字
                BufferedImage outImage = new BufferedImage(1000, 1000, BufferedImage.TYPE_INT_RGB);
                Graphics2D outg = outImage.createGraphics();
                outg.setColor(Color.WHITE);// 颜色
                outg.fillRect(0, 0, 1000, 1000);// 填充整个屏幕
                // 画二维码到新的面板
                outg.drawImage(img, 120, 60, img.getWidth(), img.getHeight(), null);
                // 画文字到新的面板
                outg.setColor(Color.BLACK);// 颜色
                // outg.setFont(font != null ? font : new Font("arial",
                // Font.PLAIN, 8));
                outg.setFont(new Font("arial", Font.PLAIN, 70)); // 字体、字型、字号
                // log.info("FontFamily:"+outg.getFont().getFamily()+"--FontName:"+outg.getFont().getName());
                outg.drawString(note, 140, 930); // 画文字
                outg.dispose();
                outImage.flush();
                image = outImage;
            }
            image.flush();
            // ImageIO.write(image, "jpg", codeFile);
            // 设置图片的DPI为300
            byte[] process = process(image, 300, request, busiDesc, model);
            if (process != null) {
                os = new FileOutputStream(codeFile);
                os.write(process, 0, process.length);
                os.flush();
            } else {
                throw new AppException("设备" + note + "生成二维码时设置dpi失败");
            }
        } catch (Exception var9) {
            this.doException(request, busiDesc, model, var9);
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException var9) {
                    this.doException(request, busiDesc, model, var9);
                }
            }
        }
    }

    private byte[] process(BufferedImage image, int dpi, HttpServletRequest request, String busiDesc,
                           Map<String, Object> model) {
        ByteArrayOutputStream output = null;
        ImageOutputStream stream = null;
        for (Iterator<ImageWriter> iw = ImageIO.getImageWritersByFormatName("png"); iw.hasNext();) {
            ImageWriter writer = iw.next();
            ImageWriteParam writeParam = writer.getDefaultWriteParam();
            ImageTypeSpecifier typeSpecifier = ImageTypeSpecifier
                    .createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
            IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam);
            if (metadata.isReadOnly() || !metadata.isStandardMetadataFormatSupported()) {
                continue;
            }
            try {
                output = new ByteArrayOutputStream();
                setDPI(metadata, dpi);
                stream = ImageIO.createImageOutputStream(output);
                writer.setOutput(stream);
                writer.write(metadata, new IIOImage(image, null, metadata), writeParam);
            } catch (IOException var9) {
                this.doException(request, busiDesc, model, var9);
            } finally {
                if (stream != null) {
                    try {
                        stream.close();
                    } catch (IOException var9) {
                        this.doException(request, busiDesc, model, var9);
                    }
                }
                if (output != null) {
                    try {
                        output.close();
                    } catch (IOException var9) {
                        this.doException(request, busiDesc, model, var9);
                    }
                }
            }
            return output.toByteArray();
        }
        return null;
    }
    /**
     * 设置图片的DPI值
     *
     * @param metadata
     * @param dpi
     * @return void
     */
    private void setDPI(IIOMetadata metadata, int dpi) throws IIOInvalidTreeException {
        double dotsPerMilli = 1.0 * dpi / 10 / AssetQRcodeParam.INCH_2_CM;
        IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
        horiz.setAttribute("value", Double.toString(dotsPerMilli));
        IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
        vert.setAttribute("value", Double.toString(dotsPerMilli));
        IIOMetadataNode dim = new IIOMetadataNode("Dimension");
        dim.appendChild(horiz);
        dim.appendChild(vert);
        IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
        root.appendChild(dim);
        metadata.mergeTree("javax_imageio_1.0", root);
    }


}