using FLY.Thick.Blowing.IService;
using FObjBase;
using FObjBase.Reflect;
using Misc;
using SQLite;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FLY.Thick.Blowing.Server.Model
{
///
/// 提供接口,让别人获取 整理好的 当前生产,或之前生产的数据。
/// 从LocalDb 获取数据, 或从 直接从数据获取数据
///
/// 与HistoryDb,成对。
/// HistoryDb 是写
/// BulkDb 是读
///
public class BulkDb : IBulkDbService
{
///
/// 本地数据库
///
LocalDb localDb;
DbModel dbModel;
IShareDbService shareDb;
///
/// 最后一条扫描数据Id
///
public long LastScanDataId { get; private set; } = -1;
///
/// 最后一条产品Id
///
public long LastProfileId { get; private set; } = -1;
///
/// 数据库最后一次被修改时间
///
public DateTime LastTimestamp { get; private set; }
///
/// 开始产生数据时间
///
public DateTime StartTime { get; private set; }
///
/// 最后产生数据时间
///
public DateTime EndTime { get; private set; }
///
/// 当前生产,已经结束,已经下辊了
///
public bool IsFinished { get; private set; }
///
/// 混合数据,时间范围
/// 大于 TimeSpan.Zero 起作用
///
public TimeSpan MixDataTimeRange { get; set; } = TimeSpan.FromMinutes(5);
///
/// 混合数据,均值波动范围
/// 大于 0 起作用
///
public double MixDataAvgRange { get; set; } = 5;
///
///
///
public event PropertyChangedEventHandler PropertyChanged;
///
/// 临时数据改变
///
[Push(typeof(BulkDbTempFrameChangedEventArgs))]
public event EventHandler TempFrameChanged;
public Func GetTempFrameAction;
///
///
///
public BulkDb()
{
}
///
/// 写入动态数据
///
///
///
public void SetTempFrame(DateTime time, DateTime endTime, int startIndex, double[] D)
{
TempFrameChanged?.Invoke(this, new BulkDbTempFrameChangedEventArgs() { Time = time, EndTime = endTime, StartIndex = startIndex, D = D });
}
///
/// 获取临时数据
///
///
///
///
[Call(typeof(BulkDbTempFrameChangedEventArgs))]
public void GetTempFrame(
AsyncCBHandler asyncDelegate, object asyncContext)
{
BulkDbTempFrameChangedEventArgs e;
if (GetTempFrameAction != null)
e = GetTempFrameAction();
else
e = new BulkDbTempFrameChangedEventArgs();
asyncDelegate?.Invoke(asyncContext, e);
}
///
///
///
///
///
///
public void Init(IShareDbService shareDb,
LocalDb localDb, DbModel dbModel)
{
this.localDb = localDb;
this.dbModel = dbModel;
this.shareDb = shareDb;
LocalDBLoad();
Misc.BindingOperations.SetBinding(localDb, nameof(localDb.ProfileStartTime), this, nameof(StartTime));
Misc.BindingOperations.SetBinding(localDb, nameof(localDb.ProfileEndTime), this, nameof(EndTime));
Misc.BindingOperations.SetBinding(localDb, nameof(localDb.IsProfileFinished), this, nameof(IsFinished));
this.shareDb.ProfileChanged += ShareDB_ProfileChanged;
this.shareDb.ScanDataAdded += ShareDB_ScanDataAdded;
}
private void ShareDB_ProfileChanged(object sender, EventArgs _e)
{
ProfileChangedEventArgs e = (ProfileChangedEventArgs)_e;
var profile = e.profile;
//清除本地缓存
localDb.CurrProfile = profile;
localDb.ProfileStartTime = profile.StartTime;
localDb.ProfileEndTime = profile.EndTime;
localDb.IsProfileFinished = profile.IsFinished;
LastProfileId = profile.ID;
LastTimestamp = DateTime.Now;
}
private void ShareDB_ScanDataAdded(object sender, EventArgs _e)
{
ScanDataAddedEventArgs e = (ScanDataAddedEventArgs)_e;
LastScanDataId = e.scandata.ID;
LastTimestamp = DateTime.Now;
}
///
/// 加载数据库中最后1次订单数据到 本地
///
void LocalDBLoad()
{
var reponse = dbModel.sqliteHelper.ExecuteScalar($"SELECT MAX({nameof(Db_Profile.ID)}) FROM {dbModel.TbProfile.TableName}");
if (reponse is DBNull)
{
localDb.ProfileStartTime = DateTime.MinValue;
localDb.ProfileEndTime = DateTime.MinValue;
localDb.IsProfileFinished = true;
return;
}
long maxid = System.Convert.ToInt64(reponse);
var profile = dbModel.TbProfile.Find($"WHERE {nameof(Db_Profile.ID)} = {maxid}").First();
reponse = dbModel.sqliteHelper.ExecuteScalar($"SELECT MAX({nameof(Db_ScanData.ID)}) FROM {dbModel.TbScanData.TableName}");
if (!(reponse is DBNull))
{
maxid = System.Convert.ToInt64(reponse);
LastScanDataId = maxid;
}
localDb.CurrProfile = profile;
localDb.ProfileStartTime = profile.StartTime;
localDb.ProfileEndTime = profile.EndTime;
localDb.IsProfileFinished = profile.IsFinished;
LastProfileId = profile.ID;
}
///
/// 获取profile
///
///
///
///
[Call(typeof(Pack_GetProfileReponse))]
public async void GetProfile(
Pack_GetProfileRequest request,
AsyncCBHandler asyncDelegate, object asyncContext)
{
Pack_GetProfileReponse reponse = new Pack_GetProfileReponse();
reponse.Request = request;
await Task.Factory.StartNew(() =>
{
List db_profiles = dbModel.TbProfile.Find($"WHERE {nameof(Db_Profile.ID)} = {request.Id}");
if (db_profiles.Count() == 0)
return;
reponse.profile = db_profiles.First();
});
asyncDelegate(asyncContext, reponse);
}
///
/// 获取N幅数据,需要异步
///
///
///
///
public async void GetFrame(Pack_GetFrameRequest request, AsyncCBHandler asyncDelegate, object asyncContext)
{
Pack_GetFrameReponse reponse = new Pack_GetFrameReponse();
reponse.Request = request;
if (request.Mix > 10)//数量限制,避免死机
request.Mix = 10;
else if (request.Mix < 1)
request.Mix = 1;
await Task.Factory.StartNew(() =>
{
List db_scandatas;
if (request.Id <= 0)
db_scandatas = dbModel.TbScanData.Find(
$"ORDER BY {nameof(Db_ScanData.ID)} DESC" +
$" LIMIT {request.Mix} OFFSET {-request.Id}");
else
db_scandatas = dbModel.TbScanData.Find(
$"WHERE {nameof(Db_ScanData.ID)} <= {request.Id}" +
$" ORDER BY ID DESC LIMIT {request.Mix}");
if (db_scandatas.Count() == 0)
return;
var lc_scanDatas = Lc_AutoMapperProfile.Mapper.Map, List>(db_scandatas);
var lc_scanData = lc_scanDatas.First();
if (lc_scanDatas.Count() > 1)
{
//求均值
lc_scanData.Thicks = GetMixScanData(lc_scanDatas);
}
reponse.scanData = lc_scanData;
//找profile
var db_profiles = dbModel.TbProfile.Find(
$"WHERE {nameof(Db_Profile.StartTime)}<={lc_scanData.EndTime.ToStringOfSQLiteFieldType()}" +
$" AND {nameof(Db_Profile.EndTime)}>={lc_scanData.EndTime.ToStringOfSQLiteFieldType()}" +
$" ORDER BY {nameof(Db_Profile.ID)} DESC");
if (db_profiles.Count() > 0)
{
reponse.profile = db_profiles.First();
}
});
asyncDelegate(asyncContext, reponse);
}
///
/// 获取纵向趋势图
///
///
///
///
public async void GetTrend(Pack_GetTrendRequest request, AsyncCBHandler asyncDelegate, object asyncContext)
{
Pack_GetTrendReponse reponse = new Pack_GetTrendReponse();
reponse.Request = request;
if (request.Count > 200)//数量限制,避免死机
request.Count = 200;
else if (request.Count < 1)
request.Count = 1;
if (request.Mix > 10)//数量限制,避免死机
request.Mix = 10;
else if (request.Mix < 1)
request.Mix = 1;
if (request.Interval < 1)//避免 /0
request.Interval = 1;
await Task.Factory.StartNew(() =>
{
List db_scandatas = null;
if (request.Interval <= request.Mix)
{
//间隔<=混合,全部数据连续获取
int cnt = request.Count * request.Interval + request.Mix - 1;
if (!request.IsSearchByTime)
{
if (request.Id <= 0)
db_scandatas = dbModel.TbScanData.Find(
$" ORDER BY ID DESC" +
$" LIMIT {cnt} OFFSET {-request.Id}");
else
db_scandatas = dbModel.TbScanData.Find(
$"WHERE (ID <= {request.Id})" +
$" ORDER BY ID DESC" +
$" LIMIT {cnt}");
}
else
{
db_scandatas = dbModel.TbScanData.Find(
$"WHERE ({nameof(Db_ScanData.Time)} <= {request.Time.ToStringOfSQLiteFieldType()})" +
$" ORDER BY ID DESC" +
$" LIMIT {cnt}");
}
}
else
{
//间隔>混合 隔段获取
int cnt = request.Count * request.Mix;
if (!request.IsSearchByTime)
{
if (request.Id <= 0)
db_scandatas = dbModel.TbScanData.Find(
$"WHERE ID % {request.Interval} < {request.Mix}" +
$" ORDER BY ID DESC" +
$" LIMIT {cnt} OFFSET {-request.Id}");
else
db_scandatas = dbModel.TbScanData.Find(
$"WHERE (ID <= {request.Id})" +
$" AND ( ID % {request.Interval} < {request.Mix})" +
$" ORDER BY ID DESC" +
$" LIMIT {cnt}");
}
else
{
db_scandatas = dbModel.TbScanData.Find(
$"WHERE ({nameof(Db_ScanData.Time)} <= {request.Time.ToStringOfSQLiteFieldType()})" +
$" AND ( ID % {request.Interval} < {request.Mix})" +
$" ORDER BY ID DESC" +
$" LIMIT {cnt}");
}
}
if (db_scandatas.Count() == 0)
return;
//从尾向前排的!!!!
var lc_scanDatas = Lc_AutoMapperProfile.Mapper.Map, List>(db_scandatas);
reponse.Values = ToTrend2(lc_scanDatas, request.Count, request.Mix, request.Interval);
var lc_scanData = lc_scanDatas.First();
reponse.ScanDataId = lc_scanData.ID;
});
asyncDelegate(asyncContext, reponse);
}
double[] GetMixScanData(List lc_scanDatas)
{
var lc_scanData = lc_scanDatas[0];
//求均值
double[] thks = new double[lc_scanData.Thicks.Count()];
int[] cnt = new int[thks.Count()];
for (int j = 0; j < lc_scanDatas.Count(); j++)
{
int index = j;
if (lc_scanDatas[index].Thicks.Count() != thks.Count())
{
//结束,异常
break;
}
for (int i = 0; i < thks.Count(); i++)
{
var v = lc_scanDatas[index].Thicks[i];
if (!double.IsNaN(v))
{
thks[i] += v;
cnt[i]++;
}
}
}
for (int i = 0; i < thks.Count(); i++)
{
if (cnt[i] > 0)
thks[i] /= cnt[i];
else
thks[i] = double.NaN;
}
return thks;
}
double[] GetMixScanData(List lc_scanDatas, int offset, int mix, out int realMix)
{
//lc_scanDatas[0] 是最新的数据!!
List lc_scanDatas2 = new List();
for (int i = 0; i < mix; i++)
{
int index = offset + i;
if (index >= lc_scanDatas.Count())
break;
lc_scanDatas2.Add(lc_scanDatas[offset + i]);
}
//连续两幅图时间间隔 大于 MixDataTimeRange 删除
if (MixDataTimeRange > TimeSpan.Zero)
{
for (int i = 1; i < lc_scanDatas2.Count(); i++)
{
var scanData0 = lc_scanDatas2[i - 1];
var scanData1 = lc_scanDatas2[i];
if (scanData0.Time - scanData1.Time > MixDataTimeRange)
{
lc_scanDatas2.RemoveRange(i, lc_scanDatas2.Count() - i);
break;
}
}
}
//把 均值与 最新的一幅图 的均值 偏差 大于 MixDataAvgRange 删除
if (MixDataAvgRange > 0)
{
var newest_scanData = lc_scanDatas2[0];
//注意数据是没有剔除的, 计算平均值时,要明确范围
var newest_avg = Misc.MyMath.Avg(newest_scanData.Thicks);
if (!double.IsNaN(newest_avg))
{
for (int i = 1; i < lc_scanDatas2.Count(); i++)
{
var scanData = lc_scanDatas2[i];
var avg = Misc.MyMath.Avg(scanData.Thicks);
if (double.IsNaN(avg))//一幅数据异常,全部删除
{
lc_scanDatas2.RemoveRange(i, lc_scanDatas2.Count() - i);
break;
}
//变化太大
if (Math.Abs(newest_avg - avg) > MixDataAvgRange)
{
lc_scanDatas2.RemoveRange(i, lc_scanDatas2.Count() - i);
break;
}
}
}
else
{
lc_scanDatas2.RemoveRange(1, lc_scanDatas2.Count() - 1);
}
}
realMix = lc_scanDatas2.Count();
if (lc_scanDatas2.Count() > 1)
{
//求均值
return GetMixScanData(lc_scanDatas2);
}
else
{
return lc_scanDatas2.First().Thicks.ToArray();
}
}
List ToTrend2(List lc_scanDatas, int count, int mix, int interval)
{
// lc_scanDatas.First() 是ID最大的数据
//if (mix == 1)
//{
// return lc_scanDatas.Select(sd =>
// {
// double avg = sd.Thicks.AverageNoNull();
// double sigma = sd.Thicks.Sigma();
// return new TrendValue()
// {
// ScanDataID = sd.ID,
// ProfileID = sd.ProfileID,
// Sigma = sigma,
// Value = avg,
// Time = sd.Time
// };
// }).ToList();
//}
List trendValues = new List();
for (int i = 0; i < lc_scanDatas.Count(); i++)
{
var sd = lc_scanDatas[i];
if (sd.ID % interval == 0)
{
//它是数据点
double[] thks = GetMixScanData(lc_scanDatas, i, mix, out int _m);
//求均值
double avg = thks.AverageNoNull();
double sigma = thks.Sigma();
trendValues.Add(new TrendValue()
{
ScanDataID = sd.ID,
Sigma = sigma,
Value = avg,
Time = lc_scanDatas[i].Time
});
if (trendValues.Count() >= count)
break;//完成
}
}
return trendValues;
}
///
/// 完成
///
public void Finish()
{
shareDb.FinishProfile();
}
}
}