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

using System;
using System.Collections.Concurrent;
using osu.Framework.Graphics;
using osu.Game.Configuration;
using osu.Game.Rulesets.Configuration;

namespace osu.Game.Rulesets
{
    /// <summary>
    /// A cache that provides a single <see cref="IRulesetConfigManager"/> per-ruleset.
    /// This is done to support referring to and updating ruleset configs from multiple locations in the absence of inter-config bindings.
    /// </summary>
    public class RulesetConfigCache : Component
    {
        private readonly ConcurrentDictionary<int, IRulesetConfigManager> configCache = new ConcurrentDictionary<int, IRulesetConfigManager>();
        private readonly SettingsStore settingsStore;

        public RulesetConfigCache(SettingsStore settingsStore)
        {
            this.settingsStore = settingsStore;
        }

        /// <summary>
        /// Retrieves the <see cref="IRulesetConfigManager"/> for a <see cref="Ruleset"/>.
        /// </summary>
        /// <param name="ruleset">The <see cref="Ruleset"/> to retrieve the <see cref="IRulesetConfigManager"/> for.</param>
        /// <returns>The <see cref="IRulesetConfigManager"/> defined by <paramref name="ruleset"/>, null if <paramref name="ruleset"/> doesn't define one.</returns>
        /// <exception cref="InvalidOperationException">If <paramref name="ruleset"/> doesn't have a valid <see cref="RulesetInfo.ID"/>.</exception>
        public IRulesetConfigManager GetConfigFor(Ruleset ruleset)
        {
            if (ruleset.RulesetInfo.ID == null)
                return null;

            return configCache.GetOrAdd(ruleset.RulesetInfo.ID.Value, _ => ruleset.CreateConfig(settingsStore));
        }

        protected override void Dispose(bool isDisposing)
        {
            base.Dispose(isDisposing);

            // ensures any potential database operations are finalised before game destruction.
            foreach (var c in configCache.Values)
                c?.Dispose();
        }
    }
}