예제 #1
0
        internal DVNode(IMNodeInternal node, ForwardDelegate forwardMethod, IAsynchQueue queue, IKeyTableFactory tableFactory, int TTL, IConfigSource config)
            : base(node, tableFactory, config)
        {
            _queue         = queue;
            _forwardMethod = forwardMethod;
            this.TTL       = TTL;

            distanceVector = new DistanceVector();

            neighbourVectors    = tableFactory.MakeKeyTable <DistanceVector>();
            highlightParameters = new Parameters(new object[] { "HColour", node.Colour });

            IConfig dvConfig = config.Configs["DV"];

            if (dvConfig == null)
            {
                dvConfig = config.Configs["DistanceVector"];
            }
            if (dvConfig == null)
            {
                dvConfig = config.Configs["Algorithm"];
            }
            if (dvConfig == null)
            {
                dvConfig = config.Configs[0];
            }

            _poison            = dvConfig.GetBoolean("PoisonReverse", true);
            _everPrint         = dvConfig.GetBoolean("EverPrint", false);
            _alwaysPrint       = dvConfig.GetBoolean("AlwaysPrint", false);
            highlightPrintText = dvConfig.GetBoolean("HighlightPrint", false);
        }
예제 #2
0
        internal DVNode(IMNodeInternal node, ForwardDelegate forwardMethod, IAsynchQueue queue, IKeyTableFactory tableFactory, int TTL, IConfigSource config)
            : base(node, tableFactory, config)
        {
            _queue = queue;
            _forwardMethod = forwardMethod;
            this.TTL = TTL;

            distanceVector = new DistanceVector();

            neighbourVectors = tableFactory.MakeKeyTable<DistanceVector>();
            highlightParameters = new Parameters(new object[] { "HColour", node.Colour });

            IConfig dvConfig = config.Configs["DV"];
            if (dvConfig == null)
                dvConfig = config.Configs["DistanceVector"];
            if (dvConfig == null)
                dvConfig = config.Configs["Algorithm"];
            if (dvConfig == null)
                dvConfig = config.Configs[0];

            _poison = dvConfig.GetBoolean("PoisonReverse", true);
            _everPrint = dvConfig.GetBoolean("EverPrint", false);
            _alwaysPrint = dvConfig.GetBoolean("AlwaysPrint", false);
            highlightPrintText = dvConfig.GetBoolean("HighlightPrint", false);
        }
예제 #3
0
        /// <summary>
        /// Once the algorithm has finished use the information it has stored to update the routing table.
        /// </summary>
        private void UpdateRoutingTable()
        {
            IKeyTable <IMLink> oldTable = ForwardingTable;

            foreach (DijkstraNode target in _confirmed)
            {
                if (target.ID != ID)
                {
                    //Work backwards along the route, starting at the target, until the first hop is found
                    DijkstraNode prev = target;
                    while (prev != null && !Equals(prev.GetPrev(ID)))
                    {
                        prev = prev.GetPrev(ID);
                    }

                    if (prev != null && Links.ContainsKey(prev.ID))
                    {
                        IMLink l = Links[prev.ID];
                        SetRoute(Algorithm, target.ID, l, target.GetDistanceFromRoot(ID));
                        oldTable.Remove(target.ID);
                    }
                }
            }
            //Trigger events for any nodes that can no longer be routed to
            foreach (IMNodeInternal n in KnownNodes)
            {
                if (oldTable.ContainsKey(n.ID))
                {
                    RemoveRoute(Algorithm, n.ID);
                }
            }
        }
 public SandboxControlLink(ILink link, INode from, INode to, SandboxControl control, IKeyTableFactory tableFactory, IPrimFactory primFactory, IPermissions permissions)
     : base(link, from, to, control, permissions)
 {
     _control = control;
     _bufferedChanges = tableFactory.MakeKeyTable<double>();
     _dialog = new Dialog(control.HostPrim, primFactory, LINK_BUTTONS);
     _dialog.ResponseReceived += DialogPressed;
 }
 public SandboxControlLink(ILink link, INode from, INode to, SandboxControl control, IKeyTableFactory tableFactory, IPrimFactory primFactory, IPermissions permissions)
     : base(link, from, to, control, permissions)
 {
     _control                  = control;
     _bufferedChanges          = tableFactory.MakeKeyTable <double>();
     _dialog                   = new Dialog(control.HostPrim, primFactory, LINK_BUTTONS);
     _dialog.ResponseReceived += DialogPressed;
 }
