<commit_before>﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using Umbraco.Core.Logging;

namespace Umbraco.Core.Services.Implement
{
    // TODO: Convert all of this over to Niels K's localization framework one day

    public class LocalizedTextService :  ILocalizedTextService2
    {
        private readonly ILogger _logger;
        private readonly Lazy<LocalizedTextServiceFileSources> _fileSources;
        private readonly IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> _dictionarySource;
        private readonly IDictionary<CultureInfo, IDictionary<string, string>> _noAreaDictionarySource;
        private readonly char[] _splitter = new[] { '/' };
        /// <summary>
        /// Initializes with a file sources instance
        /// </summary>
        /// <param name="fileSources"></param>
        /// <param name="logger"></param>
        public LocalizedTextService(Lazy<LocalizedTextServiceFileSources> fileSources, ILogger logger)
        {
            if (logger == null) throw new ArgumentNullException("logger");
            _logger = logger;
            if (fileSources == null) throw new ArgumentNullException("fileSources");
            var dictionaries = FileSourcesToDictionarySources(fileSources.Value);
            _dictionarySource = dictionaries.WithArea;
            _noAreaDictionarySource = dictionaries.WithoutArea;
            _fileSources = fileSources;
        }

        private (IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> WithArea, IDictionary<CultureInfo, IDictionary<string, string>> WithoutArea) FileSourcesToDictionarySources(LocalizedTextServiceFileSources fileSources)
        {
            var xmlSources = fileSources.GetXmlSources();
            return XmlSourcesToDictionarySources(xmlSources);
        }
        private (IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> WithArea, IDictionary<CultureInfo, IDictionary<string, string>> WithoutArea) XmlSourcesToDictionarySources(IDictionary<CultureInfo, Lazy<XDocument>> source)
        {
            var cultureDictionary = new Dictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>>();
            var cultureNoAreaDictionary = new Dictionary<CultureInfo, IDictionary<string, string>>();
            foreach (var xmlSource in source)
            {
                var areaAliaValue = GetAreaStoredTranslations(source, xmlSource.Key);
                cultureDictionary.Add(xmlSource.Key, areaAliaValue);
                var aliasValue = new Dictionary<string, string>(StringComparer.InvariantCulture);
                foreach (var area in areaAliaValue)
                {
                    foreach (var alias in area.Value)
                    {
                        if (!aliasValue.ContainsKey(alias.Key))
                        {
                            aliasValue.Add(alias.Key, alias.Value);
                        }
                    }
                }
                cultureNoAreaDictionary.Add(xmlSource.Key, aliasValue);
            }
            return (cultureDictionary, cultureNoAreaDictionary);
        }
        /// <summary>
        /// Initializes with an XML source
        /// </summary>
        /// <param name="source"></param>
        /// <param name="logger"></param>
        public LocalizedTextService(IDictionary<CultureInfo, Lazy<XDocument>> source, ILogger logger)
        {
            if (source == null) throw new ArgumentNullException("source");
            if (logger == null) throw new ArgumentNullException("logger");
            _logger = logger;
            var dictionaries = XmlSourcesToDictionarySources(source);
            _dictionarySource = dictionaries.WithArea;
            _noAreaDictionarySource = dictionaries.WithoutArea;
        }


        /// <summary>
        /// Initializes with a source of a dictionary of culture -> areas -> sub dictionary of keys/values
        /// </summary>
        /// <param name="source"></param>
        /// <param name="logger"></param>
        public LocalizedTextService(IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> source, ILogger logger)
        {
            _dictionarySource = source ?? throw new ArgumentNullException(nameof(source));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
            var cultureNoAreaDictionary = new Dictionary<CultureInfo, IDictionary<string, string>>();
            foreach (var cultureDictionary in _dictionarySource)
            {
                var areaAliaValue = GetAreaStoredTranslations(source, cultureDictionary.Key);
                var aliasValue = new Dictionary<string, string>();
                foreach (var area in areaAliaValue)
                {
                    foreach (var alias in area.Value)
                    {
                        if (!aliasValue.ContainsKey(alias.Key))
                        {
                            aliasValue.Add(alias.Key, alias.Value);
                        }
                    }
                }
                cultureNoAreaDictionary.Add(cultureDictionary.Key, aliasValue);
            }
            _noAreaDictionarySource = cultureNoAreaDictionary;
        }

