<commit_before>// Copyright (c) 2007-2018 ppy Pty Ltd <<EMAIL>>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests;
using osu.Game.Rulesets;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.IPC;

namespace osu.Game.Tournament
{
    public abstract class TournamentGameBase : OsuGameBase
    {
        private const string bracket_filename = "bracket.json";

        protected LadderInfo Ladder;
        private Storage storage;

        private DependencyContainer dependencies;

        [Cached]
        private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();

        private Bindable<Size> windowSize;
        private FileBasedIPC ipc;

        protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
        {
            return dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
        }

        [BackgroundDependencyLoader]
        private void load(Storage storage, FrameworkConfigManager frameworkConfig)
        {
            Resources.AddStore(new DllResourceStore(@"osu.Game.Tournament.dll"));

            Fonts.AddStore(new GlyphStore(Resources, @"Resources/Fonts/Aquatico-Regular"));
            Fonts.AddStore(new GlyphStore(Resources, @"Resources/Fonts/Aquatico-Light"));

            Textures.AddStore(new TextureLoaderStore(new ResourceStore<byte[]>(new StorageBackedResourceStore(storage))));

            this.storage = storage;

            windowSize = frameworkConfig.GetBindable<Size>(FrameworkSetting.WindowedSize);

            string content = null;
            if (storage.Exists(bracket_filename))
                using (Stream stream = storage.GetStream(bracket_filename, FileAccess.Read, FileMode.Open))
                using (var sr = new StreamReader(stream))
                {
                    content = sr.ReadToEnd();
                }

            Ladder = content != null ? JsonConvert.DeserializeObject<LadderInfo>(content) : new LadderInfo();

            dependencies.Cache(Ladder);

            dependencies.CacheAs<MatchIPCInfo>(ipc = new FileBasedIPC());
            Add(ipc);

            bool addedInfo = false;

            // assign teams
            foreach (var pairing in Ladder.Pairings)
            {
                pairing.Team1.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym == pairing.Team1Acronym);
                pairing.Team2.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym == pairing.Team2Acronym);

