private void ApplyRestrictionsToAllSegments(int?sortedLaneIndex = null)
        {
            NetInfo         selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info;
            List <object[]> selectedSortedLanes = TrafficManagerTool.GetSortedVehicleLanes(SelectedSegmentId, selectedSegmentInfo, null);

            LinkedList <ushort> nodesToProcess    = new LinkedList <ushort>();
            HashSet <ushort>    processedNodes    = new HashSet <ushort>();
            HashSet <ushort>    processedSegments = new HashSet <ushort>();

            processedSegments.Add(SelectedSegmentId);

            ushort selectedStartNodeId = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].m_startNode;
            ushort selectedEndNodeId   = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].m_endNode;

            if (selectedStartNodeId != 0)
            {
                nodesToProcess.AddFirst(selectedStartNodeId);
            }
            if (selectedEndNodeId != 0)
            {
                nodesToProcess.AddFirst(selectedEndNodeId);
            }

            while (nodesToProcess.First != null)
            {
                ushort nodeId = nodesToProcess.First.Value;
                nodesToProcess.RemoveFirst();
                processedNodes.Add(nodeId);

                if (Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].CountSegments() > 2)
                {
                    continue;                     // junction. stop.
                }
                // explore segments at node
                for (var s = 0; s < 8; s++)
                {
                    var segmentId = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].GetSegment(s);

                    if (segmentId <= 0 || processedSegments.Contains(segmentId))
                    {
                        continue;
                    }
                    processedSegments.Add(segmentId);

                    NetInfo         segmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].Info;
                    List <object[]> sortedLanes = TrafficManagerTool.GetSortedVehicleLanes(segmentId, segmentInfo, null);

                    if (sortedLanes.Count == selectedSortedLanes.Count)
                    {
                        // number of lanes matches selected segment
                        int sli = -1;
                        for (int i = 0; i < sortedLanes.Count; ++i)
                        {
                            ++sli;

                            if (sortedLaneIndex != null && sli != sortedLaneIndex)
                            {
                                continue;
                            }

                            object[] selectedLaneData = selectedSortedLanes[i];
                            object[] laneData         = sortedLanes[i];

                            uint         selectedLaneId    = (uint)selectedLaneData[0];
                            uint         selectedLaneIndex = (uint)selectedLaneData[2];
                            NetInfo.Lane selectedLaneInfo  = segmentInfo.m_lanes[selectedLaneIndex];

                            uint         laneId    = (uint)laneData[0];
                            uint         laneIndex = (uint)laneData[2];
                            NetInfo.Lane laneInfo  = segmentInfo.m_lanes[laneIndex];

                            // apply restrictions of selected segment & lane
                            VehicleRestrictionsManager.SetAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo, laneId, VehicleRestrictionsManager.GetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, selectedLaneIndex, selectedLaneInfo));
                        }

                        // add nodes to explore
                        ushort startNodeId = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startNode;
                        ushort endNodeId   = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endNode;

                        if (startNodeId != 0 && !processedNodes.Contains(startNodeId))
                        {
                            nodesToProcess.AddFirst(startNodeId);
                        }
                        if (endNodeId != 0 && !processedNodes.Contains(endNodeId))
                        {
                            nodesToProcess.AddFirst(endNodeId);
                        }
                    }
                }
            }
        }
        private void _guiVehicleRestrictionsWindow(int num)
        {
            if (GUILayout.Button(Translation.GetString("Invert")))
            {
                // invert pattern

                NetInfo         selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info;
                List <object[]> sortedLanes         = TrafficManagerTool.GetSortedVehicleLanes(SelectedSegmentId, selectedSegmentInfo, null);        // TODO does not need to be sorted, but every lane should be a vehicle lane
                foreach (object[] laneData in sortedLanes)
                {
                    uint         laneId    = (uint)laneData[0];
                    uint         laneIndex = (uint)laneData[2];
                    NetInfo.Lane laneInfo  = selectedSegmentInfo.m_lanes[laneIndex];

                    ExtVehicleType baseMask = ExtVehicleType.None;
                    if (VehicleRestrictionsManager.IsRoadLane(laneInfo))
                    {
                        baseMask = ExtVehicleType.RoadVehicle;
                    }
                    else if (VehicleRestrictionsManager.IsRailLane(laneInfo))
                    {
                        baseMask = ExtVehicleType.RailVehicle;
                    }

                    if (baseMask == ExtVehicleType.None)
                    {
                        continue;
                    }

                    ExtVehicleType allowedTypes = VehicleRestrictionsManager.GetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo);
                    allowedTypes = ~allowedTypes & baseMask;
                    VehicleRestrictionsManager.SetAllowedVehicleTypes(SelectedSegmentId, laneIndex, laneId, allowedTypes);
                }
            }

            GUILayout.BeginHorizontal();
            if (GUILayout.Button(Translation.GetString("Allow_all_vehicles")))
            {
                // allow all vehicle types

                NetInfo         segmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info;
                List <object[]> sortedLanes = TrafficManagerTool.GetSortedVehicleLanes(SelectedSegmentId, segmentInfo, null);                // TODO does not need to be sorted, but every lane should be a vehicle lane
                foreach (object[] laneData in sortedLanes)
                {
                    uint         laneId    = (uint)laneData[0];
                    uint         laneIndex = (uint)laneData[2];
                    NetInfo.Lane laneInfo  = segmentInfo.m_lanes[laneIndex];

                    ExtVehicleType baseMask = ExtVehicleType.None;
                    if (VehicleRestrictionsManager.IsRoadLane(laneInfo))
                    {
                        baseMask = ExtVehicleType.RoadVehicle;
                    }
                    else if (VehicleRestrictionsManager.IsRailLane(laneInfo))
                    {
                        baseMask = ExtVehicleType.RailVehicle;
                    }

                    if (baseMask == ExtVehicleType.None)
                    {
                        continue;
                    }

                    VehicleRestrictionsManager.SetAllowedVehicleTypes(SelectedSegmentId, laneIndex, laneId, baseMask);
                }
            }

            if (GUILayout.Button(Translation.GetString("Ban_all_vehicles")))
            {
                // ban all vehicle types

                NetInfo         segmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info;
                List <object[]> sortedLanes = TrafficManagerTool.GetSortedVehicleLanes(SelectedSegmentId, segmentInfo, null);                // TODO does not need to be sorted, but every lane should be a vehicle lane
                foreach (object[] laneData in sortedLanes)
                {
                    uint         laneId    = (uint)laneData[0];
                    uint         laneIndex = (uint)laneData[2];
                    NetInfo.Lane laneInfo  = segmentInfo.m_lanes[laneIndex];

                    ExtVehicleType baseMask = ExtVehicleType.None;
                    if (VehicleRestrictionsManager.IsRoadLane(laneInfo))
                    {
                        baseMask = ExtVehicleType.RoadVehicle;
                    }
                    else if (VehicleRestrictionsManager.IsRailLane(laneInfo))
                    {
                        baseMask = ExtVehicleType.RailVehicle;
                    }

                    if (baseMask == ExtVehicleType.None)
                    {
                        continue;
                    }

                    VehicleRestrictionsManager.SetAllowedVehicleTypes(SelectedSegmentId, laneIndex, laneId, ~baseMask);
                }
            }
            GUILayout.EndHorizontal();

            if (GUILayout.Button(Translation.GetString("Apply_vehicle_restrictions_to_all_road_segments_between_two_junctions")))
            {
                NetInfo         selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info;
                List <object[]> selectedSortedLanes = TrafficManagerTool.GetSortedVehicleLanes(SelectedSegmentId, selectedSegmentInfo, null);

                LinkedList <ushort> nodesToProcess    = new LinkedList <ushort>();
                HashSet <ushort>    processedNodes    = new HashSet <ushort>();
                HashSet <ushort>    processedSegments = new HashSet <ushort>();
                processedSegments.Add(SelectedSegmentId);

                ushort selectedStartNodeId = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].m_startNode;
                ushort selectedEndNodeId   = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].m_endNode;

                if (selectedStartNodeId != 0)
                {
                    nodesToProcess.AddFirst(selectedStartNodeId);
                }
                if (selectedEndNodeId != 0)
                {
                    nodesToProcess.AddFirst(selectedEndNodeId);
                }

                while (nodesToProcess.First != null)
                {
                    ushort nodeId = nodesToProcess.First.Value;
                    nodesToProcess.RemoveFirst();
                    processedNodes.Add(nodeId);

                    if (Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].CountSegments() > 2)
                    {
                        continue;                         // junction. stop.
                    }
                    // explore segments at node
                    for (var s = 0; s < 8; s++)
                    {
                        var segmentId = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].GetSegment(s);

                        if (segmentId <= 0 || processedSegments.Contains(segmentId))
                        {
                            continue;
                        }
                        processedSegments.Add(segmentId);

                        NetInfo         segmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].Info;
                        List <object[]> sortedLanes = TrafficManagerTool.GetSortedVehicleLanes(segmentId, segmentInfo, null);

                        if (sortedLanes.Count == selectedSortedLanes.Count)
                        {
                            // number of lanes matches selected segment
                            for (int i = 0; i < sortedLanes.Count; ++i)
                            {
                                object[] selectedLaneData = selectedSortedLanes[i];
                                object[] laneData         = sortedLanes[i];

                                uint         selectedLaneId    = (uint)selectedLaneData[0];
                                uint         selectedLaneIndex = (uint)selectedLaneData[2];
                                NetInfo.Lane selectedLaneInfo  = segmentInfo.m_lanes[selectedLaneIndex];

                                uint         laneId    = (uint)laneData[0];
                                uint         laneIndex = (uint)laneData[2];
                                NetInfo.Lane laneInfo  = segmentInfo.m_lanes[laneIndex];

                                // apply restrictions of selected segment & lane
                                VehicleRestrictionsManager.SetAllowedVehicleTypes(segmentId, laneIndex, laneId, VehicleRestrictionsManager.GetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, selectedLaneIndex, selectedLaneInfo));
                            }

                            // add nodes to explore
                            ushort startNodeId = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startNode;
                            ushort endNodeId   = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endNode;

                            if (startNodeId != 0 && !processedNodes.Contains(startNodeId))
                            {
                                nodesToProcess.AddFirst(startNodeId);
                            }
                            if (endNodeId != 0 && !processedNodes.Contains(endNodeId))
                            {
                                nodesToProcess.AddFirst(endNodeId);
                            }
                        }
                    }
                }
            }
        }
        private void _guiVehicleRestrictionsWindow(int num)
        {
            if (GUILayout.Button(Translation.GetString("Invert")))
            {
                // invert pattern

                NetInfo         selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info;
                List <object[]> sortedLanes         = TrafficManagerTool.GetSortedVehicleLanes(SelectedSegmentId, selectedSegmentInfo, null);        // TODO does not need to be sorted, but every lane should be a vehicle lane
                foreach (object[] laneData in sortedLanes)
                {
                    uint         laneId    = (uint)laneData[0];
                    uint         laneIndex = (uint)laneData[2];
                    NetInfo.Lane laneInfo  = selectedSegmentInfo.m_lanes[laneIndex];

                    ExtVehicleType baseMask = VehicleRestrictionsManager.GetBaseMask(laneInfo);

                    if (baseMask == ExtVehicleType.None)
                    {
                        continue;
                    }

                    ExtVehicleType allowedTypes = VehicleRestrictionsManager.GetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo);
                    allowedTypes = ~allowedTypes & baseMask;
                    VehicleRestrictionsManager.SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, allowedTypes);
                }
            }

            GUILayout.BeginHorizontal();
            if (GUILayout.Button(Translation.GetString("Allow_all_vehicles")))
            {
                // allow all vehicle types

                NetInfo         selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info;
                List <object[]> sortedLanes         = TrafficManagerTool.GetSortedVehicleLanes(SelectedSegmentId, selectedSegmentInfo, null);        // TODO does not need to be sorted, but every lane should be a vehicle lane
                foreach (object[] laneData in sortedLanes)
                {
                    uint         laneId    = (uint)laneData[0];
                    uint         laneIndex = (uint)laneData[2];
                    NetInfo.Lane laneInfo  = selectedSegmentInfo.m_lanes[laneIndex];

                    ExtVehicleType baseMask = VehicleRestrictionsManager.GetBaseMask(laneInfo);

                    if (baseMask == ExtVehicleType.None)
                    {
                        continue;
                    }

                    VehicleRestrictionsManager.SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, baseMask);
                }
            }

            if (GUILayout.Button(Translation.GetString("Ban_all_vehicles")))
            {
                // ban all vehicle types

                NetInfo         selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[SelectedSegmentId].Info;
                List <object[]> sortedLanes         = TrafficManagerTool.GetSortedVehicleLanes(SelectedSegmentId, selectedSegmentInfo, null);        // TODO does not need to be sorted, but every lane should be a vehicle lane
                foreach (object[] laneData in sortedLanes)
                {
                    uint         laneId    = (uint)laneData[0];
                    uint         laneIndex = (uint)laneData[2];
                    NetInfo.Lane laneInfo  = selectedSegmentInfo.m_lanes[laneIndex];

                    VehicleRestrictionsManager.SetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, laneIndex, laneInfo, laneId, ExtVehicleType.None);
                }
            }
            GUILayout.EndHorizontal();

            if (GUILayout.Button(Translation.GetString("Apply_vehicle_restrictions_to_all_road_segments_between_two_junctions")))
            {
                ApplyRestrictionsToAllSegments();
            }
        }