<commit_before>﻿// Copyright (c) ppy Pty Ltd <<EMAIL>>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Screens;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.GameTypes;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Multi.Match.Components;
using osu.Game.Screens.Multi.Play;
using osu.Game.Screens.Select;
using PlaylistItem = osu.Game.Online.Multiplayer.PlaylistItem;

namespace osu.Game.Screens.Multi.Match
{
    public class MatchSubScreen : MultiplayerSubScreen, IPreviewTrackOwner
    {
        public override bool DisallowExternalBeatmapRulesetChanges => true;

        public override string Title { get; }

        public override string ShortTitle => "room";

        [Resolved(typeof(Room), nameof(Room.RoomID))]
        private Bindable<int?> roomId { get; set; }

        [Resolved(typeof(Room), nameof(Room.Name))]
        private Bindable<string> name { get; set; }

        [Resolved(typeof(Room), nameof(Room.Type))]
        private Bindable<GameType> type { get; set; }

        [Resolved(typeof(Room))]
        protected BindableList<PlaylistItem> Playlist { get; private set; }

        [Resolved(typeof(Room))]
        protected Bindable<PlaylistItem> CurrentItem { get; private set; }

        [Resolved]
        private BeatmapManager beatmapManager { get; set; }

        [Resolved]
        private PreviewTrackManager previewTrackManager { get; set; }

        [Resolved(CanBeNull = true)]
        private OsuGame game { get; set; }

        private MatchLeaderboard leaderboard;

        public MatchSubScreen(Room room)
        {
            Title = room.RoomID.Value == null ? "New room" : room.Name.Value;
        }

        [BackgroundDependencyLoader]
        private void load()
        {
            MatchChatDisplay chat;
            Components.Header header;
            Info info;
            GridContainer bottomRow;
            MatchSettingsOverlay settings;

            InternalChildren = new Drawable[]
            {
                new GridContainer
                {
                    RelativeSizeAxes = Axes.Both,
                    Content = new[]
                    {
                        new Drawable[]
                        {
                            header = new Components.Header
                            {
                                Depth = -1,
                                RequestBeatmapSelection = () =>
                                {
                                    this.Push(new MatchSongSelect
                                    {
                                        Selected = item =>
                                        {
                                            Playlist.Clear();
                                            Playlist.Add(item);
                                        }
                                    });
                                }
                            }
                        },
                        new Drawable[] { info = new Info { OnStart = onStart } },
                        new Drawable[]
                        {
                            bottomRow = new GridContainer
                            {
                                RelativeSizeAxes = Axes.Both,
                                Content = new[]
                                {
                                    new Drawable[]
                                    {
                                        leaderboard = new MatchLeaderboard
                                        {
                                            Padding = new MarginPadding
                                            {
                                                Left = 10 + HORIZONTAL_OVERFLOW_PADDING,
                                                Right = 10,
                                                Vertical = 10,
                                            },
                                            RelativeSizeAxes = Axes.Both
                                        },
                                        new Container
                                        {
                                            Padding = new MarginPadding
                                            {
                                                Left = 10,
                                                Right = 10 + HORIZONTAL_OVERFLOW_PADDING,
                                                Vertical = 10,
                                            },
                                            RelativeSizeAxes = Axes.Both,
                                            Child = chat = new MatchChatDisplay
                                            {
                                                RelativeSizeAxes = Axes.Both
                                            }
                                        },
                                    },
                                },
                            }
                        },
                    },
                    RowDimensions = new[]
                    {
                        new Dimension(GridSizeMode.AutoSize),
                        new Dimension(GridSizeMode.AutoSize),
                        new Dimension(GridSizeMode.Distributed),
                    }
                },
                new Container
                {
                    RelativeSizeAxes = Axes.Both,
                    Padding = new MarginPadding { Top = Components.Header.HEIGHT },
                    Child = settings = new MatchSettingsOverlay { RelativeSizeAxes = Axes.Both },
                },
            };

            header.Tabs.Current.BindValueChanged(tab =>
            {
                const float fade_duration = 500;

                var settingsDisplayed = tab.NewValue is SettingsMatchPage;

                header.ShowBeatmapPanel.Value = !settingsDisplayed;
                settings.State.Value = settingsDisplayed ? Visibility.Visible : Visibility.Hidden;
                info.FadeTo(settingsDisplayed ? 0 : 1, fade_duration, Easing.OutQuint);
                bottomRow.FadeTo(settingsDisplayed ? 0 : 1, fade_duration, Easing.OutQuint);
            }, true);

            chat.Exit += () =>
            {
                if (this.IsCurrentScreen())
                    this.Exit();
            };

            beatmapManager.ItemAdded += beatmapAdded;
        }

