private void updateRoutingTable()
        {
            List<VarID> sinkList = new List<VarID>(); // ONE route to each sink...

            _tableRouting.Clear();  // Start fresh. This list is a factor of valid data elsewhere.

            // Get all valid sink IDs
            foreach (PEQTableEntrySubscription subEntry in _tableSubscription)
            {
                if (!sinkList.Contains(subEntry._SinkID))
                    sinkList.Add(subEntry._SinkID);
            }

            // Find the best route to each sink.
            foreach (VarID sinkID in sinkList)
            {
                Byte best_hop = 0xFF; // Ensure that the best subEntry is added to the route.
                double best_time = 0; // Ensure that the most recent entry is used
                PEQTableEntrySubscription best_hopEntry = null;
                foreach (PEQTableEntrySubscription subEntry in _tableSubscription)
                {
                    if (subEntry._HopCount <= best_hop)
                    {
                        if (subEntry._Timestamp >= best_time)
                        {
                            best_hop = subEntry._HopCount;
                            best_time = subEntry._Timestamp;
                            best_hopEntry = subEntry;
                        }
                    }
                }

                if (best_hopEntry != null)
                {
                    PEQTableEntryRouting newRoute = new PEQTableEntryRouting(_NUM_ID_BYTES);
                    newRoute._DestinationID = best_hopEntry._DestinationID;
                    newRoute._SinkID = best_hopEntry._SinkID;
                    newRoute._nextHopCheat = best_hopEntry._nextHopCheat;
                    newRoute._Valid = best_hopEntry._Valid;
                    _tableRouting.Add(newRoute);

                    IGraphicalReport newRouteReport;
                    if (best_hopEntry._CriteriaType == 0x0000)
                        newRouteReport = GenerateDirectionReport(GetMessageLevel(new PEQMessageBuildTree()));
                    else
                        newRouteReport = GenerateDirectionReport(GetMessageLevel(new PEQMessageSubscribe()));
                    if (newRouteReport != null)
                    {
                        if (currentRouteReport != null)
                        {
                            newRouteReport.ReportAction = MNS_Reporting.Action.Modify;
                            newRouteReport.PreviousStatic = currentRouteReport;
                            currentRouteReport = newRouteReport;
                            Notify(newRouteReport);
                        }
                        else
                        {
                            currentRouteReport = GenerateDirectionReport();
                            if (currentRouteReport != null)
                                Notify(currentRouteReport);
                        }
                    }
                    else if (currentRouteReport != null)
                    {
                        LineReport dirReport = new LineReport(_eventManager.CurrentClock,
                        (XYDoubleLocation)_location,
                        (XYDoubleLocation)newRoute._nextHopCheat, 0, -250, true, -_id.GetID());
                        dirReport.PreviousStatic = currentRouteReport;
                        dirReport.ReportAction = MNS_Reporting.Action.Stop;
                        Notify(dirReport);

                        currentRouteReport = null;
                    }
                }
            }
        }
        private void completeSearch(PEQTableEntrySearch winner)
        {
            PEQTableEntryRouting outRoute = null;
            if (winner == null)
                return; // should perform completeSearch(sinkID) first!
            bool found = false;
            // End Search, Update Route
            foreach (PEQTableEntryRouting route in _tableRouting)
            {
                if ((route._SinkID == winner._SinkID) && (!route._Valid))
                {
                    found = true;
                    route._Valid = true;
                    route._DestinationID = winner._DestinationID;
                    route._nextHopCheat = winner._nextHopCheat;
                    outRoute = route;
                }
            }

            // Add route
            if (!found)
            {
                PEQTableEntryRouting route = new PEQTableEntryRouting(_NUM_ID_BYTES);
                route._DestinationID = winner._DestinationID;
                route._SinkID = winner._SinkID;
                route._nextHopCheat = winner._nextHopCheat;
                _tableRouting.Add(route);
                outRoute = route;
            }

            updateRoutingTable();

            if (winner._DataMessage is PEQMessageNotify)
                sendNotify(outRoute, (PEQMessageNotify)winner._DataMessage);
        }
        private void sendNotify(PEQTableEntryRouting Route, PEQMessageNotify msg)
        {
            PEQMessageNotify newMsg = (PEQMessageNotify)msg.Clone();
            newMsg._SenderID = _id;
            newMsg._SequenceNumber = _sequenceNumber++;
            newMsg._DestinationID = Route._DestinationID;
            newMsg._nextHopCheat = _location;
            newMsg._Data._NumHops++;
            newMsg._Data._TotalDistance += _location.Distance(msg._nextHopCheat);

            PEQTimerMessage timerEvent = new PEQTimerMessage(newMsg,
                _eventManager.CurrentClock + _TIMER_WAIT_SEND, this);
            _eventManager.AddEvent(timerEvent);
        }