public static void Adjust(Milestone prospectiveMover, DateTime newValue) { if (prospectiveMover.m_dateTime.Equals(newValue)) { return; } lock ( s_lock ) { if (_debug) { _Debug.WriteLine("Attempting to coordinate correct movement of " + prospectiveMover.Name + " from " + prospectiveMover.DateTime + " to " + newValue + "."); } // Change, and then enqueue the first milestone. _oldValues.Add(prospectiveMover, prospectiveMover.DateTime); _changedMilestones.Enqueue(prospectiveMover); while (prospectiveMover.m_dateTime != newValue) // TODO: This is a SLEDGEHAMMER. Figure out why root changes don't always hold. { prospectiveMover.m_dateTime = newValue; // Propagate the change downstream (including any resultant changes.) Propagate(); } // Finally, tell each changed milestone to fire it's change event. foreach (Milestone changed in _oldValues.Keys) { changed.NotifyValueChanged((DateTime)_oldValues[changed]); } // And reset the data structures for the next use. _oldValues.Clear(); while (_pushedDisablings.Count > 0) { ((MilestoneRelationship)(_pushedDisablings.Pop())).PopEnabled(); } _changedMilestones.Clear(); } }
private static void Propagate() { while (_changedMilestones.Count > 0) { Milestone ms = (Milestone)_changedMilestones.Dequeue(); if (_debug) { _Debug.WriteLine("\tPerforming propagation of change to " + ms.Name); } #region Create a Hashtable of Lists - key is target Milestone, list contains relationships to that ms. Hashtable htol = new Hashtable(); foreach (MilestoneRelationship mr in ms.Relationships) { if (!mr.Enabled) { continue; // Only enabled relationships can effect change. } if (mr.Dependent.Equals(ms)) { continue; // Only relationships where we are the independent can effect change. } //if ( m_debug ) _Debug.WriteLine("\tConsidering " + mr.ToString()); if (!htol.Contains(mr.Dependent)) { htol.Add(mr.Dependent, new ArrayList()); } ((ArrayList)htol[mr.Dependent]).Add(mr); // We now have outbounds, grouped by destination milestone. } #endregion //if ( m_debug ) _Debug.WriteLine("\tPerforming change assessments for relationships that depend on " + ms.Name); // For each 'other' milestone with which this milestone has a relationship, we will // handle all of the relationships that this ms has with that one, as a group. bool fullData = false; foreach (Milestone target in htol.Keys) { if (_debug) { _Debug.WriteLine("\t\tReconciling all relationships between " + ms.Name + " and " + target.Name); // E : RCV Liquid1.Xfer-In.Start and E : RCV Liquid1.Xfer-In.End } IList relationships = (ArrayList)htol[target]; // Gives us a list of parallel relationships to the same downstream. // if ( ms.Name.Equals("B : RCV Liquid1.Xfer-In.Start") && target.Name.Equals("B : RCV Liquid1.Temp-Set.End") ) { // fullData = true; // } if (fullData) { foreach (MilestoneRelationship mr2 in relationships) { _Debug.WriteLine(mr2.ToString()); } } DateTime minDateTime = DateTime.MinValue; DateTime maxDateTime = DateTime.MaxValue; foreach (MilestoneRelationship mr2 in relationships) { /*foreach ( MilestoneRelationship recip in mr2.Reciprocals) { * recip.PushEnabled(false); * m_pushedDisablings.Push(recip); * }*/ if (fullData) { if (_debug) { _Debug.WriteLine("\t\tAdjusting window to satisfy " + mr2); } } DateTime thisMinDt, thisMaxDt; mr2.Reaction(ms.DateTime, out thisMinDt, out thisMaxDt); // Get the relationship's acceptable window. minDateTime = DateTimeOperations.Max(minDateTime, thisMinDt); // Narrow the range from below. maxDateTime = DateTimeOperations.Min(maxDateTime, thisMaxDt); // Narrow the range from above. if (fullData) { if (_debug) { _Debug.WriteLine("\t\t\tThe window is now from " + minDateTime + " to " + maxDateTime + "."); } } } //if ( m_debug ) _Debug.WriteLine("\t\tThe final window is from " + minDateTime + " to " + maxDateTime + "."); if (minDateTime <= maxDateTime) { DateTime newDateTime = GetClosestDateTime(minDateTime, maxDateTime, target.DateTime); if (!target.DateTime.Equals(newDateTime)) { if (_debug) { _Debug.WriteLine("\t\t\tWe will move " + target.Name + " from " + target.DateTime + " to " + newDateTime); } if (!_changedMilestones.Contains(target)) { _changedMilestones.Enqueue(target); } if (!_oldValues.Contains(target)) { _oldValues.Add(target, target.m_dateTime); } if (fullData) { if (_debug) { _Debug.WriteLine("\t\t\tThere are now " + _changedMilestones.Count + " milestones with changes to process."); } } target.m_dateTime = newDateTime; } else { if (_debug) { _Debug.WriteLine("\t\t\t" + target.Name + " stays put."); } } // } else { // if ( m_debug ) _Debug.WriteLine("\t\t\tThis is an unachievable window."); // throw new ApplicationException("Can't find a new datetime value for " + target.ToString()); } fullData = false; } } }