/// <summary> /// Calculates for how long the sensor stayed in each state during the hour. /// </summary> /// <param name="clientsHistory">The clients states changes history for the given hour (can be empty).</param> /// <param name="sensorsHistory">The sensors states changes history for the give hour (can be empty).</param> /// <param name="previousClientHistory">The most recent client state change prior to the hour we calculating for (can be null).</param> /// <param name="previousSensorHistory">The most recent sensor state change prior to the hour we calculating for (can be null).</param> /// <returns>Dictionary where is the key is a state and the value is for how long in ms the sensor stayed in this state</returns> private Dictionary<int, long> calculateHourlyStats( List<ClientStateHistory> clientsHistory, List<SensorStateHistory> sensorsHistory, ClientStateHistory previousClientHistory, SensorStateHistory previousSensorHistory) { IDictionary<ClientStateHistory, List<SensorStateHistory>> sensorStatesByClient = new SortedDictionary<ClientStateHistory, List<SensorStateHistory>>(); var result = new Dictionary<int, long>() { { (int)StatState.Offline, 0 }, { (int)StatState.Available, 0 }, { (int)StatState.Occupied, 0 } }; if (clientsHistory.Count == 0 && previousClientHistory == null) { result[(int)StatState.Offline] = ((long)TimeSpan.FromHours(1).TotalMilliseconds); return result; } //No Data on current hour, take previous stats and set for full hour if (clientsHistory.Count == 0 && sensorsHistory.Count == 0) { if (previousClientHistory == null || previousClientHistory.IsOnline == false) { result[-1] = ((long)TimeSpan.FromHours(1).TotalMilliseconds); } if (previousClientHistory != null && previousClientHistory.IsOnline && previousSensorHistory != null) { result[previousSensorHistory.State] = ((long)TimeSpan.FromHours(1).TotalMilliseconds); } return result; } //Set previous and set to beginging of current hour if (previousClientHistory != null) { previousClientHistory.StateChangedTimestamp = getStartingHour(clientsHistory, sensorsHistory); sensorStatesByClient.Add(previousClientHistory, new List<SensorStateHistory>()); if (previousSensorHistory != null) { previousSensorHistory.StateChangedTimestamp = previousClientHistory.StateChangedTimestamp; sensorStatesByClient[previousClientHistory].Add(previousSensorHistory); } } //clients list to dictionary keys foreach (var clientHistoryRecord in clientsHistory) { sensorStatesByClient.Add(clientHistoryRecord, new List<SensorStateHistory>()); } //triage sensors to relevant client records foreach (var sensorHistRecord in sensorsHistory) { //going backwards. var key = sensorStatesByClient.Keys.OrderByDescending(c => c.StateChangedTimestamp).FirstOrDefault(c => c.StateChangedTimestamp <= sensorHistRecord.StateChangedTimestamp); if (key != null)//otherwise we ignore.. we have sensorChangeState before first ever Client State change!! { sensorStatesByClient[key].Add(sensorHistRecord); } } //for each client set a dummy first sensor record (with time equal to begining of the range..) foreach (var client in sensorStatesByClient) { if (client.Key.IsOnline) { var closest = FindClosestSensorHistory(client.Key.StateChangedTimestamp, sensorsHistory) ?? previousSensorHistory ?? new SensorStateHistory() { State = (int)StatState.Available, StateChangedTimestamp = client.Key.StateChangedTimestamp }; if (!client.Value.Any() || client.Value.First().StateChangedTimestamp != client.Key.StateChangedTimestamp) { client.Value.Insert(0, new SensorStateHistory() { StateChangedTimestamp = client.Key.StateChangedTimestamp, State = closest.State }); } } } //calc offline var orderedKeys = sensorStatesByClient.Keys.OrderBy(c => c.StateChangedTimestamp); DateTime from = orderedKeys.First().StateChangedTimestamp.ToRoundHourBottom(); foreach (var key in orderedKeys) { if (key.IsOnline == true) { result[-1] += ((long)(key.StateChangedTimestamp - from).TotalMilliseconds); } from = key.StateChangedTimestamp; } //add the rest if (!orderedKeys.Last().IsOnline) { result[-1] += orderedKeys.Last().StateChangedTimestamp.MsTillTheEndOfHour(); } //calc available/occupied for each online range DateTime to = orderedKeys.First().StateChangedTimestamp.ToRoundHourUpper(); foreach (var key in orderedKeys.Reverse()) { if (key.IsOnline == true) { for (int i = sensorStatesByClient[key].Count - 1; i >= 0; i--) { var sensorState = sensorStatesByClient[key][i]; result[sensorState.State] += ((long)(to - sensorStatesByClient[key][i].StateChangedTimestamp).TotalMilliseconds); to = sensorState.StateChangedTimestamp; } } to = key.StateChangedTimestamp; } return result; }
private Dictionary<int, long> invokeCalculateHourlyStats( List<ClientStateHistory> clientsHistory, List<SensorStateHistory> sensorsHistory, ClientStateHistory previousClientHistory, SensorStateHistory previousSensorHistory) { var result = _testedMethod.Invoke(_processor, parameters: new object[] { clientsHistory, sensorsHistory, previousClientHistory, previousSensorHistory }); return result as Dictionary<int, long>; }