package jtznyj.engineer.service.dataDiagnosticService;

import jtznyj.engineer.service.winform.data.MonitorContext;
import jtznyj.engineer.service.winform.data.MonitorDescription;
import jtznyj.engineer.service.winform.data.RecordHashTable;
import jtznyj.engineer.service.winform.data.SecondState;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import jtznyj.engineer.service.dataDiagnosticService.data.DataDiagnosticParameter;
import jtznyj.engineer.service.dataDiagnosticService.data.DrillState;
import jtznyj.engineer.service.dataDiagnosticService.data.DrillStateResult;
import jtznyj.engineer.service.winform.data.mcp_.SecValue;

import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;

/**
 * 趋势诊断分析类
 *
 * @param
 */
@Slf4j
public abstract class WellTrendDataDiagnostic extends TrendDataDiagnostic<RecordHashTable, MonitorDescription, DataDiagnosticParameter> {
    /**
     * 趋势数据
     */
    protected List<TimeValuePair<Hashtable>> trendDataList = new ArrayList<>();

    protected SecondState _secondState;

    /**
     * double空值时，数据库填充的值
     */
    public static final double DOUBLE_NULL_VALUE = -999.25;


    /**
     * 添加时间线数据(确保添加的数据都在监控时间区间)
     *
     * @param record
     */
    protected void tryAddTimeValue(Hashtable record) {
        if (record != null) {
            //确保监控数据都在监控时间范围之内
            Date dt = (Date) record.get(MonitorContext.fieldTime);
            if (this.param._monitorTime > 0) {
                if (this.trendDataList.size() > 0) {
                    //时差
                    TimeValuePair<Hashtable> back1 = trendDataList.get(this.trendDataList.size() - 1);
                    int totalSeconds = Math.abs((int) ((dt.getTime() - back1.getDateTime().getTime()) / 1000));
                    if (totalSeconds > this.param._monitorTime) {
                        //超过了监控时间范围
                        this.trendDataList.remove(this.trendDataList.size() - 1);
                    }
                }
            }
            double v = (double) record.get(this.param._originalField);
            if (v != DOUBLE_NULL_VALUE) {
                TimeValuePair tv = new TimeValuePair(dt, v, record);
                this.trendDataList.add(0, tv);
            }
        }
    }

    /**
     * 诊断分析前置判断
     *
     * @param record
     * @param currentPumpState
     * @param drillState
     * @param lastPumpRunTime
     * @param lastPumpStopTime
     * @return
     */
    protected DataDiagnosticAnalyzeResult beforeAnalyse(Hashtable record, boolean currentPumpState,
                                                        DrillState drillState, Date lastPumpRunTime, Date lastPumpStopTime) {
        double percent = 0.0;
        this._secondState = new SecondState(this.param._name);
        this._secondState.SetAlarm(false);

        DataDiagnosticAnalyzeResult analyseResult = new DataDiagnosticAnalyzeResult();
        analyseResult.description = null;
        analyseResult.result = true;
        analyseResult.percent = percent;
        if (record == null) {
            analyseResult.result = false;
            analyseResult.percent = percent;
            return analyseResult;
        }

        //外部已经间接调用了该方法，无须在调用。
        //this.tryAddTimeValue(record);
        //是否有空值或者是负值的判断
        //当前值
        double v1 = (double) record.get(this.param._originalField);
        if (v1 < 0) {
            analyseResult.result = false;
            analyseResult.percent = percent;
            return analyseResult;
        }
        //前置条件
        if (this.param._preconditions && StringUtils.isNotEmpty(this.param._preconditionsField)) {
            double v = (double) record.get(DataDiagnosticEngineer.getRealFieldName(this.param._preconditionsField));
            if (v < 0) {
                analyseResult.result = false;
                analyseResult.percent = percent;
                return analyseResult;
            }
        }
        Date dtCurrent = (Date) record.get(MonitorContext.fieldTime);
        if (this.param._isPumpRunJump) {   //已开泵
            double sec = Math.abs((dtCurrent.getTime() - lastPumpRunTime.getTime()) / 1000);
            if (sec < (double) this.param._isPumpRunJumpTime) {
                this.reset();
                analyseResult.result = false;
                analyseResult.percent = percent;
                return analyseResult;
            }
        }
        if (this.param._isPumpStopJump) {
            //停泵
            double sec = Math.abs((dtCurrent.getTime() - lastPumpStopTime.getTime()) / 1000);
            if (sec < (double) this.param._isPumpStopJumpTime) {
                this.reset();
                analyseResult.result = false;
                analyseResult.percent = percent;
                return analyseResult;
            }
        }
        if (this.param._pchx) {
            //排除气体
            try {
                boolean bHx;
                if (currentPumpState && drillState == DrillState.Drilling) {
                    //迟到时间
                    int cdsj = 0;
                    try {
                        if (record.get(MonitorContext.fieldCdsj) != null) {
                            cdsj = Integer.parseInt(record.get(MonitorContext.fieldCdsj).toString().trim());
                        }
                    } catch (Exception ex) {
                    }
                    bHx = (Math.abs(dtCurrent.getTime() - lastPumpRunTime.getTime()) / 1000 < (double) ((cdsj + this.param._pchxTime) * 60));
                } else {
                    bHx = true;
                }
                if (bHx) {
                    this.reset();
                    analyseResult.result = false;
                    analyseResult.percent = percent;
                    return analyseResult;
                }
            } catch (Exception ex) {
            }
        }
        if (this.trendDataList.size() == 0) {
            analyseResult.result = false;
            analyseResult.percent = percent;
            return analyseResult;
        }

        //判断是否低于正常值
        TimeValuePair<Hashtable> back1 = this.trendDataList.get(this.trendDataList.size() - 1);
        if (this.trendDataList.size() >= 1 && this.param._continue && back1.getValue() < this.param._continueValue) {
            this.reset();
            //重置所有参数
            analyseResult.result = false;
            analyseResult.resetAllParams = true;
            return analyseResult;
        }
        return analyseResult;
    }