                foreach (var conditional in pairing.ConditionalPairings)
                {
                    conditional.Team1.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym == conditional.Team1Acronym);
                    conditional.Team2.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym == conditional.Team2Acronym);
                    conditional.Grouping.Value = pairing.Grouping.Value;
                }
            }

            // assign progressions
            foreach (var pair in Ladder.Progressions)
            {
                var src = Ladder.Pairings.FirstOrDefault(p => p.ID == pair.Item1);
                var dest = Ladder.Pairings.FirstOrDefault(p => p.ID == pair.Item2);

                if (src == null) throw new InvalidOperationException();

                if (dest != null)
                {
                    if (pair.Losers)
                        src.LosersProgression.Value = dest;
                    else
                        src.Progression.Value = dest;
                }
            }

            // link pairings to groupings
            foreach (var group in Ladder.Groupings)
            foreach (var id in group.Pairings)
            {
                var found = Ladder.Pairings.FirstOrDefault(p => p.ID == id);
                if (found != null) found.Grouping.Value = group;
            }

            Ladder.CurrentMatch.Value = Ladder.Pairings.FirstOrDefault(p => p.Current.Value);

            // add full player info based on user IDs
            foreach (var t in Ladder.Teams)
            foreach (var p in t.Players)
                if (string.IsNullOrEmpty(p.Username))
                {
                    var req = new GetUserRequest(p.Id);
                    req.Perform(API);
                    p.Username = req.Result.Username;

                    addedInfo = true;
                }

            // add full beatmap info based on beatmap IDs
            foreach (var g in Ladder.Groupings)
            foreach (var b in g.Beatmaps)
                if (b.BeatmapInfo == null)
                {
                    var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = b.ID });
                    req.Perform(API);
                    b.BeatmapInfo = req.Result?.ToBeatmap(RulesetStore);

                    addedInfo = true;
                }

            List<TournamentTeam> countries;
            using (Stream stream = Resources.GetStream("Resources/countries.json"))
            using (var sr = new StreamReader(stream))
                countries = JsonConvert.DeserializeObject<List<TournamentTeam>>(sr.ReadToEnd());

            foreach (var t in Ladder.Teams)
                if (string.IsNullOrEmpty(t.FullName))
                {
                    var result = countries.FirstOrDefault(c => c.Acronym == t.Acronym);
                    if (result != null)
                    {
                        t.Acronym = result.Acronym;
                        t.FlagName = result.FlagName;
                        t.FullName = result.FullName;
                    }
                }

            if (addedInfo)
                SaveChanges();

            Add(new OsuButton
            {
                Text = "Save Changes",
                Width = 140,
                Height = 50,
                Anchor = Anchor.BottomRight,
                Origin = Anchor.BottomRight,
                Padding = new MarginPadding(10),
                Action = SaveChanges,
            });
        }

        protected override void LoadComplete()
        {
            MenuCursorContainer.Cursor.Alpha = 0;
            base.LoadComplete();
        }

        protected override void Update()
        {
            base.Update();
            var minWidth = (int)(windowSize.Value.Height / 9f * 16 + 400);
            if (windowSize.Value.Width < minWidth)
            {
                // todo: can be removed after ppy/osu-framework#1975
                windowSize.Value = Host.Window.ClientSize = new Size(minWidth, windowSize.Value.Height);
            }
        }

        protected virtual void SaveChanges()
        {
            using (var stream = storage.GetStream(bracket_filename, FileAccess.Write, FileMode.Create))
            using (var sw = new StreamWriter(stream))
            {
                sw.Write(JsonConvert.SerializeObject(Ladder,
                    new JsonSerializerSettings
                    {
                        NullValueHandling = NullValueHandling.Ignore,
                        DefaultValueHandling = DefaultValueHandling.Ignore,
                    }));
            }
        }
    }
}
<commit_msg>Automatically fix invalid pairing dates on load (based on contained groupings)<commit_after>// Copyright (c) 2007-2018 ppy Pty Ltd <<EMAIL>>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests;
using osu.Game.Rulesets;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.IPC;

namespace osu.Game.Tournament
{
    public abstract class TournamentGameBase : OsuGameBase
    {
        private const string bracket_filename = "bracket.json";

        protected LadderInfo Ladder;
        private Storage storage;

        private DependencyContainer dependencies;

        [Cached]
        private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();

        private Bindable<Size> windowSize;
        private FileBasedIPC ipc;

        protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
        {
            return dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
        }

        [BackgroundDependencyLoader]
        private void load(Storage storage, FrameworkConfigManager frameworkConfig)
        {
            Resources.AddStore(new DllResourceStore(@"osu.Game.Tournament.dll"));

            Fonts.AddStore(new GlyphStore(Resources, @"Resources/Fonts/Aquatico-Regular"));
            Fonts.AddStore(new GlyphStore(Resources, @"Resources/Fonts/Aquatico-Light"));

            Textures.AddStore(new TextureLoaderStore(new ResourceStore<byte[]>(new StorageBackedResourceStore(storage))));

            this.storage = storage;

            windowSize = frameworkConfig.GetBindable<Size>(FrameworkSetting.WindowedSize);

            string content = null;
            if (storage.Exists(bracket_filename))
                using (Stream stream = storage.GetStream(bracket_filename, FileAccess.Read, FileMode.Open))
                using (var sr = new StreamReader(stream))
                {
                    content = sr.ReadToEnd();
                }

            Ladder = content != null ? JsonConvert.DeserializeObject<LadderInfo>(content) : new LadderInfo();

            dependencies.Cache(Ladder);

            dependencies.CacheAs<MatchIPCInfo>(ipc = new FileBasedIPC());
            Add(ipc);

            bool addedInfo = false;

            // assign teams
            foreach (var pairing in Ladder.Pairings)
            {
                pairing.Team1.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym == pairing.Team1Acronym);
                pairing.Team2.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym == pairing.Team2Acronym);

