using Godot;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using BITKit.Core.Entites;
using BITKit.Packages.Core.LazyLoad;
using Cysharp.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace BITKit;
///
/// 单例SCADA Service,从http接口获取json后解析为指定数据
///
public partial class SCADAService : Node,IProvider,IActivable
{
public const string _CurrentAngle="CurrentAngle";
public const string _CurrentRotation="CurrentRotation";
///
/// 在构造函数中注入依赖
///
public SCADAService()
{
BITApp.ServiceCollection.AddSingleton(this);
}
///
/// 获取json的Url
///
private readonly DataReference _url = new("SCADA_GetInfos");
///
/// 是否固定控制的Entity,如果固定,只会刷新一次,如果不固定,每帧都会刷新
///
[Export]
private bool fixedEntities;
///
/// 是否启用
///
[Export]
public bool Enabled { get; set; } = true;
///
/// 已加载的Entity
///
private readonly Dictionary _entities = new();
///
/// 获取Entity并加载依赖
///
public override async void _Ready()
{
if (!fixedEntities) return;
await UniTask.Yield();
LoadAllEntities();
BIT4Log.Log($"已加载{_entities.Count}个设备");
if (string.IsNullOrEmpty(_url))
{
BIT4Log.Warning("SCADA Url为空");
}
else
{
BIT4Log.Log($"已找到SCADA_GetInfos:\t{_url.Get()}");
}
}
///
/// 内部方法,从EntityService加载所有Entity
///
private void LoadAllEntities()
{
foreach (var entity in DI.Get().Entities)
{
if (entity.TryGetComponent(out var deviceComponent))
{
_entities.Add(deviceComponent.Id,deviceComponent.Entity);
}
}
}
///
/// 从http请求json
///
///
/// 解析json
///
/// 从SCADA获取的Json
public void Set(string json)
{
if(Enabled is false)return;
//首先从result中获取数组
var jArray = JsonConvert.DeserializeObject(json)["result"]!.ToObject();
//然后遍历所有数组的内容
foreach (var element in jArray)
{
//获取数组元素的Id
var id = element["id"]!.ToObject();
//通过Id查找已加载的Entity
if (!_entities.TryGetValue(id, out var entity)) continue;
//加载数组中的"value"为json
var _key = element["value"]!.ToString();
string _json;
if (_key.Substring(0) is "\"")
{
_json = element["value"]!.ToObject();
}
else
{
_json = element["value"].ToString();
}
//获取被加载为string的json
var obj = JsonConvert.DeserializeObject(_json);
//反序列化string为原始json
var value = JObject.Parse(obj!.ToString()!);
//提交json和entity
ProcessEntity(value,entity);
}
}
///
/// 提交jObject数据和Entity进行解析和处理
///
/// json [result] [index] [value] 中的原始json
/// 引用实体,如PLC-ZL
private static void ProcessEntity(JObject jObject, IEntity entity)
{
//从Entity中加载所有Rotation Component
var rotationComponents = entity
.Components
.Where(x => x is RotationComponent)
.Select((x => (RotationComponent)x));
//遍历所有Rotation Component
foreach (var rotationComponent in rotationComponents)
{
//加载rotation需要的path,如 var angle = value["J1"]
var path = rotationComponent.Path;
//加载以获取到的角度
var rawAngle = jObject[path]!.ToObject();
//补间角度
var currentAngle = rotationComponent.CurrentAngle = Mathf.Lerp(rotationComponent.CurrentAngle, rawAngle,
90 * BITAppForGodot.DeltaTime);
//最终角度 = 当前角度*角度权重 + 角度偏移 + 原始角度
var euler = currentAngle * rotationComponent.Weight + rotationComponent.Offset + rotationComponent.OriginalEuler;
//为Node3D.Rotation提交最后的角度计算结果
euler.X = Mathf.DegToRad(euler.X);
euler.Y = Mathf.DegToRad(euler.Y);
euler.Z = Mathf.DegToRad(euler.Z);
rotationComponent.node3D.Rotation = euler;
//rotationComponent.RotationDegrees = euler;
rotationComponent.SetMeta(_CurrentAngle,(int)rawAngle);
rotationComponent.SetMeta(_CurrentRotation,euler);
}
}
public string Get()
{
throw new NotImplementedException();
}
public void SetActive(bool active) => Enabled = active;
}