package com.bonait.bnframework.business;

import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import androidx.annotation.NonNull;

import com.aliyun.alink.linksdk.channel.core.base.INet;
import com.bonait.bnframework.common.constant.ConfigName;
import com.bonait.bnframework.common.constant.DataBus;
import com.bonait.bnframework.common.constant.MessageName;
import com.bonait.bnframework.common.db.QueryDB;
import com.bonait.bnframework.common.db.mode.BPA_GOODS;
import com.bonait.bnframework.common.db.mode.BPA_GOODSRECIPE;
import com.bonait.bnframework.common.db.mode.BPA_PLCADDRESS;
import com.bonait.bnframework.common.db.mode.BPA_SILOS;
import com.bonait.bnframework.common.helper.ByteHelper;
import com.bonait.bnframework.common.helper.I.IRun;
import com.bonait.bnframework.common.helper.I.IRunT;
import com.bonait.bnframework.common.helper.I.IThread;
import com.bonait.bnframework.common.helper.I.IWriteCallBack;
import com.bonait.bnframework.common.helper.ThreadManager;
import com.bonait.bnframework.common.message.MessageManager;
import com.bonait.bnframework.common.modbus.ModbusTcpMainServer;
import com.bonait.bnframework.common.modbus.ModbusTcpServer;
import com.bonait.bnframework.common.utils.ToastUtils;
import com.bonait.bnframework.modules.home.fragment.mode.MyStatus;
import com.qmuiteam.qmui.widget.dialog.QMUIDialog;
import com.qmuiteam.qmui.widget.dialog.QMUIDialogAction;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 执行配方
 */
public class ExecuteTheRecipe {

    //region 变量
    /**
     * 等待超时时间
     */
    //public static int whileTime = 40;
    public static int whileTime = 100;

    //手动操作耗时时长
    public static int HandTime=0;

    /**
     * 监听变量值
     */
    public static HashMap<String, Object> ListeningValue = new HashMap<String, Object>();

    /**
     * 外部界面
     */
    public static Context context = null;

    /**
     * 商品是否强制结束
     */
    public static boolean IsForcedEnd = false;

    /**
     * 当前配方
     */
    public static ArrayList<BPA_GOODSRECIPE> all_list = new ArrayList<>();

    static BPA_GOODSRECIPE selectpf;
    /**
     * 当前工序的index
     */
    static int Index_select = 0;
    /**
     * 商品是否开始制作
     */
    public static boolean MakeStatus = false;
    /**
     * 是否启动
     */
    public static boolean IsStart = false;
    /**
     * 是否暂停
     */
    public static boolean IsPause = false;

    /**
     * 当前执行工序
     */
    public static IRunT ExecuteCurrentOperation = null;
    /**
     * plc 当前版本号
     */
    public static String PlcVersion="0001";
    /**
     * 通知版本号更新显示
     */
    public static IRun NotifyVersionNumUpdates = null;

    /**
     * 通知手动暂停
     */
    public static IRunT NoticeHandSuspension = null;

    /**
     * 当前工序预计剩余时间
     */
    public static IRunT NoticeAtPresentTime=null;
    //endregion

    //region 强制结束

    /**
     * 设置强制结束
     */
    public static void SetForcedEnd() {
        ToastUtils.info("客官,小菠萝正在强制结束当前炒制菜品,请耐心等候!!!");
        IsForcedEnd = true;
    }

    /**
     * 停止强制结束
     */
    public static void StopForcedEnd() {
        IsForcedEnd = false;
    }
    //endregion

    //region 执行配方

