package com.gyee.alarm.rule;


import com.gyee.alarm.model.vo.DeviceTypeValue;
import com.gyee.alarm.rule.expression.AlarmExpression;
import com.gyee.alarm.util.realtimesource.timeseries.DoubleTsData;
import com.gyee.alarm.util.realtimesource.timeseries.TsDataType;
import com.gyee.common.model.PointData;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;
import java.util.LinkedList;


// 取测点在给定的时间范围内数据上升的量是否超过阈值
// 应用场景： 判断温升，测点值的上升速度过快等
// 函数原型： RiseExceed（测点名，时间（秒），阈值）
@Data
@NoArgsConstructor
public class AlarmFunctionRiseExceed extends AlarmFunction {

    private DoubleTsData lastUpdateTsData;
    //private DoubleTsData minTsData;
    //数据缓存
    private LinkedList<DoubleTsData> tsDataQueue = new LinkedList<DoubleTsData>();
    private long interval; //时间范围，单位秒
    private double threshold; //阈值


    public AlarmFunctionRiseExceed(AlarmExpression alarmExpression, DeviceTypeValue tType, String tId) {
        super(alarmExpression, tType, tId);
        String exp = alarmExpression.getExpression();
        exp = exp.substring(11, exp.length() - 1);
        String[] arr = exp.split(",");
        interval = Long.valueOf(arr[1]);
        threshold = Double.valueOf(arr[2]);
    }

    @Override
    public Object explain() {
        if (this.getAlarmExpression().getVarList() == null || this.getAlarmExpression().getVarList().size() < 1)
            return false;
        String varName = this.getAlarmExpression().getVarList().get(0);
        DoubleTsData tsData = getValue(varName);
        if (tsData == null)
            return false;
        if (lastUpdateTsData == null) {
            lastUpdateTsData = tsData;
            tsDataQueue.offer(tsData);
            return false;
        }

        //如果数据时间戳在变化，最新数据时间作为基准时间
        //否则，认为数据已不更新，取系统时间和最新数据时间较大者为基准时间
        long ts = new Date().getTime();
        if (tsData.getTs() > lastUpdateTsData.getTs())
            ts = tsData.getTs();
        else if (tsData.getTs() > ts)
            ts = tsData.getTs();


        DoubleTsData minTsData = tsDataQueue.peek();

        while (ts - minTsData.getTs() > interval * 1000 &&
                tsDataQueue.size() > 0) {
            minTsData = tsDataQueue.poll();
        }
        tsDataQueue.offer(tsData);
        for (int i = 0; i < tsDataQueue.size(); i++) {
            if (minTsData.getDoubleValue() >= tsDataQueue.get(i).getDoubleValue()) {
                minTsData = tsDataQueue.get(i);
            }
        }

        while (tsDataQueue.size() > 0 &&
                tsDataQueue.peek().getTs() < minTsData.getTs()) {
            tsDataQueue.poll();
        }

        lastUpdateTsData = tsData;
        if (tsData.getDoubleValue() - minTsData.getDoubleValue() > threshold) {
            return true;
        }
        return false;
    }


    public DoubleTsData getValue(String varName) {
        PointData tagInfo = this.getTagInfo(varName);

        return new DoubleTsData(tagInfo.getPointTime(), (short) 0, tagInfo.getPointValueInDouble());

    }
}