예제 #6
0
        public View(IKeyTableFactory tableFactory, IAsynchQueueFactory queueFactory, IPrimFactory primFactory, IConfigSource config)
            : base(tableFactory, queueFactory)
        {
            _factory          = primFactory;
            _displayingBoards = tableFactory.MakeKeyTable <IEnumerable <UUID> >();
            _moveQ            = queueFactory.MakeQueue();
            _deliverQ         = queueFactory.MakeQueue();
            //_moveQ = new SmartThreadPool(int.MaxValue, 30, 3);

            IConfig viewConfig = config.Configs["View"];

            if (viewConfig == null)
            {
                viewConfig = config.Configs[0];
            }

            _wait           = viewConfig.GetInt("Wait", _wait);
            _waitMultiplier = viewConfig.GetFloat("WaitMultiplier", 5f);
            _displayChannel = viewConfig.GetInt("ListeningChannel", -43);
            _autoUpdate     = viewConfig.GetBoolean("AutoUpdateTables", false);
            int tableResolution = viewConfig.GetInt("TableResolution", -1);

            if (tableResolution > 0)
            {
                VNode.SetTableResolution(tableResolution);
            }

            _moveQ.Start("View Move Queue" /*, viewConfig.GetInt("PacketsPerThread", PACKETS_PER_THREAD)*/);
            _deliverQ.Start("View Deliver Queue");
            //_moveQ.Start();

            VLink.MaxWidth              = viewConfig.GetFloat("maxLinkWidth", VLink.MaxWidth);
            VLink.MinWidth              = viewConfig.GetFloat("minLinkWidth", VLink.MinWidth);
            VPacket.MaxMovesPerUnit     = viewConfig.GetInt("maxNumPacketMovesPerUnit", VPacket.MaxMovesPerUnit);
            VPacket.MinMovesPerUnit     = viewConfig.GetInt("minNumPacketMovesPerUnit", VPacket.MinMovesPerUnit);
            VPacket.DefaultMovesPerUnit = viewConfig.GetInt("defaultNumPacketMovesPerUnit", VPacket.DefaultMovesPerUnit);

            _tickThread = new Thread(() => {
                _cont    = true;
                int wait = (int)(Wait * _waitMultiplier);
                int tick = 0;
                while (_cont)
                {
                    Util.Wait(wait, _cont && wait > 0, this);
                    DateTime start = DateTime.Now;
                    if (_cont && OnTick != null)
                    {
                        OnTick();
                    }
                    wait = (int)((Wait * _waitMultiplier) - DateTime.Now.Subtract(start).TotalMilliseconds);
                    tick++;
                }
            });
            _tickThread.Name = "View Tick Thread";
            _tickThread.Start();

            Logger.Info("View started.");
        }
        public IndividualState(Module.Control control, IKeyTableFactory tableFactory)
        {
            _control = control;

            _state            = new Dictionary <string, string>();
            _selectedEntities = new Dictionary <string, IControlEntity>();
            _toggles          = tableFactory.MakeKeyTable <Dictionary <string, Toggle> >();
            _stateButtons     = tableFactory.MakeKeyTable <List <IButton> >();
        }
        public IndividualState(Module.Control control, IKeyTableFactory tableFactory)
        {
            _control = control;

            _state = new Dictionary<string, string>();
            _selectedEntities = new Dictionary<string, IControlEntity>();
            _toggles = tableFactory.MakeKeyTable<Dictionary<string, Toggle>>();
            _stateButtons = tableFactory.MakeKeyTable<List<IButton>>();
        }