    protected void UpdateLastSecValues(ArrayList<SecValue> secValues, SecValue sv) {
        if (secValues.size() == 0) {
            secValues.add(sv);
        } else {
            int last = secValues.size() - 1;
            if (secValues.get(last)._startTime == sv._startTime) {
                secValues.set(last, sv);
            } else {
                secValues.add(sv);
            }
        }
    }

    /**
     * 井深
     *
     * @param record
     * @return
     */
    public static double getWellDepth(Hashtable record) {
        return (double) record.get(MonitorContext.fieldScjs);
    }

    /**
     * 钻头深度
     *
     * @param record
     * @return
     */
    public static double getDrillDepth(Hashtable record) {
        return (double) record.get(MonitorContext.fieldZtwz);
    }

    /**
     * 单一模型诊断分析
     *
     * @param record
     * @param currentPumpState
     * @param drillState
     * @param lastPumpRunTime
     * @param lastPumpStopTime
     * @return
     */
    protected abstract DataDiagnosticAnalyzeResult internalAnalyse(Hashtable record, boolean currentPumpState,
                                                                   DrillState drillState, Date lastPumpRunTime,
                                                                   Date lastPumpStopTime);

    /**
     * 获得钻机状态信息
     *
     * @return
     */
    public static DrillStateResult GetDrillState(Hashtable _prevDrillStateData, Hashtable record) {
        DrillStateResult result = new DrillStateResult();

        boolean currentIsPumpRun;
        //时间
        //泵冲1(SPM)
        double bc = (double) record.get(MonitorContext.fieldBc1);
        //泵冲2(SPM)
        double bc2 = (double) record.get(MonitorContext.fieldBc2);
        //泵冲3(SPM)
        double bc3 = (double) record.get(MonitorContext.fieldBc3);
        //钻头位置(m)
        double ztwz = (double) record.get(MonitorContext.fieldZtwz);
        //实测井深(M)
        double js = (double) record.get(MonitorContext.fieldScjs);

        //fieldCdsj = "迟到时间";

        //大钩高度(m)
        double dggd = (double) record.get(MonitorContext.fieldDggd);
        //大钩负荷(KN)
        double dgfh = (double) record.get(MonitorContext.fieldDgfh);
        //立压(MPa)
        double ly = (double) record.get(MonitorContext.fieldLy);
        //转速(RPM)
        double zpzs = (double) record.get(MonitorContext.fieldZpzs);

        //fieldZtjc = "Temp5";
        //默认也是没有对应的字段
        double ztjc = 0.0;
        try {
            ztjc = (double) record.get(MonitorContext.fieldZtjc);
        } catch (Exception ex_C0) {
        }
        double bc4 = bc + bc2 + bc3;
        double zqmx = 15.0;
        zqmx *= 9.8;
        double bcmx = 1.0;
        double qxzcd = 27.0;
        //开泵条件
        currentIsPumpRun = (bc > bcmx || bc2 > bcmx || bc3 > bcmx);
        boolean bZpRun = zpzs > 0.001;
        boolean bZtjc = ztjc > 0.001;

        boolean bQxzRange = Math.abs(ztwz - js) < qxzcd;//Math.abs(钻头位置-实测井深)
        DrillState curDrillState;
        if (_prevDrillStateData == null) {
            //默认第一条是停钻状态
            curDrillState = DrillState.Stop;
        } else {
            //上一钻头位置
            double prevZtwz = (double) _prevDrillStateData.get(MonitorContext.fieldZtwz);
            //上一大钩高度
            double prevDggd = (double) _prevDrillStateData.get(MonitorContext.fieldDggd);
            boolean bZj = ztwz - prevZtwz > 0.0;
            boolean bDgDown = prevDggd - dggd > 0.0;
            double dAbsZtwz = Math.abs(ztwz - prevZtwz);
            //判断大钩负荷和zqmx关系
            if (dgfh < zqmx) {
                //钻机状态--卡坐
                curDrillState = DrillState.TakePipe;
                if (currentIsPumpRun) {
                    //如果是开泵状态，则钻机状态处于循环状态
                    curDrillState = DrillState.Circulate;
                }
            } else if (currentIsPumpRun && (bZpRun || bZtjc) && bQxzRange) {
                double subZtjs = ztwz - js;
                if (Math.abs(subZtjs) < 0.1 || bZtjc) {
                    curDrillState = DrillState.Drilling;
                } else {
                    curDrillState = DrillState.ClearHole;
                }
            } else if (dAbsZtwz < 1E-05) {
                if (currentIsPumpRun) {
                    if (bZpRun) {
                        curDrillState = DrillState.ClearHole;
                    } else {
                        curDrillState = DrillState.Circulate;
                    }
                } else if (bDgDown) {
                    curDrillState = DrillState.Trip;
                } else {
                    curDrillState = DrillState.DrillDown;
                }
            } else if (currentIsPumpRun) {
                curDrillState = DrillState.Circulate;
            } else if (ztwz - prevZtwz >= 0.0) {
                curDrillState = DrillState.DrillDown;
            } else {
                curDrillState = DrillState.Trip;
            }
        }
        result.state = curDrillState;
        result.isPumpRun = currentIsPumpRun;
        return result;
    }