        protected override void LoadComplete()
        {
            base.LoadComplete();

            CurrentItem.BindValueChanged(currentItemChanged, true);
        }

        public override bool OnExiting(IScreen next)
        {
            RoomManager?.PartRoom();

            Mods.Value = Array.Empty<Mod>();

            previewTrackManager.StopAnyPlaying(this);

            return base.OnExiting(next);
        }

        /// <summary>
        /// Handles propagation of the current playlist item's content to game-wide mechanisms.
        /// </summary>
        private void currentItemChanged(ValueChangedEvent<PlaylistItem> e)
        {
            // Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info
            var localBeatmap = e.NewValue?.Beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == e.NewValue.Beatmap.OnlineBeatmapID);

            Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
            Mods.Value = e.NewValue?.RequiredMods?.ToArray() ?? Array.Empty<Mod>();

            if (e.NewValue?.Ruleset != null)
                Ruleset.Value = e.NewValue.Ruleset;

            previewTrackManager.StopAnyPlaying(this);
        }

        /// <summary>
        /// Handle the case where a beatmap is imported (and can be used by this match).
        /// </summary>
        private void beatmapAdded(BeatmapSetInfo model) => Schedule(() =><commit_msg>Cull some unnecessary whitespace<commit_after>﻿// Copyright (c) ppy Pty Ltd <<EMAIL>>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Screens;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.GameTypes;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Multi.Match.Components;
using osu.Game.Screens.Multi.Play;
using osu.Game.Screens.Select;
using PlaylistItem = osu.Game.Online.Multiplayer.PlaylistItem;

namespace osu.Game.Screens.Multi.Match
{
    public class MatchSubScreen : MultiplayerSubScreen, IPreviewTrackOwner
    {
        public override bool DisallowExternalBeatmapRulesetChanges => true;

        public override string Title { get; }

        public override string ShortTitle => "room";

        [Resolved(typeof(Room), nameof(Room.RoomID))]
        private Bindable<int?> roomId { get; set; }

        [Resolved(typeof(Room), nameof(Room.Name))]
        private Bindable<string> name { get; set; }

        [Resolved(typeof(Room), nameof(Room.Type))]
        private Bindable<GameType> type { get; set; }

        [Resolved(typeof(Room))]
        protected BindableList<PlaylistItem> Playlist { get; private set; }

        [Resolved(typeof(Room))]
        protected Bindable<PlaylistItem> CurrentItem { get; private set; }

        [Resolved]
        private BeatmapManager beatmapManager { get; set; }

        [Resolved]
        private PreviewTrackManager previewTrackManager { get; set; }

        [Resolved(CanBeNull = true)]
        private OsuGame game { get; set; }

        private MatchLeaderboard leaderboard;

        public MatchSubScreen(Room room)
        {
            Title = room.RoomID.Value == null ? "New room" : room.Name.Value;
        }

        [BackgroundDependencyLoader]
        private void load()
        {
            MatchChatDisplay chat;
            Components.Header header;
            Info info;
            GridContainer bottomRow;
            MatchSettingsOverlay settings;

            InternalChildren = new Drawable[]
            {
                new GridContainer
                {
                    RelativeSizeAxes = Axes.Both,
                    Content = new[]
                    {
                        new Drawable[]
                        {
                            header = new Components.Header
                            {
                                Depth = -1,
                                RequestBeatmapSelection = () =>
                                {
                                    this.Push(new MatchSongSelect
                                    {
                                        Selected = item =>
                                        {
                                            Playlist.Clear();
                                            Playlist.Add(item);
                                        }
                                    });
                                }
                            }
                        },
                        new Drawable[] { info = new Info { OnStart = onStart } },
                        new Drawable[]
                        {
                            bottomRow = new GridContainer
                            {
                                RelativeSizeAxes = Axes.Both,
                                Content = new[]
                                {
                                    new Drawable[]
                                    {
                                        leaderboard = new MatchLeaderboard
                                        {
                                            Padding = new MarginPadding
                                            {
                                                Left = 10 + HORIZONTAL_OVERFLOW_PADDING,
                                                Right = 10,
                                                Vertical = 10,
                                            },
                                            RelativeSizeAxes = Axes.Both
                                        },
                                        new Container
                                        {
                                            Padding = new MarginPadding
                                            {
                                                Left = 10,
                                                Right = 10 + HORIZONTAL_OVERFLOW_PADDING,
                                                Vertical = 10,
                                            },
                                            RelativeSizeAxes = Axes.Both,
                                            Child = chat = new MatchChatDisplay
                                            {
                                                RelativeSizeAxes = Axes.Both
                                            }
                                        },
                                    },
                                },
                            }
                        },
                    },
                    RowDimensions = new[]
                    {
                        new Dimension(GridSizeMode.AutoSize),
                        new Dimension(GridSizeMode.AutoSize),
                        new Dimension(GridSizeMode.Distributed),
                    }
                },
                new Container
                {
                    RelativeSizeAxes = Axes.Both,
                    Padding = new MarginPadding { Top = Components.Header.HEIGHT },
                    Child = settings = new MatchSettingsOverlay { RelativeSizeAxes = Axes.Both },
                },
            };

            header.Tabs.Current.BindValueChanged(tab =>
            {
                const float fade_duration = 500;

                var settingsDisplayed = tab.NewValue is SettingsMatchPage;

                header.ShowBeatmapPanel.Value = !settingsDisplayed;
                settings.State.Value = settingsDisplayed ? Visibility.Visible : Visibility.Hidden;
                info.FadeTo(settingsDisplayed ? 0 : 1, fade_duration, Easing.OutQuint);
                bottomRow.FadeTo(settingsDisplayed ? 0 : 1, fade_duration, Easing.OutQuint);
            }, true);

            chat.Exit += () =>
            {
                if (this.IsCurrentScreen())
                    this.Exit();
            };

            beatmapManager.ItemAdded += beatmapAdded;
        }

        protected override void LoadComplete()
        {
            base.LoadComplete();

            CurrentItem.BindValueChanged(currentItemChanged, true);
        }

        public override bool OnExiting(IScreen next)
        {
            RoomManager?.PartRoom();
            Mods.Value = Array.Empty<Mod>();
            previewTrackManager.StopAnyPlaying(this);

            return base.OnExiting(next);
        }

        /// <summary>
        /// Handles propagation of the current playlist item's content to game-wide mechanisms.
        /// </summary>
        private void currentItemChanged(ValueChangedEvent<PlaylistItem> e)
        {
            // Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info
            var localBeatmap = e.NewValue?.Beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == e.NewValue.Beatmap.OnlineBeatmapID);

            Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
            Mods.Value = e.NewValue?.RequiredMods?.ToArray() ?? Array.Empty<Mod>();

            if (e.NewValue?.Ruleset != null)
                Ruleset.Value = e.NewValue.Ruleset;

            previewTrackManager.StopAnyPlaying(this);
        }

        /// <summary>
        /// Handle the case where a beatmap is imported (and can be used by this match).
        /// </summary>
        private void beatmapAdded(BeatmapSetInfo model) => Schedule(() =>
{'fraction_non_alphanumeric': 0.07381025483573841, 'fraction_numerical': 0.002456248081056187, 'mean_word_length': 1.0347326336831584, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 112, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1361568', 'n_tokens_mistral': 3696, 'n_tokens_neox': 3383, 'n_words': 761}