예제 #9
0
        protected AbstractAlgorithmNode(IMNodeInternal node, IKeyTableFactory tableFactory, IConfigSource config)
        {
            AlgCollectionExtension._tableFactory = tableFactory;
            Logger     = LogManager.GetLogger(GetType());
            _node      = node;
            _table     = tableFactory.MakeKeyTable <IMLink>();
            _distances = tableFactory.MakeKeyTable <float>();
            this.RegisterAlgNode();

            Node.OnWeightChange += (link, weight) => WeightChanged(Links[link], IsCurrentAlgorithm && Links[link].Parameters.Get <bool>("Visualise"));
            Node.OnLinkAdded    += (n, link, parameters) => LinkAdded(link, parameters, IsCurrentAlgorithm && parameters.Get <bool>("Visualise"));
            Node.OnLinkRemoved  += (n, link, parameters) => LinkRemoved(link, parameters, IsCurrentAlgorithm && parameters.Get <bool>("Visualise"));
        }
예제 #10
0
        public DijkstraNode(IMNodeInternal node, IKeyTableFactory tableFactory, IAsynchQueue queue, IConfigSource config)
            : base(node, tableFactory, config)
        {
            _queue     = queue;
            _distances = tableFactory.MakeKeyTable <float>();
            _wipRoute  = tableFactory.MakeKeyTable <IMLink>();
            _prev      = tableFactory.MakeKeyTable <DijkstraNode>();

            _confirmed = new LinkedList <DijkstraNode>();
            _tentative = new LinkedList <DijkstraNode>();
            _links     = new LinkedList <IMLink>();

            SetDistanceFromRoot(ID, 0f, null, null);
        }
예제 #11
0
        public MNode(INode node, ForwardDelegate forwardMethod, String defaultAlgorithm, IAlgorithm[] algorithms, IKeyTableFactory tableFactory)
            : base(node)
        {
            _passDownMethod = forwardMethod;
            _tableFactory   = tableFactory;
            _links          = tableFactory.MakeKeyTable <IMLink>();
            _neighbours     = tableFactory.MakeKeyTable <IMNodeInternal>();
            _algorithms     = new Dictionary <string, IAlgorithmNode>();

            foreach (IAlgorithm alg in algorithms)
            {
                IAlgorithmNode algNode = alg.MakeNode(this, SendPacket);
                _algorithms.Add(alg.Name, algNode);
                algNode.OnRouteChange     += RouteChangeListener;
                algNode.IsCurrentAlgorithm = alg.Name.Equals(defaultAlgorithm);
                if (algNode.IsCurrentAlgorithm)
                {
                    _currentAlgorithm = algNode;
                }
            }
            if (_currentAlgorithm == null)
            {
                throw new Exception("Test Node unable to set algorithm. '" + defaultAlgorithm + "' is not a valid algorithm.");
            }
            _currentAlgorithmName = defaultAlgorithm;

            _passDownMethod = forwardMethod;

            OnPacketReceived += (at, p) => {
                IMPacket packet = p as IMPacket;
                if (packet != null && packet.Type == PTypes.data)
                {
                    ReceiveData(packet);
                }
                else if (packet != null && _algorithms.ContainsKey(packet.Algorithm))
                {
                    _algorithms[packet.Algorithm].ProcessPacket(packet);
                }
            };
            _weightDelegate = (id, newWeight) => {
                if (OnWeightChange != null)
                {
                    OnWeightChange(id, newWeight);
                    Logger.Debug(Name + " triggered OnWeightChange for '" + Links[id].Name + "'.");
                }
            };
            _highlightDelegate = () => ResetHighlightAll();
            OnHighlightReset  += _highlightDelegate;
        }