    /**
     * 执行诊断
     *
     * @return 诊断分析结果
     */
    @Override
    public DataDiagnosticAnalyzeResult performAnalyze(DrillStateResult drillStateResult) {
        boolean _isPumpRun = true;
        //钻机状态
        DrillState drillState = DrillState.None;
        DataDiagnosticAnalyzeResult analyseResult = null;
        Date _dtPumpRunTime = new Date();
        Date _dtPumpStopTime = new Date();
        //for (Hashtable dataItem : dataList)
        Hashtable currentDataItem = this.data;
        {
            boolean currentIsPumpRun = false;
            //DrillStateResult temp = this.GetDrillState(prevDrillStateData,dataItem);

            drillState = drillStateResult.state;
            //当前是否开泵
            currentIsPumpRun = drillStateResult.isPumpRun;
            if (currentDataItem == null) {
                _dtPumpRunTime = (Date) currentDataItem.get(MonitorContext.fieldTime);
                _dtPumpStopTime = (Date) currentDataItem.get(MonitorContext.fieldTime);
            }
            if (_isPumpRun != currentIsPumpRun) {
                if (currentIsPumpRun) {
                    _dtPumpRunTime = (Date) currentDataItem.get(MonitorContext.fieldTime);
                } else {
                    _dtPumpStopTime = (Date) currentDataItem.get(MonitorContext.fieldTime);
                }
            }
            _isPumpRun = currentIsPumpRun;
            analyseResult = this.internalAnalyse(currentDataItem, _isPumpRun, drillState, _dtPumpRunTime, _dtPumpStopTime);
            if (analyseResult.result) {
                return analyseResult;
            }
        }

        return analyseResult;
    }

    /**
     * 重置
     */
    @Override
    public void reset() {
        super.reset();
        this.trendDataList.clear();
    }

    /**
     * 移动到下一条，为开始下一条数据的诊断分析做准备
     *
     * @return 移动并且准备是否成功， 成功返回true，否则返回 false
     */
    @Override
    public boolean moveNext() {
        if (this.rangeIndex >= this.dataList.size() - 1) {
            return false;
        }
        this.rangeIndex++;
        this.tryAddTimeValue(this.dataList.get(this.rangeIndex));
        return true;
    }

    /**
     * 初始化
     *
     * @return 初始化成功返回true ，失败则返回 false
     */
    @Override
    public boolean init() {
        this.reset();
        if (this.param._monitorTime <= 0 || this.dataList.size() == 0) {
            return true;
        }
        //确保监控数据都在监控时间范围之内
        Hashtable record = dataList.get(this.rangeIndex);
        Date dt;
        int totalSeconds;
        this.tryAddTimeValue(record);
        if (this.param._continuedTime <= 0) {
            return true;
        }
        this.rangeIndex++;
        while (this.rangeIndex < this.dataList.size()) {
            record = dataList.get(this.rangeIndex);
            dt = (Date) record.get(MonitorContext.fieldTime);
            //时差
            if (this.trendDataList.size() > 0) {
                TimeValuePair<Hashtable> back1 = trendDataList.get(this.trendDataList.size() - 1);
                totalSeconds = Math.abs((int) ((dt.getTime() - back1.getDateTime().getTime()) / 1000));
                if (totalSeconds >= this.param._monitorTime) {
                    break;
                }
            }

            this.tryAddTimeValue(record);
            this.rangeIndex++;
        }
        return true;
    }
}