    /**
     * 执行配方
     *
     * @param recipe
     * @return
     */
    public static boolean Execute(BPA_GOODSRECIPE recipe, ArrayList<BPA_GOODSRECIPE> all, int index) {
        boolean status = false;
        all_list = all;
        selectpf = recipe;
        Index_select = index;
        try {
            //1.解析
            if (IsForcedEnd) {
                ExecuteTheRecipe.showlog("客官,小菠萝正在强制结束当前炒制菜品,请耐心等候!!!");
                return false;
            }

            if(!ConfigName.getInstance().PlcIsConnect)
            {
                ExecuteTheRecipe.showlog("客官,检测到硬件已经断开连接,主动停止炒制!!!");
                IsForcedEnd=true;
                return false;
            }

            //判断是否加热异常
            boolean isJre = false;
            Object K = ReadPLC("加热");
            isJre = K == null ? false : (boolean) K;
            if(isJre)//判断是否加热异常
            {
                Object gz = ReadPLC("异常加热故障信息");
                if(gz!=null && (boolean) gz)
                {
                    ExecuteTheRecipe.showlog("客官,检测到硬件加热异常，已主动停止炒制，请联系海科人员!!!");
                    IsForcedEnd=true;
                    final boolean[] IsComplete = {false};
                    String title = "加热异常-温馨提示！";
                    String message = "客官硬件加热异常，请联系海科人员，已强制停止炒制！";
                    Activity activity = findActivity(context);
                    if (activity != null) {
                        activity.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                try {

                                    //.setCanceledOnTouchOutside(false) // 禁用点击其他地方关闭对话框
                                    new QMUIDialog.MessageDialogBuilder(context).setCancelable(false).setCanceledOnTouchOutside(false).setTitle(title).setMessage(message).addAction("确定", new QMUIDialogAction.ActionListener() {
                                        @Override
                                        public void onClick(QMUIDialog dialog, int index) {
                                            IsComplete[0] = true;
                                            dialog.dismiss();
                                        }
                                    }).create(com.qmuiteam.qmui.R.style.QMUI_Dialog).show();

                                } catch (Exception e) {

                                }
                            }
                        });
                    }
                    while (!IsComplete[0]) {
                        Thread.sleep(100);//10 *6
                    }
                    return false;
                }
            }

            ExecuteTheRecipe.showlog("开始执行:" + recipe.sort + "、" + recipe.processms);
            if (NoticeAtPresentTime!=null){NoticeAtPresentTime.Run(0);}

            if (recipe.materialType == 0)//正常物料
            {
                //先到达抽料位
                Make位置("抽料位");
                //开始配料
                ExecuteMaterialIssuance(recipe.processvalue);
            } else if (recipe.materialType == 1)//工序模型
            {
                if (recipe.processname.equals("加水") || recipe.processname.equals("并行出料")) {
                    Make位置("抽料位");
                } else if (recipe.processname.equals("主料")) {
                    if (ConfigName.getInstance().versionSelectionEnum.contains("一拖")) {
                        Make位置("原点位");
                    } else {
                        Make位置("炒菜位1");
                    }
                } else if (recipe.processname.equals("辅料")) {
                    Make位置("原点位");
                }

                //执行工序
                ExecuteOperationSteps(recipe.processname, recipe.processvalue);

                if (recipe.processname.equals("出菜")) {
                    Make位置("炒菜位1");
                }
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
            status = false;
        } finally {
            return status;
        }
    }

    /**
     * 液体物料信息-配料
     *
     * @param text
     */
    public static void ExecuteMaterialIssuance(String text) {
        try {
            if (!text.isEmpty()) {
                long startTime = System.currentTimeMillis(); //起始时间
                if(NoticeHandSuspension!=null){NoticeHandSuspension.Run(true);}


                //仓号 值
                HashMap<BPA_SILOS, Integer> formulation = new HashMap<>();
                int MaxValue=0;
                //region 获取仓号和值
                List<String> data = new ArrayList<>();
                if (text.contains("|")) {
                    String[] res = text.split("[|]");
                    for (int i = 0; i < res.length; i++) {
                        data.add(res[i]);
                    }
                } else {
                    data.add(text);
                }
                for (String item : data) {
                    if (!item.isEmpty() && item.contains(",")) {
                        String[] wl = item.split("[,]");
                        if (wl != null && wl.length == 2) {
                            String name = wl[0];
                            //int val = (int) Math.round((Double.parseDouble(wl[1]) * 10));
                            int val = (int) Math.round((Double.parseDouble(wl[1])));
                            //int val = Integer.parseInt(wl[1]);
                            List<BPA_SILOS> bpa_silos = QueryDB.GetSolisByMaterialName(name);
                            if (bpa_silos.size() > 0 && val > 0) {
                                BPA_SILOS silos = bpa_silos.get(0);
                                if(val>=32767)
                                {
                                    val=32767;
                                    ExecuteTheRecipe.showlog("料仓" + silos.num + "出量克数溢出，已按照最大出量出料！！！");
                                }
                                formulation.put(silos, val);

                                Object jz_z=ReadPLC("料仓"+silos.num+"校准值");
                                if(jz_z!=null)
                                {
                                    int jzzz= Integer.parseInt(String.valueOf(jz_z));
                                    int jzzz_1=jzzz==0?500:jzzz;
                                    int ztime= (int)(val/ (jzzz_1/5.0));
                                    MaxValue=ztime>MaxValue?ztime:MaxValue;
                                }
                            }
                        }
                    }
                }
                //endregion
                //写入PLC,直接出料，不用等待
                for (Map.Entry<BPA_SILOS, Integer> entry : formulation.entrySet()) {
                    BPA_SILOS silos = entry.getKey();
                    Integer value = entry.getValue();
                    Write_PLC_Material(silos, value);
                }

                Thread.sleep(200);//等待写入完成

                //一直等待下料完成 否则就一直等待 40s超时
                for (Map.Entry<BPA_SILOS, Integer> entry : formulation.entrySet()) {
                    BPA_SILOS silos = entry.getKey();
                    ThreadWhile_WL("料仓" + silos.num + "下料完成",MaxValue);
                }

                long endTime = System.currentTimeMillis(); //结束时间
                int time = (int) ((endTime - startTime) / 1000);
                HandTime=HandTime+time;
                if(NoticeHandSuspension!=null){NoticeHandSuspension.Run(false);}
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }

    /**
     * 执行工序步骤
     *
     * @param text
     */
    public static void ExecuteOperationSteps(String processname, String text) {
        try {
            if (!text.isEmpty() && !processname.isEmpty()) {
                //工序名称和值
                HashMap<String, String> formulation = new HashMap<>();
                //region 获取仓号和值
                List<String> data = new ArrayList<>();
                if (text.contains("|")) {
                    String[] res = text.split("[|]");
                    for (int i = 0; i < res.length; i++) {
                        data.add(res[i]);
                    }
                } else {
                    data.add(text);
                }
                for (String item : data) {
                    if (!item.isEmpty() && item.contains(",")) {
                        String[] wl = item.split("[,]");
                        if (wl != null && wl.length == 2) {
                            String name = wl[0];
                            String val = wl[1];
                            formulation.put(name, val);
                        }
                    }
                }
                //endregion
                //写入PLC
                if (formulation.size() > 0) {
                    switch (processname) {
                        case "搅拌":
                            Write_PLC_Stir(formulation);
                            break;
                        case "位置":
                            Write_PLC_Location(formulation);
                            break;
                        case "加热":
                            Write_PLC_Heating(formulation);
                            break;
                        case "主料":
                            if (ConfigName.getInstance().versionSelectionEnum.contains("一拖四")) {
                                Write_PLC_MainIngredients4(formulation);
                            } else if (ConfigName.getInstance().versionSelectionEnum.contains("一拖二")) {
                                Write_PLC_MainIngredients2(formulation);
                            } else {
                                Write_PLC_Ingredients(formulation);
                            }
                            break;
                        case "辅料":
                            if (ConfigName.getInstance().versionSelectionEnum.contains("一拖")) {
                                Write_PLC_MainAccessory(formulation);
                            }
                            break;
                        case "并行出料":
                            Write_PLC_ParallelDischarge(formulation);
                            break;
                        case "延迟":
                            Write_PLC_Delay(formulation);
                            break;
                        case "出菜":
                            if (ConfigName.getInstance().versionSelectionEnum.contains("一拖")) {
                                Write_PLC_MainOutdishes(formulation);
                            } else {
                                Write_PLC_Outdishes(formulation);
                            }
                            break;
                        case "清洗":
                            Write_PLC_CleanPan(formulation);
                            break;
                    }
                }
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }
    //endregion

    //region 物料PLC控制

    /**
     * 写入仓号需求值
     *
     * @param silos
     * @param val
     */
    private static void Write_PLC_Material(BPA_SILOS silos, int val) {
        try {
            if (ExecuteCurrentOperation != null) {
                ExecuteCurrentOperation.Run("液体料|" + silos.num);
            }
            //ExecuteTheRecipe.showlog("准备写入PLC仓号需求:" + silos.num + "," + val / 10.0);
            ExecuteTheRecipe.showlog("准备写入PLC仓号需求:" + silos.num + "," + val);

            String name = "料仓" + silos.num + "下料完成";
            ExecuteTheRecipe.WritePLC(name, false, null);

            final boolean[] IsComplete = {false};

            WritePLC("料仓" + silos.num + "需求值", val, new IWriteCallBack() {
                @Override
                public void onSuccess() {
                    ExecuteTheRecipe.showlog("需求值写入成功！");
                    IsComplete[0] = true;
                }

                @Override
                public void onFailure(String ErrorMsg) {
                    ExecuteTheRecipe.showlog("需求值写入失败！尝试再次写入...错误原因：" + ErrorMsg);
                    WritePLC("料仓" + silos.num + "需求值", val, null);
                    IsComplete[0] = true;
                }
            });

            Thread.sleep(200);

            BottomClick1("料仓" + silos.num + "下料");

            ExecuteTheRecipe.showlog("料仓" + silos.num + "下料");

            //減去料仓数量
            int otherG = silos.silosmargin - (val / 10);
            QueryDB.UpdateYL(silos.id, otherG >= 0 ? otherG : 0);
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }
    //endregion

    //region 写PLC工序

    /**
     * 写PLC搅拌
     *
     * @param data
     */
    private static void Write_PLC_Stir(HashMap<String, String> data) {
        try {
            int val = 0; int writeValue=0;
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (key.contains("(秒)")) {
                    val = Integer.parseInt(value);
                } else {
                    ToastUtils.info("工序:" + key + "," + value);
                    writeValue = GetMXValue(key, value);
                    if (ExecuteCurrentOperation != null) {
                        ExecuteCurrentOperation.Run("搅拌" + "|" + writeValue);
                    }
                    int finalWriteValue = writeValue;
                    WritePLC(key, writeValue, new IWriteCallBack() {
                        @Override
                        public void onSuccess() {
                            ExecuteTheRecipe.showlog("搅拌，挡位-" + finalWriteValue + "，写入成功！");
                            if (finalWriteValue == 0) {
                                WritePLC("搅拌", false, null);
                            } else {
                                WritePLC("搅拌", true, null);
                            }
                        }

                        @Override
                        public void onFailure(String ErrorMsg) {
                            ExecuteTheRecipe.showlog("搅拌，挡位-" + finalWriteValue + "，写入失败！原因：" + ErrorMsg);
                            WritePLC(key, finalWriteValue, null);
                            if (finalWriteValue == 0) {
                                WritePLC("搅拌", false, null);
                            } else {
                                WritePLC("搅拌", true, null);
                            }
                        }
                    });
                }
            }

            //region 回读验证
            Object obj= ReadPLC("搅拌");
            if(obj!=null)
            {
                ExecuteTheRecipe.showlog("搅拌回读信号，挡位-" + writeValue + "，开关状态：" + obj);
                if(writeValue==0)
                {
                    if((boolean) obj)
                    {
                        ExecuteTheRecipe.showlog("搅拌重写，写入开关状态：false，写入成功！");
                        WritePLC("搅拌", false, null);
                    }
                }else
                {
                    if(!(boolean) obj)
                    {
                        ExecuteTheRecipe.showlog("搅拌重写，写入开关状态：true，写入成功！");
                        WritePLC("搅拌", true, null);
                    }
                }
            }
            //endregion

            if (val > 0 && !IsForcedEnd) {
                ThreadDelay(val);
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }

    /**
     * 写PLC位置
     *
     * @param data
     */
    private static void Write_PLC_Location(HashMap<String, String> data) {
        try {
            int val = 0;
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (key.contains("(秒)")) {
                    val = Integer.parseInt(value);
                } else if (key.contains("速度")) {
                    int writeValue = GetMXValue(key, value);
                    //修改最高速度40
                    WritePLC(key, writeValue >= 30 ? 30 : writeValue, null);
                }
            }

            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (!key.contains("(秒)") && !key.contains("速度")) {
                    ExecuteTheRecipe.showlog("工序:" + key + "," + value);

                    if (ExecuteCurrentOperation != null) {
                        ExecuteCurrentOperation.Run("位置" + "|" + value);
                    }
                    //原点位,等待机器移动倒响应位置
                    BottomClick1(value);

                    //一直等待机器移动到该位置
                    ThreadWhile(value + "反馈");
                }
            }

            if (val > 0 && !IsForcedEnd) {
                ThreadDelay(val);
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }

    /**
     * 写PLC主料
     *
     * @param data
     */
    private static void Write_PLC_Ingredients(HashMap<String, String> data) {
        try {
            //是否手动
            boolean ishand = true;

            //region 判断是否手动
            if (ConfigName.getInstance().versionSelectionEnum.equals("大炒版本")) {
                ishand = true;
            } else {
                for (HashMap.Entry<String, String> entry : data.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    if (key.contains("投料动作")) {
                        if (value.contains("手动投料")) {
                            ishand = true;
                        } else {
                            ishand = false;
                        }
                    }
                }
            }
            //endregion


            if (ishand) {
                if (ConfigName.getInstance().versionSelectionEnum.equals("大炒自动投料版本") || ConfigName.getInstance().versionSelectionEnum.equals("小炒版本")) {
                    ExecuteTheRecipe.BottomClick1("平移-去1号位");
                }
                String name = "";
                String zl = "";
                int val = 0;
                for (HashMap.Entry<String, String> entry : data.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    if (key.contains("名称")) {
                        name = value;
                    } else if (key.contains("重量")) {
                        zl = value;
                    }
                }
                ExecuteTheRecipe.showlog("工序:手动投料," + name + "," + zl);
                String title = "手动投料-温馨提示！";
                String message = "客官请投入主料,[" + name + "]重量" + zl + "g,投入后点击[确定]继续流程！";

                if (ConfigName.getInstance().WhetherManualFeedingSuspended.contains("是")) {
                    ExecuteTheRecipe.WritePLC("暂停开关", true, null);
                }
                ModbusTcpServer.get().WriteBool("M52.1", (boolean) true, null);
                long startTime = System.currentTimeMillis(); //起始时间
                if(NoticeHandSuspension!=null){NoticeHandSuspension.Run(true);}

                final boolean[] IsComplete = {false};
                Activity activity = findActivity(context);
                if (activity != null) {
                    activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            try {

                                //.setCanceledOnTouchOutside(false) // 禁用点击其他地方关闭对话框
                                new QMUIDialog.MessageDialogBuilder(context).setCancelable(false).setCanceledOnTouchOutside(false).setTitle(title).setMessage(message).addAction("确定", new QMUIDialogAction.ActionListener() {
                                    @Override
                                    public void onClick(QMUIDialog dialog, int index) {
                                        IsComplete[0] = true;
                                        dialog.dismiss();
                                    }
                                }).create(com.qmuiteam.qmui.R.style.QMUI_Dialog).show();

                            } catch (Exception e) {

                            }
                        }
                    });
                }

                while (!IsComplete[0]) {
                    Thread.sleep(100);//10 *6
                }

                if (ConfigName.getInstance().WhetherManualFeedingSuspended.contains("是")) {
                    ExecuteTheRecipe.WritePLC("暂停开关", false, null);
                }
                ModbusTcpServer.get().WriteBool("M52.1", (boolean) false, null);
                long endTime = System.currentTimeMillis(); //结束时间
                int time = (int) ((endTime - startTime) / 1000);
                HandTime=HandTime+time;
                if(NoticeHandSuspension!=null){NoticeHandSuspension.Run(false);}


                ExecuteTheRecipe.showlog("手动已确认投入主料:" + name + "-继续流程");
            } else {
                //自动投料
                if (ConfigName.getInstance().versionSelectionEnum.equals("大炒自动投料版本") || ConfigName.getInstance().versionSelectionEnum.equals("小炒版本")) {
                    String writeValue = "1号位";
                    for (HashMap.Entry<String, String> entry : data.entrySet()) {
                        String key = entry.getKey();
                        String value = entry.getValue();
                        if (key.contains("主料位置")) {
                            writeValue = value;
                        }
                    }
                    if (ExecuteCurrentOperation != null) {
                        ExecuteCurrentOperation.Run("主料" + "|" + writeValue);
                    }

                    //1.去某一个位置
                    BottomClick1("平移-去" + writeValue);

                    //一直等待机器移动到该位置，否则就一直等待
                    ThreadWhile("平移轴在" + writeValue);

                    //2.给倒菜启动
                    BottomClick1("主料");

                    //等待倒菜完成
                    ThreadWhile("倒菜完成");
                }
            }

            if (IsMoveYiHaoWei()) {
                if (ConfigName.getInstance().versionSelectionEnum.equals("大炒自动投料版本") || ConfigName.getInstance().versionSelectionEnum.equals("小炒版本")) {
                    ExecuteTheRecipe.BottomClick1("平移-去1号位");
                }
            }

            //判断炒制位置
            String czwz = "炒菜位1";
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (key.contains("炒制位置")) {
                    czwz = value;
                }
            }
            Make位置(czwz);

            //判断是否有烹饪时间
            int val = 0;
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (key.contains("(秒)")) {
                    val = Integer.parseInt(value);
                }
            }

            if (val > 0 && !IsForcedEnd) {
                ThreadDelay(val);
            }

            ExecuteTheRecipe.showlog("烹饪时间等待结束!继续下一步.");
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }

    /**
     * 按下
     *
     * @param name
     */
    public static void BottomClick(String name) {
        try {
            Log.e("按钮按下", name);
            WritePLC(name, true, null);
            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    Log.e("按钮复位", name);
                    ExecuteTheRecipe.WritePLC(name, false, null);
                }
            }, 500);
        } catch (Exception ex) {
            Log.e("按钮异常", name + ex.getMessage());
        }
    }

    /**
     * 组断执行
     *
     * @param name
     */
    public static void BottomClick1(String name) {
        try {
            Log.e("按钮按下", name);
            WritePLC(name, true, null);
            Thread.sleep(200);
            WritePLC(name, false, null);
            Log.e("按钮复位", name);
            ExecuteTheRecipe.showlog("写入plc-------" + name);
        } catch (Exception ex) {
            Log.e("按钮异常", name + ex.getMessage());
            WritePLC(name, false, null);
        }
    }

    private static Activity findActivity(@NonNull Context context) {
        if (context instanceof Activity) {
            return (Activity) context;
        } else if (context instanceof ContextWrapper) {
            return findActivity(((ContextWrapper) context).getBaseContext());
        } else {
            return null;
        }
    }

    /**
     * 写PLC 加热
     *
     * @param data
     */
    private static void Write_PLC_Heating(HashMap<String, String> data) {
        try {
            int val = 0;int writeValue=0;
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (key.contains("(秒)")) {
                    val = Integer.parseInt(value);
                } else {
                    ExecuteTheRecipe.showlog("工序:" + key + "," + value);
                    writeValue = GetMXValue(key, value);
                    if (ExecuteCurrentOperation != null) {
                        ExecuteCurrentOperation.Run("加热" + "|" + writeValue);
                    }
                    //写加热挡位
                    int finalWriteValue = writeValue;
                    WritePLC(key, writeValue, new IWriteCallBack() {
                        @Override
                        public void onSuccess() {
                            ExecuteTheRecipe.showlog("写加热挡位：" + finalWriteValue + "成功");
                            if (finalWriteValue == 0) {
                                ConfigName.getInstance().IsOpenHuoLi = false;
                                WritePLC("加热", false, null);
                            } else {
                                ConfigName.getInstance().IsOpenHuoLi = true;
                                WritePLC("加热", true, null);
                            }
                        }

                        @Override
                        public void onFailure(String ErrorMsg) {
                            ExecuteTheRecipe.showlog("写加热挡位：" + finalWriteValue + "失败,错误原因：" + ErrorMsg);
                            WritePLC(key, finalWriteValue, null);
                            if (finalWriteValue == 0) {
                                ConfigName.getInstance().IsOpenHuoLi = false;
                                WritePLC("加热", false, null);
                            } else {
                                ConfigName.getInstance().IsOpenHuoLi = true;
                                WritePLC("加热", true, null);
                            }
                        }
                    });

                }
            }

            //region 回读验证
            Object obj= ReadPLC("加热");
            if(obj!=null)
            {
                ExecuteTheRecipe.showlog("加热回读信号，挡位-" + writeValue + "，开关状态：" + obj);
                if(writeValue==0)
                {
                    if((boolean) obj)
                    {
                        ExecuteTheRecipe.showlog("加热重写，写入开关状态：false，写入成功！");
                        WritePLC("加热", false, null);
                    }
                }else
                {
                    if(!(boolean) obj)
                    {
                        ExecuteTheRecipe.showlog("加热重写，写入开关状态：true，写入成功！");
                        WritePLC("加热", true, null);
                    }
                }
            }
            //endregion

            if (val > 0 && !IsForcedEnd) {
                ThreadDelay(val);
            }

        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }

    /**
     * 写PLC 并行出料
     *
     * @param data
     */
    private static void Write_PLC_ParallelDischarge(HashMap<String, String> data) {
        try {

            int val = 0;
            int cl_value = 0;
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (key.contains("(秒)")) {
                    val = Integer.parseInt(value);
                } else if (key.contains("出料克数")) {
                    //1000.0    10000/3 3333
                    //cl_value = (int) Math.round((Double.parseDouble(value) * 10));
                    cl_value = (int) Math.round((Double.parseDouble(value)));
                }
            }


            HashMap<BPA_SILOS, Integer> formulation = new HashMap<>();
            List<BPA_SILOS> bpa_silos = QueryDB.GetSilosALL();
            for (BPA_SILOS item : bpa_silos) {
                if (item.num == 1 || item.num == 2 || item.num == 3) {
                    if ((cl_value / 3) > 0) {
                        formulation.put(item, cl_value / 3);
                    }
                }
            }

            //写入PLC,直接出料，不用等待
            for (Map.Entry<BPA_SILOS, Integer> entry : formulation.entrySet()) {
                BPA_SILOS silos = entry.getKey();
                Integer value = entry.getValue();
                Write_PLC_Material(silos, value);
            }

            Thread.sleep(200);//等待写入完成

            //一直等待下料完成 否则就一直等待 40s超时
            for (Map.Entry<BPA_SILOS, Integer> entry : formulation.entrySet()) {
                BPA_SILOS silos = entry.getKey();
                ThreadWhile("料仓" + silos.num + "下料完成");
            }

            if (val > 0 && !IsForcedEnd) {
                ThreadDelay(val);
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }

    /**
     * 写PLC 延迟
     *
     * @param data
     */
    private static void Write_PLC_Delay(HashMap<String, String> data) {
        try {
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                ExecuteTheRecipe.showlog("工序:" + key + "," + value);
                if (key.contains("(秒)") && !IsForcedEnd) {
                    int val = Integer.parseInt(value);
                    ThreadDelay(val);
                }
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }

    /**
     * 写PLC 出菜
     *
     * @param data
     */
    private static void Write_PLC_Outdishes(HashMap<String, String> data) {
        try {
            ExecuteTheRecipe.showlog("准备出菜！");

            //先延迟
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                ToastUtils.info("工序:" + key + "," + value);
                if (key.contains("(秒)")) {
                    int val = Integer.parseInt(value);
                    if (all_list.size() > 0 && !IsForcedEnd) {
                        ThreadDelay(val);
                    }
                }
            }

            ExecuteTheRecipe.WritePLC("搅拌", false, null);
            ExecuteTheRecipe.WritePLC("加热", false, null);
            ExecuteTheRecipe.showlog("关闭搅拌、关闭加热！");

            BottomClick1("出菜");

            //一直等待机器移动到该位置，否则就一直等待 6s超时
            ThreadWhile3("出餐启动反馈", 5);

            ExecuteTheRecipe.showlog("出菜完成,锅体准备回到原位！");
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }

    /**
     * 写PLC 清洗
     *
     * @param data
     */
    private static void Write_PLC_CleanPan(HashMap<String, String> data) {
        try {
            ExecuteTheRecipe.showlog("准备清洗！");

            //先延迟
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                ToastUtils.info("工序:" + key + "," + value);
                if (key.contains("(秒)") && !IsForcedEnd) {
                    int val = Integer.parseInt(value);
                    ThreadDelay(val);
                }
            }

            //复位反馈信号
            ExecuteTheRecipe.WritePLC("炒锅清洗反馈", false, null);

            //开始清洗
            BottomClick1("炒锅清洗");

            //等待清洗完成
            ThreadWhile3("炒锅清洗反馈", 5);

            ExecuteTheRecipe.showlog("炒锅清洗完成！");
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }
    //endregion

    //region 一拖四写PLC工序

    /**
     * 写PLC主料 一拖4
     *
     * @param data
     */
    private static void Write_PLC_MainIngredients4(HashMap<String, String> data) {
        try {
            //是否手动
            boolean ishand = true;
            ExecuteTheRecipe.showlog("准备倒入主料！");

            //region 判断是否手动
            if (ConfigName.getInstance().versionSelectionEnum.equals("大炒版本")) {
                ishand = true;
            } else {
                for (HashMap.Entry<String, String> entry : data.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    if (key.contains("投料动作")) {
                        if (value.contains("手动投料")) {
                            ishand = true;
                        } else {
                            ishand = false;
                        }
                    }
                }
            }
            //endregion


            if (ishand) {
                String name = "";
                String zl = "";
                int val = 0;
                for (HashMap.Entry<String, String> entry : data.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    if (key.contains("名称")) {
                        name = value;
                    } else if (key.contains("重量")) {
                        zl = value;
                    }
                }
                ExecuteTheRecipe.showlog("工序:手动投料," + name + "," + zl);
                String title = "手动投料-温馨提示！";
                String message = "客官请投入主料,[" + name + "]重量" + zl + "g,投入后点击[确定]继续流程！";

                if (ConfigName.getInstance().WhetherManualFeedingSuspended.contains("是")) {
                    ExecuteTheRecipe.WritePLC("暂停开关", true, null);
                }
                ModbusTcpServer.get().WriteBool("M52.1", (boolean) true, null);
                long startTime = System.currentTimeMillis(); //起始时间
                if(NoticeHandSuspension!=null){NoticeHandSuspension.Run(true);}


                final boolean[] IsComplete = {false};
                Activity activity = findActivity(context);
                if (activity != null) {
                    activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                new QMUIDialog.MessageDialogBuilder(context).setCancelable(false).setCanceledOnTouchOutside(false).setTitle(title).setMessage(message).addAction("确定", new QMUIDialogAction.ActionListener() {
                                    @Override
                                    public void onClick(QMUIDialog dialog, int index) {
                                        IsComplete[0] = true;
                                        dialog.dismiss();
                                    }
                                }).create(com.qmuiteam.qmui.R.style.QMUI_Dialog).show();
                            } catch (Exception e) {

                            }
                        }
                    });
                }

                while (!IsComplete[0]) {
                    Thread.sleep(100);//10 *6
                }

                if (ConfigName.getInstance().WhetherManualFeedingSuspended.contains("是")) {
                    ExecuteTheRecipe.WritePLC("暂停开关", false, null);
                }
                ModbusTcpServer.get().WriteBool("M52.1", (boolean) false, null);
                long endTime = System.currentTimeMillis(); //结束时间
                int time = (int) ((endTime - startTime) / 1000);
                HandTime=HandTime+time;
                if(NoticeHandSuspension!=null){NoticeHandSuspension.Run(false);}


                ExecuteTheRecipe.showlog("确定完成,继续制作！");
            } else {
                //自动投料
                String writeValue = "1号位";
                for (HashMap.Entry<String, String> entry : data.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    if (key.contains("主料位置")) {
                        if (!value.contains("3") && !value.contains("4")) {
                            writeValue = value;
                        }
                    }
                }
                if (ExecuteCurrentOperation != null) {
                    ExecuteCurrentOperation.Run("主料" + "|" + writeValue);
                }

                //2.给倒菜启动
                BottomClick1("主料" + writeValue);
                ThreadWhile(writeValue + "倒菜完成");
            }

            if (IsMoveYiHaoWei()) {
                WriteMainPLC("炒锅投主料完成", true, null);
            }

            //判断炒制位置
            String czwz = "炒菜位1";
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (key.contains("炒制位置")) {
                    czwz = value;
                }
            }
            Make位置(czwz);

            //判断是否有烹饪时间
            int val = 0;
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (key.contains("(秒)")) {
                    val = Integer.parseInt(value);
                }
            }
            if (val > 0 && !IsForcedEnd) {
                ThreadDelay(val);
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }

    /**
     * 写PLC主料 一拖2
     *
     * @param data
     */
    private static void Write_PLC_MainIngredients2(HashMap<String, String> data) {
        try {
            //是否手动
            boolean ishand = true;
            ExecuteTheRecipe.showlog("准备倒入主料！");

            //region 判断是否手动
            if (ConfigName.getInstance().versionSelectionEnum.equals("大炒版本")) {
                ishand = true;
            } else {
                for (HashMap.Entry<String, String> entry : data.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    if (key.contains("投料动作")) {
                        if (value.contains("手动投料")) {
                            ishand = true;
                        } else {
                            ishand = false;
                        }
                    }
                }
            }
            //endregion


            if (ishand) {
                String name = "";
                String zl = "";
                int val = 0;
                for (HashMap.Entry<String, String> entry : data.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    if (key.contains("名称")) {
                        name = value;
                    } else if (key.contains("重量")) {
                        zl = value;
                    }
                }
                ExecuteTheRecipe.showlog("工序:手动投料," + name + "," + zl);
                String title = "手动投料-温馨提示！";
                String message = "客官请投入主料,[" + name + "]重量" + zl + "g,投入后点击[确定]继续流程！";
                if (ConfigName.getInstance().WhetherManualFeedingSuspended.contains("是")) {
                    ExecuteTheRecipe.WritePLC("暂停开关", true, null);
                }
                ModbusTcpServer.get().WriteBool("M52.1", (boolean) true, null);
                long startTime = System.currentTimeMillis(); //起始时间
                if(NoticeHandSuspension!=null){NoticeHandSuspension.Run(true);}

                final boolean[] IsComplete = {false};
                Activity activity = findActivity(context);
                if (activity != null) {
                    activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            try {

                                new QMUIDialog.MessageDialogBuilder(context).setCancelable(false).setCanceledOnTouchOutside(false).setTitle(title).setMessage(message).addAction("确定", new QMUIDialogAction.ActionListener() {
                                    @Override
                                    public void onClick(QMUIDialog dialog, int index) {
                                        IsComplete[0] = true;
                                        dialog.dismiss();
                                    }
                                }).create(com.qmuiteam.qmui.R.style.QMUI_Dialog).show();

                            } catch (Exception e) {

                            }
                        }
                    });
                }

                while (!IsComplete[0]) {
                    Thread.sleep(100);//10 *6
                }

                if (ConfigName.getInstance().WhetherManualFeedingSuspended.contains("是")) {
                    ExecuteTheRecipe.WritePLC("暂停开关", false, null);
                }
                ModbusTcpServer.get().WriteBool("M52.1", (boolean) false, null);
                long endTime = System.currentTimeMillis(); //结束时间
                int time = (int) ((endTime - startTime) / 1000);
                HandTime=HandTime+time;
                if(NoticeHandSuspension!=null){NoticeHandSuspension.Run(false);}

                ExecuteTheRecipe.showlog("确定完成,继续制作！");
            } else {
                //自动投料
                String writeValue = "1号位";
                if (ExecuteCurrentOperation != null) {
                    ExecuteCurrentOperation.Run("主料" + "|" + writeValue);
                }

                WriteMainPLC("机器人投放主料完成", false, null);
                WriteMainPLC("炒锅请求投主料", true, null);
                boolean isJre = false;
                Object K = ReadPLC("加热");
                isJre = K == null ? false : (boolean) K;
                if (isJre) {
                    ExecuteTheRecipe.WritePLC("加热", false, null);
                }//提前关闭加热

                final boolean[] IsComplete = {false};
                long a = System.currentTimeMillis();
                while (!IsComplete[0] && !IsForcedEnd) {
                    if ((System.currentTimeMillis() - a) > 1000 * (whileTime * 10)) {
                        break;
                    } else {
                        Object sb = ReadMainPLC("机器人投放主料完成");//ListeningValue.get(name);
                        if (sb != null) {
                            IsComplete[0] = (boolean) (sb);
                        }
                    }
                    Thread.sleep(100);//10 *6
                }
                WriteMainPLC("机器人投放主料完成", false, null);
                if (isJre) {
                    ExecuteTheRecipe.WritePLC("加热", true, null);
                }//再次释放加热
            }


            if (IsMoveYiHaoWei()) {
                WriteMainPLC("炒锅投主料完成", true, null);
            }

            //判断炒制位置
            String czwz = "炒菜位1";
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (key.contains("炒制位置")) {
                    czwz = value;
                }
            }
            Make位置(czwz);

            //判断是否有烹饪时间
            int val = 0;
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (key.contains("(秒)")) {
                    val = Integer.parseInt(value);
                }
            }
            if (val > 0 && !IsForcedEnd) {
                ThreadDelay(val);
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }

    /**
     * 写PLC投辅料
     *
     * @param data
     */
    private static void Write_PLC_MainAccessory(HashMap<String, String> data) {
        try {
            int val = 0;
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (key.contains("(秒)")) {
                    val = Integer.parseInt(value);
                }
            }

            if (ExecuteCurrentOperation != null) {
                ExecuteCurrentOperation.Run("辅料" + "|" + val);
            }
            WriteMainPLC("机器人放辅料完成", false, null);
            WriteMainPLC("炒锅请求投辅料", true, null);


            boolean isJre = false;
            Object K = ReadPLC("加热");
            isJre = K == null ? false : (boolean) K;
            if (isJre) {
                ExecuteTheRecipe.WritePLC("加热", false, null);
            }//提前关闭加热

            final boolean[] IsComplete = {false};
            long a = System.currentTimeMillis();
            while (!IsComplete[0] && !IsForcedEnd) {
                if ((System.currentTimeMillis() - a) > 1000 * (whileTime * 10)) {
                    break;
                } else {
                    Object sb = ReadMainPLC("机器人放辅料完成");//ListeningValue.get(name);
                    if (sb != null) {
                        IsComplete[0] = (boolean) (sb);
                    }
                }
                Thread.sleep(100);//10 *6
            }
            WriteMainPLC("机器人放辅料完成", false, null);
            if (isJre) {
                ExecuteTheRecipe.WritePLC("加热", true, null);
            }//再次释放加热

            //判断炒制位置
            String czwz = "炒菜位1";
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (key.contains("炒制位置")) {
                    czwz = value;
                }
            }
            Make位置(czwz);

            if (val > 0 && !IsForcedEnd) {
                ThreadDelay(val);
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }

    /**
     * 写PLC 出菜
     *
     * @param data
     */
    private static void Write_PLC_MainOutdishes(HashMap<String, String> data) {
        try {
            ExecuteTheRecipe.showlog("准备出菜！");
            //先延迟
            for (HashMap.Entry<String, String> entry : data.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                ToastUtils.info("工序:" + key + "," + value);
                if (key.contains("(秒)")) {
                    int val = Integer.parseInt(value);
                    if (all_list.size() > 0) {
                        ThreadDelay(val);
                    }
                }
            }
            ExecuteTheRecipe.WritePLC("加热", false, null);

            WriteMainPLC("炒锅出餐完成", false, null);
            WriteMainPLC("机器人到达炒锅出餐位", false, null);
            WriteMainPLC("炒菜完成请求出餐", true, null);
            //等待机器人就位
            final boolean[] IsComplete = {false};
            long a = System.currentTimeMillis();
            while (!IsComplete[0] && !IsForcedEnd) {
                if ((System.currentTimeMillis() - a) > 1000 * (whileTime * 10)) {
                    break;
                } else {
                    Object sb = ReadMainPLC("机器人到达炒锅出餐位");//ListeningValue.get(name);
                    if (sb != null) {
                        IsComplete[0] = (boolean) (sb);
                    }
                }
                Thread.sleep(100);//10 *6
            }
            WriteMainPLC("机器人到达炒锅出餐位", false, null);
            WriteMainPLC("炒锅出餐减速到位", false, null);

            BottomClick1("出菜");

            //一直等待机器移动到该位置，否则就一直等待 6s超时
            String name = "出餐启动反馈";
            IsComplete[0] = false;
            a = System.currentTimeMillis();
            while (!IsComplete[0] && !IsForcedEnd) {
                if ((System.currentTimeMillis() - a) > 1000 * (whileTime * 3)) {
                    break;
                } else {
                    Object sb = ReadPLC(name);//ListeningValue.get(name);
                    if (sb != null) {
                        IsComplete[0] = (boolean) (sb);
                    }
                    Object jsw = ReadPLC("炒锅倒菜减速位");//ListeningValue.get(name);
                    if (jsw != null) {
                        WriteMainPLC("炒锅出餐减速到位", (Boolean) jsw, null);
                    }
                }
                Thread.sleep(100);//10 *6
            }
            WriteMainPLC("炒锅出餐完成", true, null);
            ExecuteTheRecipe.showlog("出菜完成,锅体准备回到原位！");
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }
    //endregion

    //region 判断当前工序后是否还有 主料  不包含 手动配料

    /**
     * 是否还有 主料  不包含 手动配料  如果没有主料的话 那么就是对的
     *
     * @return
     */
    public static boolean IsMoveYiHaoWei() {
        boolean IsMove = false;
        try {
            int k = 0;
            ArrayList<BPA_GOODSRECIPE> kkkkkk = new ArrayList<>();
            for (BPA_GOODSRECIPE item : all_list) {
                if (k > Index_select) //查找当前工序 后的步骤 所有主料
                {
                    if (item.processname.contains("主料") && !item.processvalue.contains("手动投料"))// &&
                    {
                        kkkkkk.add(item);
                    }
                }
                k++;
            }


            if (kkkkkk.size() <= 0 && all_list.size() > 0) {
                IsMove = true;
            }

        } catch (Exception ex) {

        } finally {
            return IsMove;
        }
    }
    //endregion

    //region 主页按钮

    /**
     * 点击摇欠按钮
     *
     * @param data
     */
    public static void Write_PLC_YaoQian(MyStatus data) {
        try {
            if (data == MyStatus.Start) {
                ToastUtils.info("点击摇浅按钮");

            } else if (data == MyStatus.Stop) {
                ToastUtils.info("点击停摇按钮");
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }

    /**
     * 火力点击
     *
     * @param data
     */
    public static void Write_PLC_HuoLI(int data) {
        try {
            WritePLC("加热功率", data, new IWriteCallBack() {
                @Override
                public void onSuccess() {
                    if (data == 0) {
                        ConfigName.getInstance().IsOpenHuoLi = false;
                        WritePLC("加热", false, null);
                    } else {
                        ConfigName.getInstance().IsOpenHuoLi = true;
                        WritePLC("加热", true, null);
                    }
                }

                @Override
                public void onFailure(String ErrorMsg) {
                }
            });
            ToastUtils.info("火力按钮点击,当前级别：" + data);

        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        }
    }
    //endregion

    //region PLC监听线程

    /**
     * 自提设备监听
     */
    public static void Listening() {

        ConfigName.getInstance().PLC_Address.clear();
        ArrayList<BPA_PLCADDRESS> address = QueryDB.GetPlcaddressALL();
        for (BPA_PLCADDRESS item : address) {
            if (!item.address.isEmpty() && !item.address.equals("-------------")) {
                ConfigName.getInstance().PLC_Address.put(item.name, item);
            }
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    WritePLC("初始化", true, null);
                    Thread.sleep(500);
                    WritePLC("初始化", false, null);

                    ExecuteTheRecipe.WritePLC("温控开关", false, null);//开关闭合
                    ExecuteTheRecipe.WritePLC("暂停开关", false, null);//开关闭合

                    ExecuteTheRecipe.WritePLC("校准时间", 50, null);//默认校准时间5秒
                    ExecuteTheRecipe.WritePLC("料仓1校准开关", false, null);//默认校准时间5秒
                    ExecuteTheRecipe.WritePLC("料仓2校准开关", false, null);//默认校准时间5秒
                    ExecuteTheRecipe.WritePLC("料仓3校准开关", false, null);//默认校准时间5秒

                    ModbusTcpServer.get().WriteBool("M52.1", (boolean) false, null);
                    //读取版本号
                    ModbusTcpServer.get().ReadInt("VD1100", 1, val -> {
                        PlcVersion= String.valueOf(val[0]+"");
                        if(NotifyVersionNumUpdates!=null)
                        {
                            NotifyVersionNumUpdates.Run();
                        }
                    });

                } catch (InterruptedException e) {
                    ToastUtils.info("异常信息:" + e.getMessage());
                }
            }
        }).start();

        ThreadManager.Get().StartLong("PLC设备数据监听", true, new IThread() {
            @Override
            public void Run() throws InterruptedException {
                try {
                    for (String item : ConfigName.getInstance().PLC_Address.keySet()) {
                        String key = item;
                        BPA_PLCADDRESS plcaddress = ConfigName.getInstance().PLC_Address.get(item);
                        if (plcaddress.isread == 1) {
                            Object val = ReadPLC(key);
                            ListeningValue.put(key, val);
                        }
                    }

                    if (ConfigName.getInstance().PlcIsConnect) {
                        TempControl();
                        ReadPLCStatus();

                    }

                } catch (Exception ex) {
                    ToastUtils.error("异常信息:" + ex.getMessage());
                }
                Thread.sleep(100);
            }

            @Override
            public void RunComplete() throws InterruptedException {

            }
        });

        ThreadManager.Get().StartLong("PLC设备-心跳", true, new IThread() {
            @Override
            public void Run() throws InterruptedException {
                try {
                    if (ConfigName.getInstance().PlcIsConnect) {
                        //心跳
                        WritePLC("心跳位", 0, null);
                        Log.e("心跳", "心跳: ");
                        //Log.e("心跳", "心跳: "+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));

                    }

                } catch (Exception ex) {
                    ToastUtils.error("异常信息:" + ex.getMessage());
                }
                Thread.sleep(2000);
            }

            @Override
            public void RunComplete() throws InterruptedException {

            }
        });
    }

    /**
     * 主控设备监听
     */
    public static void MainListening() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (String item : ConfigName.getInstance().MainPlcAddress.keySet()) {
                    if (!item.equals("商品信息")) {
                        WriteMainPLC(item, false, null);
                    }
                }
            }
        }).start();

        ThreadManager.Get().StartLong("主控PLC设备-心跳", true, new IThread() {
            @Override
            public void Run() throws InterruptedException {
                try {
                    if (ConfigName.getInstance().PlcMainIsConnect) {
                        //心跳
                        ReadPLCMainStatus();
                        WriteMainPLC("心跳", false, null);
                        WriteMainPLC("炒锅空闲状态", ConfigName.getInstance().WokStatus, null);
                        WriteMainPLC("投料机构状态", ConfigName.getInstance().TouLiaoStatus, null);
                        Log.e("炒锅状态", "炒锅状态: " + ConfigName.getInstance().WokStatus);
                        Log.e("投料机构状态", "投料机构状态: " + ConfigName.getInstance().TouLiaoStatus);
                        //读取主控下发的商品
                        ReadMasterDeliveryGoods();
                    }
                } catch (Exception ex) {
                    ToastUtils.error("异常信息:" + ex.getMessage());
                }
                Thread.sleep(2000);
            }

            @Override
            public void RunComplete() throws InterruptedException {

            }
        });
    }
    //endregion

    //region PLC基础控制类

    /**
     * 写PLC数据
     *
     * @param name
     * @param value
     */
    public static void WritePLC(String name, Object value, IWriteCallBack callback) {
        try {
            if (ConfigName.getInstance().PLC_Address.containsKey(name)) {
                BPA_PLCADDRESS plcaddress = ConfigName.getInstance().PLC_Address.get(name);
                if (!plcaddress.address.isEmpty() && ConfigName.getInstance().PlcIsConnect) {
                    if (plcaddress.address.toUpperCase().startsWith("VD"))//int
                    {
                        ModbusTcpServer.get().WriteInt(plcaddress.address, (int) value, callback);
                    } else if (plcaddress.address.toUpperCase().startsWith("M"))//bool
                    {
                        ModbusTcpServer.get().WriteBool(plcaddress.address, (boolean) value, callback);
                    } else if (plcaddress.address.toUpperCase().startsWith("VW"))//short
                    {
                        ModbusTcpServer.get().WriteShort(plcaddress.address, Short.parseShort(value.toString()), callback);
                    } else if (plcaddress.address.toUpperCase().startsWith("VR"))//float
                    {
                        ModbusTcpServer.get().WriteFloat(plcaddress.address, Float.parseFloat(value.toString()), callback);
                    }
                }
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        } finally {

        }
    }

    /**
     * 读PLC数据
     *
     * @param name
     * @return
     */
    public static Object ReadPLC(String name) {
        final Object[] ReturnsVariable = {null};
        try {
            if (ConfigName.getInstance().PLC_Address.containsKey(name)) {
                BPA_PLCADDRESS plcaddress = ConfigName.getInstance().PLC_Address.get(name);
                if (!plcaddress.address.isEmpty() && ConfigName.getInstance().PlcIsConnect) {
                    if (plcaddress.address.toUpperCase().startsWith("VD"))//int
                    {
                        ModbusTcpServer.get().ReadInt(plcaddress.address, 1, ints -> {
                            ReturnsVariable[0] = ints[0];
                        });
                    } else if (plcaddress.address.toUpperCase().startsWith("M"))//bool
                    {
                        ModbusTcpServer.get().ReadBool(plcaddress.address, 1, val -> {
                            ReturnsVariable[0] = val[0];
                        });
                    } else if (plcaddress.address.toUpperCase().startsWith("VW"))//short
                    {
                        ModbusTcpServer.get().ReadShort(plcaddress.address, 1, val -> {
                            ReturnsVariable[0] = val[0];
                        });
                    }else if (plcaddress.address.toUpperCase().startsWith("VR"))//float
                    {
                        ModbusTcpServer.get().ReadFloat(plcaddress.address, 1, val -> {
                            ReturnsVariable[0] = val[0];
                        });
                    }
                }
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        } finally {
            return ReturnsVariable[0];
        }
    }

    /**
     * 写主控PLC数据
     *
     * @param name
     * @param value
     */
    public static void WriteMainPLC(String name, boolean value, IWriteCallBack callback) {
        try {
            if (ConfigName.getInstance().MainPlcAddress.containsKey(name)) {
                Integer plcaddress = ConfigName.getInstance().MainPlcAddress.get(name) + (ConfigName.getInstance().DeviceHao - 1) * 100;
                if (ConfigName.getInstance().PlcMainIsConnect) {
                    ModbusTcpMainServer.get().WriteBool(String.valueOf(plcaddress), value, callback);
                }
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        } finally {
        }
    }

    /**
     * 读主控PLC数据
     *
     * @param name
     * @return
     */
    public static Object ReadMainPLC(String name) {
        final Object[] ReturnsVariable = {null};
        try {
            if (ConfigName.getInstance().MainPlcAddress.containsKey(name)) {
                if (!name.equals("商品信息")) {
                    Integer plcaddress = ConfigName.getInstance().MainPlcAddress.get(name) + (ConfigName.getInstance().DeviceHao - 1) * 100;
                    if (ConfigName.getInstance().PlcMainIsConnect) {
                        ModbusTcpMainServer.get().ReadBool(String.valueOf(plcaddress), 1, val -> {
                            ReturnsVariable[0] = val[0];
                        });
                    }
                } else {
                    Integer plcaddress = ConfigName.getInstance().MainPlcAddress.get(name) + (ConfigName.getInstance().DeviceHao - 1) * 20;
                    if (ConfigName.getInstance().PlcMainIsConnect) {
                        ModbusTcpMainServer.get().ReadString(String.valueOf(plcaddress), 36, val1 -> {
                            ReturnsVariable[0] = val1;
                        });
                    }
                }
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        } finally {
            return ReturnsVariable[0];
        }
    }

    /**
     * 实时状态
     */
    public static ConcurrentHashMap<Integer, Boolean> IoStatus = new ConcurrentHashMap<Integer, Boolean>();

    /**
     * 获取实时状态
     *
     * @param ch
     * @return
     */
    public static boolean getConcurrentHash(int ch) {
        if (!IoStatus.containsKey(ch)) {
            return false;
        }
        return IoStatus.get(ch);
    }

    /**
     * 获取搅拌电机
     *
     * @param
     * @return
     */
    public static int getConcurrentHash_dj(String name) {
        if (!ListeningValue.containsKey(name)) {
            return 0;
        }
        Object obj = ListeningValue.get(name);
        if (obj == null) {
            return 0;
        } else {
            return (int) obj;
        }
    }

    /**
     * 获取监听变量
     *
     * @param
     * @return
     */
    public static Object getListingValue(String name) {
        if (!ListeningValue.containsKey(name)) {
            return null;
        }
        return ListeningValue.get(name);
    }

    /**
     * 读取状态
     */
    public static void ReadPLCStatus() {
        try {
            if (ConfigName.getInstance().PlcIsConnect) {
                ModbusTcpServer.get().ReadStatus("VW354", 1, data -> {
                    for (int i = 0; i < data.length; i++) {
                        byte status = data[i];//0x92
                        IoStatus.put(i * 8 + 0, ByteHelper.getBit(status, 0) == 1);
                        IoStatus.put(i * 8 + 1, ByteHelper.getBit(status, 1) == 1);
                        IoStatus.put(i * 8 + 2, ByteHelper.getBit(status, 2) == 1);
                        IoStatus.put(i * 8 + 3, ByteHelper.getBit(status, 3) == 1);
                        IoStatus.put(i * 8 + 4, ByteHelper.getBit(status, 4) == 1);
                        IoStatus.put(i * 8 + 5, ByteHelper.getBit(status, 5) == 1);
                        IoStatus.put(i * 8 + 6, ByteHelper.getBit(status, 6) == 1);
                        IoStatus.put(i * 8 + 7, ByteHelper.getBit(status, 7) == 1);
                    }
                });
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        } finally {
        }
    }

    /**
     * 反馈主控制台状态
     */
    public static void ReadPLCMainStatus() {
        try {
            if (ConfigName.getInstance().PlcIsConnect) {
                Object obj1 = ReadPLC("翻转轴1允许机器人放盒取盒");
                Object obj2 = ReadPLC("翻转轴2允许机器人放盒取盒");
                boolean ob1 = obj1 == null ? false : (boolean) obj1;
                boolean ob2 = obj2 == null ? false : (boolean) obj2;
                ConfigName.getInstance().TouLiaoStatus = ob1 && ob2;

                Object obj3 = ReadPLC("初始化完成");
                boolean ob3 = obj3 == null ? false : (boolean) obj3;
                ConfigName.getInstance().WokStatus = ob3 && !ExecuteTheRecipe.IsStart;
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        } finally {
        }
    }

    /**
     * 温控
     */
    public static void TempControl() {
        boolean TempBool = false;
        Object val_wd = ExecuteTheRecipe.getListingValue("当前锅底温度");
        int dq_wd = val_wd == null ? 0 : (int) val_wd;//当前锅底温度
        if (dq_wd >= (ConfigName.getInstance().MaxTemp - 5)) //如果当前温度大于最大温度限制  断开
        {
            TempBool = true;//设置断开
        } else if (dq_wd <= (ConfigName.getInstance().MaxTemp - 20))//需要闭合
        {
            TempBool = false;//闭合
        }

        Object tempkg = ExecuteTheRecipe.ReadPLC("温控开关");
        if (tempkg != null) {
            boolean kg = (boolean) tempkg;
            if (TempBool) //设置断开
            {
                if (kg == false) {
                    ExecuteTheRecipe.WritePLC("温控开关", true, null);//断开
                }
            } else //设置闭合
            {
                if (kg) {
                    ExecuteTheRecipe.WritePLC("温控开关", false, null);//闭合
                }
            }
        }
    }

    /**
     * 读取主控下发的商品
     */
    public static void ReadMasterDeliveryGoods() {
        Object Ismake = ReadMainPLC("商品下发");
        if (Ismake != null) {
            if ((boolean) Ismake) //信息来了,是否需要制作
            {
                WriteMainPLC("商品下发", false, null);
                Object obj = ReadMainPLC("商品信息");
                String id = obj == null ? "--------" : (String) obj;

                BPA_GOODS goods = QueryDB.GetGoodsId(id);
                if (goods == null) {
                    WriteMainPLC("商品数据验证", false, null);
                } else {
                    Object chushiover = ExecuteTheRecipe.getListingValue("初始化完成");
                    if (!ConfigName.getInstance().PlcIsConnect) {
                        ToastUtils.warning("PLC未准备就绪!!!");
                        WriteMainPLC("商品数据验证", false, null);
                    } else if (chushiover == null || !(boolean) chushiover) {
                        ToastUtils.warning("设备未初始化,请先手动初始化设备!!!");
                        WriteMainPLC("商品数据验证", false, null);
                    } else if (ExecuteTheRecipe.IsStart) {
                        ToastUtils.warning("请耐心等待商品制作结束!!!");
                        WriteMainPLC("商品数据验证", false, null);
                    } else {
                        WriteMainPLC("机器人准备就绪", false, null);
                        WriteMainPLC("商品数据验证", true, null);
                        boolean IsLaoVis = ConfigName.getInstance().user.name.equals("admin") || ConfigName.getInstance().user.account.equals("admin") || ConfigName.getInstance().user.userID.equals("超级管理员");
                        if (IsLaoVis) {
                            DataBus.getInstance().mListener.clickListener(null, goods);
                        } else {
                            MessageManager.getInstance().sendMessage(MessageName.OpenMakeGoodFrom, goods.id);
                        }
                        boolean issucess = false;
                        try {
                            final boolean[] IsComplete = {false};
                            long a = System.currentTimeMillis();
                            while (!IsComplete[0]) {
                                if ((System.currentTimeMillis() - a) > 1000 * (whileTime * 5)) {
                                    break;
                                } else {
                                    WriteMainPLC("投料机构状态", ConfigName.getInstance().TouLiaoStatus, null);
                                    Object sb = ReadMainPLC("机器人准备就绪");
                                    if (sb != null) {
                                        IsComplete[0] = (boolean) (sb);
                                        issucess = (boolean) (sb);
                                    }
                                }
                                Thread.sleep(100);//10 *6
                            }
                            WriteMainPLC("机器人准备就绪", false, null);
                        } catch (Exception e) {
                        }

                        if (issucess) {
                            if (IsLaoVis) {
                                MessageManager.getInstance().sendMessage(MessageName.IsStratMakeGood1, goods.id);
                            } else {
                                MessageManager.getInstance().sendMessage(MessageName.IsStratMakeGood, goods.id);
                            }
                        }
                    }
                }
            }
        }

        //机器人急停，制作订单 应该暂停

        //强制结束任务
        Object IsStop = ReadMainPLC("强制结束任务");
        if (IsStop != null) {
            if ((boolean) IsStop) {
                WriteMainPLC("强制结束任务", false, null);//复位

                ExecuteTheRecipe.IsPause = false;
                ExecuteTheRecipe.WritePLC("暂停开关", false, null);
                ExecuteTheRecipe.SetForcedEnd();//设置强制结束
            }
        }

//        Object IsJT = ReadMainPLC("机器人急停");
//        if (IsJT != null) {
//            if ((boolean) IsJT)//异常情况
//            {
//                //WritePLC("停止",true,null);
//            }
//        }
    }
    //endregion

    //region 获取基础挡位变量

    /**
     * 执行位置
     *
     * @param name
     */
    public static void Make位置(String name) {
        ExecuteOperationSteps(Get位置("高速", name).processname, Get位置("高速", name).processvalue);
    }

    /**
     * 获取位置
     *
     * @param sd
     * @return
     */
    public static BPA_GOODSRECIPE Get位置(String sd, String name) {
        BPA_GOODSRECIPE pf = new BPA_GOODSRECIPE();
        pf.materialType = 1;
        pf.processname = "位置";
        pf.processms = "位置(" + sd + "," + name + ",0)";
        pf.processvalue = "转动速度," + sd + "|位置动作," + name + "|延迟(秒),0";
        return pf;
    }

    /**
     * 获取挡位变量
     *
     * @param name
     * @param value
     * @return
     */
    public static int GetMXValue(String name, String value) {
        final int[] ReturnsVariable = {0};
        try {
            if (name.contains("速度")) {
                ReturnsVariable[0] = ConfigName.getInstance().StirringSpeed.get(value);
            } else if (name.contains("功率")) {
                ReturnsVariable[0] = ConfigName.getInstance().HeatingGear.get(value);
                int max = ConfigName.getInstance().HeatingGear.get(ConfigName.getInstance().HuoLi);
                if (ReturnsVariable[0] > max) {
                    ReturnsVariable[0] = max;
                }
            }
        } catch (Exception ex) {
            ToastUtils.error("异常信息:" + ex.getMessage());
        } finally {
            return ReturnsVariable[0];
        }
    }
    //endregion

    //region 延迟函数

    /**
     * 线程延迟函数(避免线程阻塞等待)
     *
     * @param delay
     */
    public static void ThreadDelay(int delay) {
        ExecuteTheRecipe.showlog("工序线程等待-------时长：" + delay + "秒,请耐心等待，开始计时！");
        int AtPresentTime=delay;
        if (NoticeAtPresentTime!=null){NoticeAtPresentTime.Run(AtPresentTime);}
        long startTime = System.currentTimeMillis();// && ConfigName.getInstance().PlcIsConnect
        while ((System.currentTimeMillis() - startTime) <= (delay * 1000) && !IsForcedEnd && ConfigName.getInstance().PlcIsConnect)
        {
            try {
                Thread.sleep(100);
                int mmmm=delay- (int) ((System.currentTimeMillis() - startTime)/1000);
                if (AtPresentTime!=mmmm)
                {
                    AtPresentTime=mmmm;
                    if (NoticeAtPresentTime!=null){NoticeAtPresentTime.Run(mmmm);}
                }
            } catch (InterruptedException ex) {
            }
        }
        AtPresentTime=0;
        if (NoticeAtPresentTime!=null){NoticeAtPresentTime.Run(AtPresentTime);}
        long endTime = System.currentTimeMillis(); //结束时间
        int time = (int) ((endTime - startTime) / 1000);
        ExecuteTheRecipe.showlog("工序线程等待结束-------总耗时：" + time);
    }
    /**
     * 线程等待
     *
     * @param name
     */
    public static void ThreadWhile_WL(String name,int time) {
        //"炒菜位1反馈";
        int AtPresentTime=time;
        if (NoticeAtPresentTime!=null){NoticeAtPresentTime.Run(AtPresentTime);}
        final boolean[] IsComplete = {false};
        long a = System.currentTimeMillis();
        ExecuteTheRecipe.showlog(name + ",等待中");
        while (!IsComplete[0] && !IsForcedEnd && ConfigName.getInstance().PlcIsConnect) {
            if ((System.currentTimeMillis() - a) > 1000 * whileTime) {
                ExecuteTheRecipe.showlog(name + ",异常超时退出!");
                break;
            } else {
                Object sb = ReadPLC(name);
                if (sb != null) {
                    IsComplete[0] = (boolean) (sb);
                    if(IsComplete[0])
                    {
                        ExecuteTheRecipe.showlog(name + ",接收到信号!");
                    }
                }
            }
            try {
                int mmmm=time- (int) ((System.currentTimeMillis() - a)/1000);
                if (AtPresentTime!=mmmm)
                {
                    AtPresentTime=mmmm;
                    if (NoticeAtPresentTime!=null){NoticeAtPresentTime.Run(mmmm);}
                }

                Thread.sleep(100);//10 *6
            } catch (InterruptedException e) {
                IsComplete[0] = true;
                ExecuteTheRecipe.showlog(name + ",异常退出!" + e.getMessage());
            }
        }
        if (NoticeAtPresentTime!=null){NoticeAtPresentTime.Run(0);}
        ExecuteTheRecipe.showlog(name + ",等待结束!");
    }
    /**
     * 线程等待
     *
     * @param name
     */
    public static void ThreadWhile(String name) {
        //"炒菜位1反馈";
        final boolean[] IsComplete = {false};
        long a = System.currentTimeMillis();
        ExecuteTheRecipe.showlog(name + ",等待中");
        while (!IsComplete[0] && !IsForcedEnd && ConfigName.getInstance().PlcIsConnect) {
            if ((System.currentTimeMillis() - a) > 1000 * whileTime) {
                ExecuteTheRecipe.showlog(name + ",异常超时退出!");
                break;
            } else {
                Object sb = ReadPLC(name);
                if (sb != null) {
                    IsComplete[0] = (boolean) (sb);
                    if(IsComplete[0])
                    {
                        ExecuteTheRecipe.showlog(name + ",接收到信号!");
                    }
                }
            }
            try {
                Thread.sleep(100);//10 *6
            } catch (InterruptedException e) {
                IsComplete[0] = true;
                ExecuteTheRecipe.showlog(name + ",异常退出!" + e.getMessage());
            }
        }
        ExecuteTheRecipe.showlog(name + ",等待结束!");
    }

    /**
     * 线程等待
     *
     * @param name
     */
    public static void ThreadWhile3(String name, int k) {
        //"炒菜位1反馈";
        int time=name.contains("清洗")?ConfigName.getInstance().AutoQXTime:ConfigName.getInstance().AutoCCTime;
        int AtPresentTime=time;
        if (NoticeAtPresentTime!=null){NoticeAtPresentTime.Run(AtPresentTime);}

        final boolean[] IsComplete = {false};
        long a = System.currentTimeMillis();
        ExecuteTheRecipe.showlog(name + ",等待中");
        while (!IsComplete[0] && !IsForcedEnd && ConfigName.getInstance().PlcIsConnect) {
            if ((System.currentTimeMillis() - a) > 1000 * whileTime * k) {
                ExecuteTheRecipe.showlog(name + ",异常超时退出!");
                break;
            } else {
                Object sb = ReadPLC(name);//ListeningValue.get(name);
                if (sb != null) {
                    IsComplete[0] = (boolean) (sb);
                    if(IsComplete[0])
                    {
                        ExecuteTheRecipe.showlog(name + ",接收到信号!");
                    }
                }
            }
            try {
                int mmmm=time- (int) ((System.currentTimeMillis() - a)/1000);
                if (AtPresentTime!=mmmm)
                {
                    AtPresentTime=mmmm;
                    if (NoticeAtPresentTime!=null){NoticeAtPresentTime.Run(mmmm);}
                }
                Thread.sleep(100);//10 *6
            } catch (InterruptedException e) {
                IsComplete[0] = true;
                ExecuteTheRecipe.showlog(name + ",异常退出!" + e.getMessage());
            }
        }
        int xhtime= (int) ((System.currentTimeMillis() - a)/1000);
        if(name.contains("清洗"))
        {
            ConfigName.getInstance().AutoQXTime=xhtime;
        }else
        {
            ConfigName.getInstance().AutoCCTime=xhtime;
        }

        Activity activity = findActivity(context);
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                ConfigData.getInstance().SavePZ();
            }
        });

        if (NoticeAtPresentTime!=null){NoticeAtPresentTime.Run(0);}
        ExecuteTheRecipe.showlog(name + ",等待结束!");
    }
    //endregion

    //region 显示日志

    /**
     * 显示日志
     */
    public static void showlog(String msg) {
        Log.e("hbl", msg);

        ToastUtils.info(msg);
    }
    //endregion
}