예제 #12
0
        protected AbstractModule(IKeyTableFactory keyTableFactory, IAsynchQueueFactory queueFactory)
        {
            TableFactory = keyTableFactory;
            Logger       = LogManager.GetLogger(GetType());

            _nodes = keyTableFactory.MakeKeyTable <TNode>();
            _links = keyTableFactory.MakeKeyTable <TLink>();

            _neighbours  = keyTableFactory.MakeKeyTable <IKeyTable <TNode> >();
            _connections = keyTableFactory.MakeKeyTable <IKeyTable <TLink> >();

            //_queue = queueFactory.MakeQueue();
            //Queue.Start(GetType().Name + " module queue");
            _queue = queueFactory.SharedQueue;
        }
예제 #13
0
        public OriginalControl(IKeyTableFactory tableFactory, IAsynchQueueFactory queueFactory, IPrimFactory primFactory, IModel model, UUID hostID, IConfigSource config)
            : base(tableFactory, queueFactory)
        {
            _hostPrim = primFactory[hostID];

            _readerMap = new Dictionary <string, UUID>();
            _writerMap = tableFactory.MakeKeyTable <string>();
            _paused    = tableFactory.MakeKeyTable <bool>();

            IConfig controlConfig = config.Configs["Control"];
            IConfig commonConfig  = config.Configs["Common"];

            if (controlConfig == null)
            {
                controlConfig = config.Configs[0];
            }
            if (commonConfig == null)
            {
                commonConfig = config.Configs[0];
            }

            _wait             = commonConfig.GetInt("Wait", 50);
            _userFolder       = controlConfig.Get("UserFolder", ".");
            _recordingEnabled = controlConfig.GetBoolean("RecordingEnabled", false);
            _timing           = controlConfig.GetBoolean("TimedPlayback", true);
            _schemaFile       = controlConfig.GetString("TopologySchema", null);

            _reader = new OpenSimLogReader(_readerMap, model, HostPrim.Pos);
            _reader.MapInstance <IModule>(this);
            _writers = tableFactory.MakeKeyTable <IXmlLogWriter>();

            _factory = primFactory;
            if (_recordingEnabled)
            {
                _modelWriter = new OpenSimLogWriter <IModel>(_writerMap, model, HostPrim.Pos, true, false);
                _model       = _modelWriter.Instance;
                IXmlLogWriter <IModule> baseWriter = new OpenSimLogWriter <IModule>(_writerMap, this, HostPrim.Pos, true);
                _recordingBase = baseWriter.Instance;
                _writers.Add(hostID, baseWriter);
            }
            else
            {
                _model = model;
            }

            Namespace = controlConfig.Get("Namespace", Namespace);
            Logger.Info("Control started.");
        }
예제 #14
0
        public Model(IView view, IKeyTableFactory tableFactory, IAsynchQueueFactory queueFactory, IConfigSource config, params IAlgorithm[] algorithms)
            : base(tableFactory, queueFactory)
        {
            if (algorithms.Length == 0)
            {
                view.Stop();
                throw new Exception("Unable to start model layer, default algorithm " + _currentAlgorithm +
                                    " is not a valid algorithm");
            }

            _knownNodes = tableFactory.MakeKeyTable <IMNodeInternal>();
            _view       = view;
            _algorithms = algorithms;

            IConfig commonConfig = config.Configs["Common"];
            IConfig modelConfig  = config.Configs["Model"];

            if (modelConfig == null)
            {
                modelConfig = config.Configs[0];
            }
            if (commonConfig == null)
            {
                commonConfig = config.Configs[0];
            }

            _wait             = commonConfig.GetInt("Wait", 50);
            _waitMult         = modelConfig.GetInt("WaitMult", 5);
            _currentAlgorithm = modelConfig.GetString("Algorithm", algorithms.First().Name);

            if (_algorithms.Count(alg => alg.Name.Equals(_currentAlgorithm)) == 0)
            {
                _currentAlgorithm = algorithms.First().Name;
                Logger.Debug("Specified Current Algorithm ('" + modelConfig.GetString("Algorithm") + "') invalid. Using '" + _currentAlgorithm + "'.");
            }
            if (!modelConfig.Contains("Algorithm"))
            {
                Logger.Debug("Current Algorithm not specified. Using '" + _currentAlgorithm + "'.");
            }

            Logger.Info("Model started with " + algorithms.Length + " algorithms.");
            foreach (IAlgorithm alg in algorithms)
            {
                Logger.Info(alg.Name + (alg.Name.Equals(_currentAlgorithm) ? " (default)" :""));
            }
        }
