public bool Overlaps(WirelessPacketTransmission otherPacket)
 {
     return(!(StartTime > otherPacket.EndTime || EndTime < otherPacket.StartTime));
 }
        internal void NodeSendPacket(SimulatedNode n, object packet, double preDelay)
        {
            WirelessPacket wp = new WirelessPacket()
            {
                StartTime = CurrentTime + preDelay, Origin = n, PacketContents = packet
            };

            // Compute how long the packet is being transmitted for
            double transmitSpeed = 2000000;
            int    packetBits    = 18 * 8;

            double packetTime = packetBits / (transmitSpeed * n.DeviceTimingSkew);

            wp.EndTime = wp.StartTime + packetTime;

            n.PastEvents.Append(new SimulationEvent(CurrentTime, n, EventType.Packet, wp, end: wp.EndTime));

            // Find nodes that are in range
            foreach (var sn in SimulationNodes)
            {
                // For each node,
                // Determine whether the node is listening when the packet starts
                if (sn.Node == n)
                {
                    continue;               // Don't send to self.
                }
                // Future: deal with Z differences
                Vector v        = new Vector(sn.NetworkNode.X - n.SourceNode.X, sn.NetworkNode.Y - n.SourceNode.Y);
                double distance = v.Length;
                if (distance > Network.BaseTransmitRange)
                {
                    continue;                                      // Node out of range.
                }
                const double TransmitPropogationSpeed = 300000000; // Speed of RF propogation in air (Close enough)

                WirelessPacketTransmission t = new WirelessPacketTransmission()
                {
                    Packet         = wp,
                    Receiver       = sn.Node,
                    ReceiveSuccess = true,
                    SignalLevel    = 0,
                    WirelessDelay  = distance / TransmitPropogationSpeed
                };

                // Add a random spike noise check to occasionally drop the packet regardless of other factors.
                double randomNoiseChance = 0.01; // 1% of packets drop due to random environmental noise
                if (NextRandom() <= randomNoiseChance)
                {
                    t.ReceiveSuccess = false;
                }

                // Assign a "received signal level" to this packet, and check against a random noise floor (some packets will not be received due to environmental factors)
                // Signal level can be attenuated by walls in the future, and can be used for overlap checks.

                // for now, give signal level between 0 (distance 0) and -80 (distance full)
                t.SignalLevel = 0 - 80 * (distance / Network.BaseTransmitRange);

                // Seperately randomly drop packets based on distance.
                if (NextRandom() < (distance / Network.BaseTransmitRange) * 0.7)
                {
                    // 70% chance to fail receive at max range.
                    t.ReceiveSuccess = false;
                }

                // Check whether this packet transmit window overlaps other packets, if so drop both packets (for now)
                foreach (var otherPacket in sn.Node.InFlightPackets)
                {
                    if (t.Overlaps(otherPacket))
                    {
                        t.ReceiveSuccess           = false;
                        t.Collision                = true;
                        otherPacket.ReceiveSuccess = false;
                        otherPacket.Collision      = true;
                    }
                }

                // Check whether the target node is receiving at time of packet start
                // Note: this actually uses the current time (ignores air propogation time, which is negligible)
                if (!NodeIsReceiving(sn.Node))
                {
                    // Node is not receiving, would miss the packet.
                    t.ReceiveSuccess = false;
                }

                // Queue this pending packet (end transmission, and in node pending list)
                PendingEvents.Insert(new SimulationEvent(t.EndTime, sn.Node, EventType.PacketComplete, t));
                sn.Node.InFlightPackets.Add(t);
            }
        }