301 lines
14 KiB
C#
301 lines
14 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using DTS.Common.Utilities.Logging;
|
|
using DTS.Slice.Users;
|
|
|
|
namespace DTS.SensorDB
|
|
{
|
|
/// <summary>
|
|
/// A class that handles merging of sensor calibrations
|
|
/// </summary>
|
|
public class SensorMerge
|
|
{
|
|
|
|
public List<SensorData> SensorDataMergeList { get; private set; } = new List<SensorData>();
|
|
public Dictionary<string, List<SensorCalibration>> SensorCalibrationMergeList { get; private set; } = new Dictionary<string, List<SensorCalibration>>();
|
|
|
|
public Dictionary<int, int> OldSensorDatabaseIdToNew { get; private set; } = new Dictionary<int, int>();
|
|
private readonly User _currentUser = null;
|
|
|
|
private readonly object _lock = new object();
|
|
private Dictionary<string, MergeStatus> _mergeStatuses = new Dictionary<string, MergeStatus>();
|
|
public MergeStatus GetMergeStatus(string serialNumber)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
return _mergeStatuses.ContainsKey(serialNumber) ? _mergeStatuses[serialNumber] : null;
|
|
}
|
|
}
|
|
public List<MergeStatus> GetMergeStatuses(List<string> serialNumbers)
|
|
{
|
|
var rv = new List<MergeStatus>();
|
|
foreach (var sn in serialNumbers)
|
|
{
|
|
rv.Add(GetMergeStatus(sn));
|
|
}
|
|
return rv;
|
|
}
|
|
public List<MergeStatus> GetAllMergeStatuses()
|
|
{
|
|
var rv = new List<MergeStatus>();
|
|
lock (_lock)
|
|
{
|
|
rv.AddRange(_mergeStatuses.Values);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
public class MergeStatus
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the string for IsSensorInUse for the sensor
|
|
/// </summary>
|
|
public string BrokenDoNotUse { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the bool for a sensor with an EID that matches another sensor in the database
|
|
/// </summary>
|
|
public bool ConflictedEID { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the bool for a sensor with an EID that matches another sensor in the database
|
|
/// </summary>
|
|
public bool WarnConflictedEID { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the bool for a sensor that may match serial number and cal date but have different calibration information.
|
|
/// </summary>
|
|
public bool ConflictedSensor { get; set; }
|
|
/// <summary>
|
|
/// If true, the sensor did not get committed because of an error
|
|
/// </summary>
|
|
public bool Errored => ConflictedEID && ConflictedSensor && WarnConflictedEID || ErrorCommitingCal || MismatchedModelOrBridgeType;
|
|
/// <summary>
|
|
/// indicates that there was an error with the cal or the cal failed to be committed
|
|
/// </summary>
|
|
public bool ErrorCommitingCal { get; set; } = false;
|
|
/// <summary>
|
|
/// If true, the sensor did not get committed because there was newer/same information in the database.
|
|
/// </summary>
|
|
public bool Ignored { get; set; }
|
|
/// <summary>
|
|
/// If true, the sensor was committed or updated.
|
|
/// </summary>
|
|
public bool Committed { get; set; }
|
|
/// <summary>
|
|
/// If true, the input file had a mismatch in the Model or BridgeType column
|
|
/// </summary>
|
|
public bool MismatchedModelOrBridgeType { get; set; }
|
|
}
|
|
public SensorMerge(User currentUser)
|
|
{
|
|
_currentUser = currentUser;
|
|
}
|
|
public SensorMerge(User currentUser, List<SensorData> sensorDataToMerge, Dictionary<string, List<SensorCalibration>> sensorCalibrationsToMerge)
|
|
{
|
|
SensorDataMergeList = sensorDataToMerge;
|
|
SensorCalibrationMergeList = sensorCalibrationsToMerge;
|
|
_currentUser = currentUser;
|
|
}
|
|
public SensorMerge(User currentUser, List<SensorData> sensorDataToMerge, Dictionary<string, List<SensorCalibration>> sensorCalibrationsToMerge, Dictionary<int, int> oldSensorDatabaseIdToNew)
|
|
{
|
|
SensorDataMergeList = sensorDataToMerge;
|
|
SensorCalibrationMergeList = sensorCalibrationsToMerge;
|
|
OldSensorDatabaseIdToNew = oldSensorDatabaseIdToNew;
|
|
_currentUser = currentUser;
|
|
}
|
|
|
|
public void PerformWork()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
|
|
_mergeStatuses = new Dictionary<string, MergeStatus>();
|
|
|
|
// Verify that SensorDataMergeList Contains the Calibration entries.
|
|
// If it doesn't, add from the DB, if they exist there.
|
|
foreach (var scList in SensorCalibrationMergeList)
|
|
{
|
|
var sn = scList.Value.FirstOrDefault()?.SerialNumber;
|
|
if (string.IsNullOrEmpty(sn)) continue;
|
|
if (SensorDataMergeList.Any(x => string.Equals(x.SerialNumber, sn))) continue;
|
|
var existing = SensorsCollection.SensorsList.GetSensorBySerialNumber(sn);
|
|
if (existing != null)
|
|
{
|
|
SensorDataMergeList.Add(existing);
|
|
}
|
|
}
|
|
|
|
//handle broken [true] before do not use
|
|
//handle do not use [true] before regular.
|
|
SensorDataMergeList.Sort((a, b) =>
|
|
{
|
|
if (a.Equals(b))
|
|
{
|
|
return 0;
|
|
}
|
|
if (a.Broken == b.Broken)
|
|
{
|
|
if (a.DoNotUse == b.DoNotUse)
|
|
{
|
|
return a.CompareTo(b);
|
|
}
|
|
return a.DoNotUse ? -1 : 1;
|
|
}
|
|
return a.Broken ? -1 : 1;
|
|
});
|
|
foreach (var sd in SensorDataMergeList)
|
|
{
|
|
try
|
|
{
|
|
_mergeStatuses[sd.SerialNumber] = new MergeStatus();
|
|
var oldId = sd.DatabaseId;
|
|
if (sd.Broken || sd.DoNotUse)
|
|
{
|
|
_mergeStatuses[sd.SerialNumber].BrokenDoNotUse = DTS.SensorDB.SensorsCollection.SensorsList.IsSensorInUse(sd);
|
|
}
|
|
if (sd.IsSquib() || sd.IsDigitalInput() || sd.IsDigitalOutput())
|
|
{
|
|
var existing =
|
|
DTS.SensorDB.SensorsCollection.SensorsList.GetSensorBySerialNumber(sd.SerialNumber);
|
|
if (null == existing)
|
|
{
|
|
if (DTS.SensorDB.SensorsCollection.SensorsList.SensorIdExists(sd.EID))
|
|
{
|
|
//just fine, note it and don't commit it
|
|
_mergeStatuses[sd.SerialNumber].WarnConflictedEID = true;
|
|
}
|
|
else
|
|
{
|
|
CommitToSensorList(sd, oldId);
|
|
_mergeStatuses[sd.SerialNumber].Committed = true;
|
|
}
|
|
}
|
|
else if (!existing.SimpleEquals(sd))
|
|
{
|
|
// Setting does not match. Update it.
|
|
CommitToSensorList(sd, oldId);
|
|
_mergeStatuses[sd.SerialNumber].Committed = true;
|
|
}
|
|
else
|
|
{
|
|
_mergeStatuses[sd.SerialNumber].Ignored = true;
|
|
//just fine, note and move on (don't commit
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if (!SensorCalibrationMergeList.ContainsKey(sd.UUID)) continue;
|
|
var scNew = SensorCalibrationMergeList[sd.UUID].FirstOrDefault();
|
|
var scOld = DTS.SensorDB.SensorCalibrationList.GetLatestCalibrationBySerialNumber(sd);
|
|
var bCommit = false;
|
|
if (null == scOld)
|
|
{
|
|
bCommit = true;
|
|
if (DTS.SensorDB.SensorsCollection.SensorsList.SensorIdExists(sd.EID) &&
|
|
(!sd.Broken || !sd.DoNotUse))
|
|
{
|
|
bCommit = false;
|
|
_mergeStatuses[sd.SerialNumber].ConflictedEID = true;
|
|
//ERROR
|
|
}
|
|
}
|
|
else if (scOld.CalibrationDate.Date < scNew.CalibrationDate || sd.Broken || sd.DoNotUse)
|
|
{
|
|
bCommit = true;
|
|
}
|
|
else if (scOld.CalibrationDate == scNew.CalibrationDate)
|
|
{
|
|
bCommit = false;
|
|
var sdOld = DTS.SensorDB.SensorsCollection.SensorsList.GetSensorBySerialNumber(sd.SerialNumber, false);
|
|
if (null == sdOld || !sdOld.SimpleEquals(sd))
|
|
{
|
|
//if the cal dates are the same but the cal info is not, we've got an error
|
|
//if the ids are the same, the cal dates are the same, and broken and do not use are all the same,
|
|
//we've got nothing to update, so we've got an error
|
|
//if broken/donotuse/id change do the update
|
|
if (null != sdOld && (!scOld.SimpleEquals(scNew) ||
|
|
sdOld.EID.Equals(sd.EID) && sdOld.Broken == sd.Broken && sd.DoNotUse == sdOld.DoNotUse))
|
|
{
|
|
_mergeStatuses[sd.SerialNumber].ConflictedSensor = true;
|
|
//ERROR
|
|
}
|
|
else
|
|
{
|
|
//http://fogbugz/fogbugz/default.asp?10391
|
|
//allow updating if the cal info is the same, and ids have changed
|
|
//we might want to check that just the id changed ...
|
|
bCommit = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//just fine, note it and don't commit it
|
|
_mergeStatuses[sd.SerialNumber].Ignored = true;
|
|
}
|
|
}
|
|
|
|
if (!bCommit) continue;
|
|
try
|
|
{
|
|
CommitToSensorList(sd, oldId);
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
//flag all 3 problems otherwise "Errored" isn't true with current rules
|
|
_mergeStatuses[sd.SerialNumber].ConflictedEID = true;
|
|
_mergeStatuses[sd.SerialNumber].ConflictedSensor = true;
|
|
_mergeStatuses[sd.SerialNumber].WarnConflictedEID = true;
|
|
APILogger.Log(ex);
|
|
continue;
|
|
}
|
|
if (null != scNew && !scNew.SimpleEquals(scOld))
|
|
{
|
|
try
|
|
{
|
|
//avoid any dates which are invalid according to ms sql
|
|
if (scNew.CalibrationDate.Year <= 1900)
|
|
{
|
|
_mergeStatuses[sd.SerialNumber].ErrorCommitingCal = true;
|
|
APILogger.Log($"Invalid date: {scNew.CalibrationDate.ToShortDateString()} - {sd.SerialNumber}");
|
|
continue;
|
|
}
|
|
SensorCalibrationList.Commit(scNew, true, sd);
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
_mergeStatuses[sd.SerialNumber].ErrorCommitingCal = true;
|
|
APILogger.Log(ex);
|
|
continue;
|
|
}
|
|
}
|
|
_mergeStatuses[sd.SerialNumber].Committed = true;
|
|
|
|
}
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
if (ex.Message.Contains("can't change sensor to"))
|
|
{
|
|
_mergeStatuses[sd.SerialNumber].MismatchedModelOrBridgeType = true;
|
|
}
|
|
else
|
|
{
|
|
_mergeStatuses[sd.SerialNumber].ErrorCommitingCal = true;
|
|
}
|
|
APILogger.Log(ex);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CommitToSensorList(SensorData sd, int oldId)
|
|
{
|
|
SensorsCollection.SensorsList.Commit(_currentUser.UserName, sd, false);
|
|
if (sd.DatabaseId != oldId)
|
|
{
|
|
OldSensorDatabaseIdToNew[oldId] = sd.DatabaseId;
|
|
}
|
|
}
|
|
}
|
|
}
|