private void OpenItem_OnClick(object sender, RoutedEventArgs e)
        {
            var ofd = new OpenFileDialog()
            {
                Filter           = "Bundle Files|*.BUN;*.BIN|All Files|*.*",
                Multiselect      = true,
                RestoreDirectory = true,
                CheckFileExists  = true,
                CheckPathExists  = true
            };

            if (ofd.ShowDialog() == true)
            {
                _game = GameDetector.Game.Unknown;
                var canContinue = true;
                var fileList    = ofd.FileNames.ToList();

                Title = $"NFS Viewer v{Assembly.GetExecutingAssembly().GetName().Version}";

                foreach (var fileName in fileList.ToList())
                {
                    var fullDirectory = Path.GetDirectoryName(fileName);

                    if (fullDirectory == null)
                    {
                        throw new NullReferenceException("fullDirectory == null");
                    }

                    var parentDirectory = Directory.GetParent(fullDirectory);

                    if (string.Equals("CARS", parentDirectory.Name, StringComparison.CurrentCultureIgnoreCase))
                    {
                        var texPath = Path.Combine(parentDirectory.FullName, "TEXTURES.BIN");
                        if (!fileList.Contains(texPath))
                        {
                            fileList.Add(texPath);
                        }
                        parentDirectory = Directory.GetParent(parentDirectory.FullName);
                    }
                    else if (string.Equals("FRONTEND", parentDirectory.Name, StringComparison.CurrentCultureIgnoreCase))
                    {
                        parentDirectory = Directory.GetParent(parentDirectory.FullName);
                    }
                    else if (string.Equals("TRACKS", parentDirectory.Name, StringComparison.CurrentCultureIgnoreCase))
                    {
                        parentDirectory = Directory.GetParent(parentDirectory.FullName);
                    }

                    var detectedGame = GameDetector.DetectGame(parentDirectory.FullName);

                    if (detectedGame != GameDetector.Game.World &&
                        detectedGame != GameDetector.Game.MostWanted &&
                        detectedGame != GameDetector.Game.Carbon &&
                        detectedGame != GameDetector.Game.ProStreet &&
                        detectedGame != GameDetector.Game.Underground &&
                        detectedGame != GameDetector.Game.Underground2 &&
                        detectedGame != GameDetector.Game.Undercover)
                    {
                        MessageUtil.ShowError("Unsupported game!");
                        canContinue = false;
                        break;
                    }

                    if (_game != GameDetector.Game.Unknown && _game != detectedGame)
                    {
                        MessageUtil.ShowError("Don't mess with me like this");
                        canContinue = false;
                        break;
                    }

                    _game = detectedGame;
                }

                if (!canContinue)
                {
                    MessageUtil.ShowError("Cannot open files.");
                    return;
                }

                Log.PushSimple(LogModel.LogLevel.Info, $"Loading {fileList.Count} file(s) in {_game} mode");

                // Data cleanup
                Containers.Clear();
                RenderManager.Reset();
                // RenderManager.Instance.Reset();
                AssetRegistry.Instance.Reset();

                foreach (var file in fileList)
                {
                    var stopwatch = new Stopwatch();
                    var cm        = new ChunkManager(_game);

                    stopwatch.Start();
                    cm.Read(file);
                    stopwatch.Stop();

                    Log.PushSimple(LogModel.LogLevel.Info, $"Loaded [{file}] in {stopwatch.ElapsedMilliseconds}ms");

                    var resources = cm.Chunks.Where(c => c.Resource != null).Select(c => c.Resource).ToList();

                    var container = new FileContainer
                    {
                        FileName   = Path.GetFileName(file),
                        InnerFiles = new ObservableCollection <FileAssetContainer>(),
                        Assets     = new ObservableCollection <FileAssetContainer>(resources.Select(r =>
                        {
                            FileAssetContainer fac = new NullAsset();

                            switch (r)
                            {
                            case TexturePack tpk:
                                fac = new TexturePackAsset
                                {
                                    Resource  = tpk,
                                    SubAssets = new ObservableCollection <FileAssetContainer>()
                                };

                                foreach (var texture in tpk.Textures.OrderBy(t => t.Name))
                                {
                                    fac.SubAssets.Add(new TextureAsset
                                    {
                                        Resource   = texture,
                                        IsSelected = false
                                    });
                                }

                                break;

                            case SolidList solidList:
                                fac = new SolidListAsset
                                {
                                    Resource  = solidList,
                                    SubAssets = new ObservableCollection <FileAssetContainer>()
                                };

                                foreach (var solidObject in solidList.Objects.OrderBy(o => o.Name))
                                {
                                    fac.SubAssets.Add(new SolidObjectAsset
                                    {
                                        Resource   = solidObject,
                                        IsSelected = false
                                    });
                                }


                                break;
                            }

                            return(fac);
                        }))
                    };

                    Containers.Add(container);
                }
            }
        }
        private void OpenMapItem_OnClick(object sender, RoutedEventArgs e)
        {
            var openFolder = new OpenFileDialog()
            {
                Filter           = "Bundle Files|*.BUN;*.BIN|All Files|*.*",
                RestoreDirectory = true,
                CheckFileExists  = true,
                CheckPathExists  = true
            };

            if (openFolder.ShowDialog() == true)
            {
                var fileName      = openFolder.FileName;
                var fullDirectory = new DirectoryInfo(fileName).Parent;

                if (fullDirectory?.Name.ToLower() != "tracks" &&
                    fullDirectory?.Name.ToLower() != "trackshigh")
                {
                    MessageUtil.ShowError("Looks like you're using the wrong menu command...");
                    return;
                }

                var parentDirectory = fullDirectory.Parent;

                if (parentDirectory != null)
                {
                    var game = _game = GameDetector.DetectGame(parentDirectory.FullName);

                    if (game == GameDetector.Game.Unknown)
                    {
                        MessageUtil.ShowError("Cannot determine installed game.");
                        return;
                    }

                    Log.PushSimple(LogModel.LogLevel.Info, $"Loading [{fileName}] in {game} mode");

                    GameBundleManager gbm;

                    switch (game)
                    {
                    case GameDetector.Game.MostWanted:
                    {
                        gbm = new MostWantedManager();
                        break;
                    }

                    case GameDetector.Game.Carbon:
                    {
                        gbm = new CarbonManager();
                        break;
                    }

                    case GameDetector.Game.ProStreet:
                    case GameDetector.Game.ProStreetTest:
                    {
                        gbm = new ProStreetManager();
                        break;
                    }

                    case GameDetector.Game.Undercover:
                    {
                        gbm = new UndercoverManager();
                        break;
                    }

                    case GameDetector.Game.World:
                    {
                        gbm = new World15Manager();
                        break;
                    }

                    default:
                        throw new ArgumentOutOfRangeException(nameof(game), game, "Invalid game!");
                    }

                    Containers.Clear();
                    //MainVisual.Children.Clear();
                    // RenderManager.Instance.Reset();
                    AssetRegistry.Instance.Reset();

                    LocationBundle bundle;

                    try
                    {
                        bundle = gbm.ReadLocationBundle(fileName);
                    }
                    catch (Exception)
                    {
                        MessageUtil.ShowError("This is not a map file.");
                        return;
                    }

                    //var bundle = gbm.ReadLocationBundle(fileName);
                    var rootContainer = new FileContainer
                    {
                        FileName = fileName,
                        Assets   = new ObservableCollection <FileAssetContainer>()
                    };

                    BinaryReader masterStream = null;

                    if (game != GameDetector.Game.World)
                    {
                        masterStream = new BinaryReader(
                            File.OpenRead(
                                Path.Combine(fullDirectory.FullName, $"STREAM{bundle.Name}.BUN")));
                    }

                    if (game == GameDetector.Game.ProStreet &&
                        (string.Equals(bundle.Name.ToLower(), "l6r_lodtest") ||
                         string.Equals(bundle.Name.ToLower(), "l6r_lighting") ||
                         string.Equals(bundle.Name.ToLower(), "l6r_nis") ||
                         string.Equals(bundle.Name.ToLower(), "l6r_testtrack")))
                    {
                        game = GameDetector.Game.ProStreetTest;
                    }

                    var stopwatch = new Stopwatch();
                    var cm        = new ChunkManager(game);
                    stopwatch.Start();

                    foreach (var section in bundle.Sections.OrderBy(s => s.Number))
                    {
                        cm.Reset();

                        var sectionContainer = new SectionContainer
                        {
                            Section   = section,
                            SubAssets = new ObservableCollection <FileAssetContainer>()
                        };

                        // NFS:World loading requires creation of independent file streams
                        if (section is WorldStreamSection wss)
                        {
                            var computedPath = Path.Combine(fullDirectory.FullName,
                                                            wss.FragmentFileId == 0
                                    ? $"STREAM{bundle.Name}_{wss.Number}.BUN"
                                    : $"STREAM{bundle.Name}_0x{wss.FragmentFileId:X8}.BUN");
                            cm.Read(computedPath);
                        }
                        else
                        {
                            if (masterStream != null)
                            {
                                masterStream.BaseStream.Position = section.Offset;

                                var sectionData = masterStream.ReadBytes((int)section.Size);

                                using (var br = new BinaryReader(new MemoryStream(sectionData)))
                                {
                                    cm.Read(br);
                                }
                            }
                        }

                        var resources = cm.Chunks.Where(c => c.Resource != null).Select(c => c.Resource).ToList();

                        sectionContainer.SubAssets = new ObservableCollection <FileAssetContainer>(resources.Select(r =>
                        {
                            FileAssetContainer fac = new NullAsset();

                            switch (r)
                            {
                            case TexturePack tpk:
                                fac = new TexturePackAsset
                                {
                                    Resource  = tpk,
                                    SubAssets = new ObservableCollection <FileAssetContainer>()
                                };

                                foreach (var texture in tpk.Textures.OrderBy(t => t.Name))
                                {
                                    fac.SubAssets.Add(new TextureAsset
                                    {
                                        Resource   = texture,
                                        IsSelected = false
                                    });
                                }

                                break;

                            case SolidList solidList:
                                fac = new SolidListAsset
                                {
                                    Resource  = solidList,
                                    SubAssets = new ObservableCollection <FileAssetContainer>()
                                };

                                foreach (var solidObj in solidList.Objects.OrderBy(o => o.Name))
                                {
                                    fac.SubAssets.Add(new SolidObjectAsset
                                    {
                                        Resource   = solidObj,
                                        IsSelected = false
                                    });
                                }

                                break;
                            }

                            return(fac);
                        }));

                        rootContainer.Assets.Add(sectionContainer);
                    }

                    stopwatch.Stop();

                    Log.PushSimple(LogModel.LogLevel.Info, $"Loaded {fileName} [{stopwatch.ElapsedMilliseconds}ms]");

                    Containers.Add(rootContainer);

                    masterStream?.Dispose();

                    Title = $"NFS Viewer v{Assembly.GetExecutingAssembly().GetName().Version} - [{fileName} ({game})]";

                    RenderManager.Reset();
                }
            }
        }