        public string Localize(string key, CultureInfo culture, IDictionary<string, string> tokens = null)
        {
            if (culture == null) throw new ArgumentNullException(nameof(culture));

            //This is what the legacy ui service did
            if (string.IsNullOrEmpty(key))<commit_msg>implement lazy<commit_after>﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using Umbraco.Core.Logging;

namespace Umbraco.Core.Services.Implement
{
    // TODO: Convert all of this over to Niels K's localization framework one day

    public class LocalizedTextService :  ILocalizedTextService2
    {
        private readonly ILogger _logger;
        private readonly Lazy<LocalizedTextServiceFileSources> _fileSources;
        private IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> _dictionarySource => _dictionarySourceLazy.Value;
        private IDictionary<CultureInfo, IDictionary<string, string>> _noAreaDictionarySource => _noAreaDictionarySourceLazy.Value;
        private readonly Lazy<IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>>> _dictionarySourceLazy;
        private readonly Lazy<IDictionary<CultureInfo, IDictionary<string, string>>> _noAreaDictionarySourceLazy;
        private readonly char[] _splitter = new[] { '/' };
        /// <summary>
        /// Initializes with a file sources instance
        /// </summary>
        /// <param name="fileSources"></param>
        /// <param name="logger"></param>
        public LocalizedTextService(Lazy<LocalizedTextServiceFileSources> fileSources, ILogger logger)
        {
            if (logger == null) throw new ArgumentNullException("logger");
            _logger = logger;
            if (fileSources == null) throw new ArgumentNullException("fileSources");
            _dictionarySourceLazy = new Lazy<IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>>>(()=> FileSourcesToDictionarySources(fileSources.Value).WithArea);
            _noAreaDictionarySourceLazy = new Lazy<IDictionary<CultureInfo, IDictionary<string, string>>>(() => FileSourcesToDictionarySources(fileSources.Value).WithoutArea);
            _fileSources = fileSources;
        }

        private (IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> WithArea, IDictionary<CultureInfo, IDictionary<string, string>> WithoutArea) FileSourcesToDictionarySources(LocalizedTextServiceFileSources fileSources)
        {
            var xmlSources = fileSources.GetXmlSources();
            return XmlSourcesToDictionarySources(xmlSources);
        }
        private (IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> WithArea, IDictionary<CultureInfo, IDictionary<string, string>> WithoutArea) XmlSourcesToDictionarySources(IDictionary<CultureInfo, Lazy<XDocument>> source)
        {
            var cultureDictionary = new Dictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>>();
            var cultureNoAreaDictionary = new Dictionary<CultureInfo, IDictionary<string, string>>();
            foreach (var xmlSource in source)
            {
                var areaAliaValue = GetAreaStoredTranslations(source, xmlSource.Key);
                cultureDictionary.Add(xmlSource.Key, areaAliaValue);
                var aliasValue = new Dictionary<string, string>(StringComparer.InvariantCulture);
                foreach (var area in areaAliaValue)
                {
                    foreach (var alias in area.Value)
                    {
                        if (!aliasValue.ContainsKey(alias.Key))
                        {
                            aliasValue.Add(alias.Key, alias.Value);
                        }
                    }
                }
                cultureNoAreaDictionary.Add(xmlSource.Key, aliasValue);
            }
            return (cultureDictionary, cultureNoAreaDictionary);
        }
        /// <summary>
        /// Initializes with an XML source
        /// </summary>
        /// <param name="source"></param>
        /// <param name="logger"></param>
        public LocalizedTextService(IDictionary<CultureInfo, Lazy<XDocument>> source, ILogger logger)
        {
            if (source == null) throw new ArgumentNullException("source");
            if (logger == null) throw new ArgumentNullException("logger");
            _logger = logger;
            _dictionarySourceLazy = new Lazy<IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>>>(()=> XmlSourcesToDictionarySources(source).WithArea);
            _noAreaDictionarySourceLazy = new Lazy<IDictionary<CultureInfo, IDictionary<string, string>>>(() => XmlSourcesToDictionarySources(source).WithoutArea);
            
        }


        /// <summary>
        /// Initializes with a source of a dictionary of culture -> areas -> sub dictionary of keys/values
        /// </summary>
        /// <param name="source"></param>
        /// <param name="logger"></param>
        public LocalizedTextService(IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> source, ILogger logger)
        {
            var dictionarySource = source ?? throw new ArgumentNullException(nameof(source));
            _dictionarySourceLazy = new Lazy<IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>>>(() => dictionarySource);
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
            var cultureNoAreaDictionary = new Dictionary<CultureInfo, IDictionary<string, string>>();
            foreach (var cultureDictionary in dictionarySource)
            {
                var areaAliaValue = GetAreaStoredTranslations(source, cultureDictionary.Key);
                var aliasValue = new Dictionary<string, string>();
                foreach (var area in areaAliaValue)
                {
                    foreach (var alias in area.Value)
                    {
                        if (!aliasValue.ContainsKey(alias.Key))
                        {
                            aliasValue.Add(alias.Key, alias.Value);
                        }
                    }
                }
                cultureNoAreaDictionary.Add(cultureDictionary.Key, aliasValue);
            }
            _noAreaDictionarySourceLazy = new Lazy<IDictionary<CultureInfo, IDictionary<string, string>>>(() => cultureNoAreaDictionary);
        }

        public string Localize(string key, CultureInfo culture, IDictionary<string, string> tokens = null)
        {
            if (culture == null) throw new ArgumentNullException(nameof(culture));

            //This is what the legacy ui service did
            if (string.IsNullOrEmpty(key))
{'fraction_non_alphanumeric': 0.09421718416297026, 'fraction_numerical': 0.0001642845408247084, 'mean_word_length': 2.4785714285714286, 'pattern_counts': {'":': 0, '<': 135, '<?xml version=': 0, '>': 147, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 12}, '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': '1215904', 'n_tokens_mistral': 2908, 'n_tokens_neox': 2822, 'n_words': 675}