예제 #15
0
        public SequenceManager(IModule control, IControlUtil controlUtil, IConfig controlConfig, IPrimFactory factory, IKeyTableFactory tableFactory, IAsynchQueue queue)
            : base(controlConfig)
        {
            _queue       = queue;
            _controlUtil = controlUtil;
            _hostPrim    = controlUtil.HostPrim;

            _readerMap        = new Dictionary <string, UUID>();
            _writerMap        = tableFactory.MakeKeyTable <string>();
            _recordingEnabled = controlConfig.GetBoolean("RecordingEnabled", false);
            _sequenceFolder   = controlConfig.Get(FOLDER_KEY, ".");
            _timing           = controlConfig.GetBoolean("TimedPlayback", true);

            _reader = new OpenSimLogReader(_readerMap, control, _hostPrim.Pos);
            _reader.MapInstance <IModule>(control);
            _writers = tableFactory.MakeKeyTable <IXmlLogWriter>();

            _control = Make <IModule>(new RecordControl(control), true);
        }
예제 #16
0
        public MNode(INode node, ForwardDelegate forwardMethod, String defaultAlgorithm, IAlgorithm[]algorithms, IKeyTableFactory tableFactory)
            : base(node)
        {
            _passDownMethod = forwardMethod;
            _tableFactory = tableFactory;
            _links = tableFactory.MakeKeyTable<IMLink>();
            _neighbours = tableFactory.MakeKeyTable<IMNodeInternal>();
            _algorithms = new Dictionary<string, IAlgorithmNode>();

            foreach (IAlgorithm alg in algorithms) {
                IAlgorithmNode algNode = alg.MakeNode(this, SendPacket);
                _algorithms.Add(alg.Name, algNode);
                algNode.OnRouteChange += RouteChangeListener;
                algNode.IsCurrentAlgorithm = alg.Name.Equals(defaultAlgorithm);
                if (algNode.IsCurrentAlgorithm)
                    _currentAlgorithm = algNode;
            }
            if (_currentAlgorithm == null)
                throw new Exception("Test Node unable to set algorithm. '" + defaultAlgorithm + "' is not a valid algorithm.");
            _currentAlgorithmName = defaultAlgorithm;

            _passDownMethod = forwardMethod;

            OnPacketReceived += (at, p) => {
                IMPacket packet = p as IMPacket;
                if (packet != null && packet.Type == PTypes.data)
                    ReceiveData(packet);
                else if (packet != null && _algorithms.ContainsKey(packet.Algorithm))
                    _algorithms[packet.Algorithm].ProcessPacket(packet);
            };
            _weightDelegate = (id, newWeight) => {
                if (OnWeightChange != null) {
                    OnWeightChange(id, newWeight);
                    Logger.Debug(Name + " triggered OnWeightChange for '" + Links[id].Name + "'.");
                }
            };
            _highlightDelegate = () => ResetHighlightAll();
            OnHighlightReset += _highlightDelegate;
        }
 public OpenSimLogWriter(IKeyTable <string> factory, TToLog instance, Vector3 hostPos, bool ignoreReturn = false, bool recursive = true)
     : base(instance, ignoreReturn, recursive)
 {
     _factory = factory;
     _hostPos = hostPos;
 }
예제 #18
0
        public DijkstraNode(IMNodeInternal node, IKeyTableFactory tableFactory, IAsynchQueue queue, IConfigSource config)
            : base(node, tableFactory, config)
        {
            _queue = queue;
            _distances = tableFactory.MakeKeyTable<float>();
            _wipRoute = tableFactory.MakeKeyTable<IMLink>();
            _prev = tableFactory.MakeKeyTable<DijkstraNode>();

            _confirmed = new LinkedList<DijkstraNode>();
            _tentative = new LinkedList<DijkstraNode>();
            _links = new LinkedList<IMLink>();

            SetDistanceFromRoot(ID, 0f, null, null);
        }