                foreach (var conditional in pairing.ConditionalPairings)
                {
                    conditional.Team1.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym == conditional.Team1Acronym);
                    conditional.Team2.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym == conditional.Team2Acronym);
                    conditional.Grouping.Value = pairing.Grouping.Value;
                }
            }

            // assign progressions
            foreach (var pair in Ladder.Progressions)
            {
                var src = Ladder.Pairings.FirstOrDefault(p => p.ID == pair.Item1);
                var dest = Ladder.Pairings.FirstOrDefault(p => p.ID == pair.Item2);

                if (src == null) throw new InvalidOperationException();

                if (dest != null)
                {
                    if (pair.Losers)
                        src.LosersProgression.Value = dest;
                    else
                        src.Progression.Value = dest;
                }
            }

            // link pairings to groupings
            foreach (var group in Ladder.Groupings)
            foreach (var id in group.Pairings)
            {
                var found = Ladder.Pairings.FirstOrDefault(p => p.ID == id);
                if (found != null)
                {
                    found.Grouping.Value = group;
                    if (group.StartDate.Value > found.Date.Value)
                        found.Date.Value = group.StartDate.Value;
                }
            }

            Ladder.CurrentMatch.Value = Ladder.Pairings.FirstOrDefault(p => p.Current.Value);

            // add full player info based on user IDs
            foreach (var t in Ladder.Teams)
            foreach (var p in t.Players)
                if (string.IsNullOrEmpty(p.Username))
                {
                    var req = new GetUserRequest(p.Id);
                    req.Perform(API);
                    p.Username = req.Result.Username;

                    addedInfo = true;
                }

            // add full beatmap info based on beatmap IDs
            foreach (var g in Ladder.Groupings)
            foreach (var b in g.Beatmaps)
                if (b.BeatmapInfo == null)
                {
                    var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = b.ID });
                    req.Perform(API);
                    b.BeatmapInfo = req.Result?.ToBeatmap(RulesetStore);

                    addedInfo = true;
                }

            List<TournamentTeam> countries;
            using (Stream stream = Resources.GetStream("Resources/countries.json"))
            using (var sr = new StreamReader(stream))
                countries = JsonConvert.DeserializeObject<List<TournamentTeam>>(sr.ReadToEnd());

            foreach (var t in Ladder.Teams)
                if (string.IsNullOrEmpty(t.FullName))
                {
                    var result = countries.FirstOrDefault(c => c.Acronym == t.Acronym);
                    if (result != null)
                    {
                        t.Acronym = result.Acronym;
                        t.FlagName = result.FlagName;
                        t.FullName = result.FullName;
                    }
                }

            if (addedInfo)
                SaveChanges();

            Add(new OsuButton
            {
                Text = "Save Changes",
                Width = 140,
                Height = 50,
                Anchor = Anchor.BottomRight,
                Origin = Anchor.BottomRight,
                Padding = new MarginPadding(10),
                Action = SaveChanges,
            });
        }

        protected override void LoadComplete()
        {
            MenuCursorContainer.Cursor.Alpha = 0;
            base.LoadComplete();
        }

        protected override void Update()
        {
            base.Update();
            var minWidth = (int)(windowSize.Value.Height / 9f * 16 + 400);
            if (windowSize.Value.Width < minWidth)
            {
                // todo: can be removed after ppy/osu-framework#1975
                windowSize.Value = Host.Window.ClientSize = new Size(minWidth, windowSize.Value.Height);
            }
        }

        protected virtual void SaveChanges()
        {
            using (var stream = storage.GetStream(bracket_filename, FileAccess.Write, FileMode.Create))
            using (var sw = new StreamWriter(stream))
            {
                sw.Write(JsonConvert.SerializeObject(Ladder,
                    new JsonSerializerSettings
                    {
                        NullValueHandling = NullValueHandling.Ignore,
                        DefaultValueHandling = DefaultValueHandling.Ignore,
                    }));
            }
        }
    }
}

{'fraction_non_alphanumeric': 0.08935398172746711, 'fraction_numerical': 0.004665327544871379, 'mean_word_length': 1.6748700173310225, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 46, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6601335', 'n_tokens_mistral': 4181, 'n_tokens_neox': 3837, 'n_words': 833}