예제 #19
0
        public MRMPrimFactory(IHost host, IWorld world, IAsynchQueueFactory queueFactory, IKeyTableFactory tableFactory, IConfigSource config, UUID hostID)
        {
            IConfig mrmConfig = config.Configs["MRM"];

            if (mrmConfig == null)
            {
                mrmConfig = config.Configs[0];
            }

            _world = world;
            _host  = host;

            _logger        = LogManager.GetLogger(typeof(MRMPrimFactory));
            _prims         = new MapKeyTable <IPrim>();
            _createdPrims  = new List <UUID>();
            _freeObjects   = new Dictionary <UUID, IObject>();
            _chatListeners = new Dictionary <int, List <ChatDelegate> >();

            //_factoryQ = queueFactory.MakeQueue();
            _factoryQ = queueFactory.SharedQueue;

            CheckWait = mrmConfig.GetInt("CheckWait", CheckWait);
            _recycle  = mrmConfig.GetBoolean("Recycle", true);

            try {
                _hostPrim = new MRMPrim(hostID, this);
            } catch (Exception e) {
                _hostPrim = null;
                throw new Exception("Problem getting Host Prim: " + e.Message + "\n" + e.StackTrace);
            }

            _chatListener += (sender, args) => {
                _world = sender;
                if (_chatListeners.ContainsKey(args.Channel))
                {
                    lock (_chatListeners)
                        foreach (var listener in _chatListeners[args.Channel])
                        {
                            listener(args.Sender.Name, args.Sender.GlobalID, args.Text, args.Channel);
                        }
                }
                if (OnChat != null)
                {
                    OnChat(args.Sender.Name, args.Sender.GlobalID, args.Text, args.Channel);
                }
            };
            _world.OnChat += _chatListener;

            _checkThread      = new Thread(CheckThread);
            _checkThread.Name = "MRMPrimFactory Check Thread";
            _checkThread.Start();



            _linkButtons = new Dictionary <uint, TouchButton>();
            _chatButtons = new Dictionary <UUID, TouchButton>();

            _knowButtons = new Dictionary <string, HashSet <UUID> >();
            _pingChannel = mrmConfig.GetInt("PingChannel", -50);
            _ping        = mrmConfig.Get("ButtonPing", "Ping");
            _pingAck     = mrmConfig.Get("ButtonPingAck", "Pong");
            _chanAck     = mrmConfig.Get("ButtonChannelAck", "ACK");
            InitTouchButtons();
        }
예제 #20
0
        /// <summary>
        /// Finds the shortest route to a target.
        ///
        /// To start with can be in one of two states:
        /// A: No route known
        /// B: There is a route known
        ///
        /// Can finish in one of four states
        /// 1. There was no route originally and one has been found
        /// 2. There is a new, shorter route along a different link
        /// 3. The target can no longer be reached but used to be reachable
        /// 4. The original route is still shortest but is now a different length
        /// 5. The original route is no longer available but a new route was found
        /// 6. The original route is still shortest and has not changed
        /// 7. The target was not reachable before and is still not reachable
        ///
        /// 1 = Update distance vector, broadcast update, trigger routing table changed event
        /// 2 = Update distance vector, broadcast update, trigger routing table changed event
        /// 3 = Update distance vector, broadcast update, trigger routing table changed event
        /// 4 = Update distance vector, broadcast update, trigger routing table changed event
        /// 5 = Update distance vector, broadcast update, trigger routing table changed event
        /// 6 = No events triggered
        /// 7 = No events triggered
        /// </summary>
        /// <param name="targetNode"></param>
        /// <returns></returns>
        private bool findShortestPath(IMNodeInternal targetNode, List <string> changes)
        {
            UUID target = targetNode.ID;

            //oldDist == null indicates initial state A, otherwise initial state B.
            Distance oldDist;

            lock (distanceVector)
                oldDist = distanceVector.ContainsKey(target) ? distanceVector[target].copy() : null;

            IKeyTable <DistanceVector> tmpNeighbours = neighbourVectors.Copy();

            IMLink link = null;
            float  dist = float.MaxValue;

            if (oldDist != null && oldDist.Link.OtherEnd(ID).Equals(target) && Links.ContainsKey(target))
            {
                //If there was an old route and target is a neighbour and the link was the link between them use the weight of that link as the starting weight
                link = Links[target];
                dist = link.Weight;
            }
            else if (oldDist != null && tmpNeighbours.ContainsKey(oldDist.Hop.ID) && tmpNeighbours[oldDist.Hop.ID].ContainsKey(target) && tmpNeighbours[oldDist.Hop.ID][target].Dist > 0f)
            {
                //If there was an old route and it involved routing via a neighbour and that neighbour can still route then take the starting weight as the distance to the neighbour + the distance from the neighbour to the target
                link = Links[oldDist.Hop.ID];
                dist = tmpNeighbours[oldDist.Hop.ID][target].Dist + link.Weight;
            }

            //Check every neighbour to see if the weight of the link to that neighbour + the distance the neighbour can achieve to the target is shorter     .
            foreach (var neighbour in Neighbours)
            {
                var neighbourLink   = Links[neighbour.ID];
                var neighbourVector = tmpNeighbours.ContainsKey(neighbour.ID) && tmpNeighbours[neighbour.ID].ContainsKey(target) ? tmpNeighbours[neighbour.ID][target] : null;
                var neighbourDist   = neighbourVector != null ? neighbourLink.Weight + neighbourVector.Dist : float.MaxValue;
                //Neighbour vector distance of 0 or less indicates poison reverse or a link to itself
                //Also checks to see if the link at the other end is the neighbour and whether the weight of the link is less than the current distance
                if ((neighbourVector != null && neighbourVector.Dist > 0 && neighbourDist < dist) ||
                    neighbour.Equals(targetNode) && neighbourLink.Weight < dist)
                {
                    link = neighbourLink;
                    dist = neighbour.Equals(targetNode) ? link.Weight : neighbourDist;
                }
            }

            if (link == null && oldDist == null)
            {
                //Case 5 + 6
                return(false);
            }
            if (link != null && oldDist == null)
            {
                //1. There was no route originally and one has been found
                UpdateRoutes(targetNode, link.OtherEnd(Node), link, dist);
                changes.Add("Distance Vector added route to " + targetNode.Name + " via " + link.OtherEnd(Node).Name + " with distance " + Math.Round(dist, 2) + ".");
            }
            else if (link == null && oldDist != null)
            {
                //3. The target can no longer be reached but used to be reachable
                lock (distanceVector) {
                    distanceVector.Remove(target);
                    RemoveRoute(DV.DV_NAME, target);
                    changes.Add("Distance Vector removed route to " + targetNode.Name + ". " + oldDist.Hop.Name + " is no longer a valid first hop and no other route was found.");
                }
            }
            else if (oldDist != null && !link.Equals(oldDist.Link))
            {
                //2. There is a new, shorter route along a different link
                UpdateRoutes(targetNode, link.OtherEnd(Node), link, dist);
                changes.Add("Distance Vector changed route to " + targetNode.Name + " from " + oldDist.Hop.Name + " to " + link.OtherEnd(Node).Name + " with distance " + Math.Round(dist, 2) + ".");
            }
            else if (oldDist != null && link.Equals(oldDist.Link) && dist != oldDist.Dist)
            {
                //4. The original route is still shortest but is now a different length
                UpdateRoutes(targetNode, link.OtherEnd(Node), link, dist);
                changes.Add("Distance Vector changed weight of route to " + targetNode.Name + " from " + Math.Round(oldDist.Dist, 2) + " to " + Math.Round(dist, 2) + ".");
            }
            else
            {
                return(false);
            }

            return(true);
        }