<commit_before>﻿//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//
using System;
using System.Collections.Generic;
using System.IO;
using XSharpModel;
using Microsoft.VisualStudio.Shell.Interop;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Shell;
using Microsoft;
using Task = System.Threading.Tasks.Task;
using Community.VisualStudio.Toolkit;
using System.Text;
using System.Xml;

namespace XSharp.LanguageService
{
    // No need to do a complicated lookup for the reference assembly names
    // Our system type controller has these already
    static public class XSharpXMLDocTools
    {
        static readonly Dictionary<string, IVsXMLMemberIndex> _memberIndexes = new Dictionary<string, IVsXMLMemberIndex>();
        static IVsXMLMemberIndexService _XMLMemberIndexService;
        static string coreLoc = "";
        static IVsXMLMemberIndex coreIndex = null;
        static XSharpXMLDocTools()
        {
            ThreadHelper.JoinableTaskFactory.Run(async delegate
            {
                _XMLMemberIndexService = await VS.GetServiceAsync<SVsXMLMemberIndexService, IVsXMLMemberIndexService>();
            });
            Assumes.Present(_XMLMemberIndexService);
            return;
        }
        public static void Initialize()
        {
            ; // Do nothing. This just triggers the Class Constructor
        }
        private static async Task LoadCoreDllAsync()
        {
            var node = @"HKEY_LOCAL_MACHINE\Software\XSharpBV\XSharp";
            var InstallPath = (string)Microsoft.Win32.Registry.GetValue(node, "XSharpPath", "");
            var assemblies = Path.Combine(InstallPath, "Assemblies");
            coreLoc = Path.Combine(assemblies, "XSharp.Core.dll");
            coreIndex = null;
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
            _XMLMemberIndexService.CreateXMLMemberIndex(coreLoc, out IVsXMLMemberIndex index);
            if (index != null)
            {
                _memberIndexes.Add(coreLoc, index);
                coreIndex = index;
            }
            return;
        }

        private static void LoadCoreDLL()
        {
            ThreadHelper.JoinableTaskFactory.Run(() => LoadCoreDllAsync());
        }
        public static void Close()
        {
            _memberIndexes.Clear();
            if (coreIndex != null)
            {
                _memberIndexes.Add(coreLoc, coreIndex);
            }
        }

        public static IVsXMLMemberIndex Firstfile
        {
            get
            {
                if (_memberIndexes.Count == 0)
                {
                    LoadCoreDLL();
                }
                return _memberIndexes.Values.FirstOrDefault();
            }
        }

        public static IVsXMLMemberIndex GetXmlDocFile(XAssembly assembly, XProject project)
        {
            IVsXMLMemberIndex index = null;
            var location = assembly.FileName;
            if (!string.IsNullOrWhiteSpace(location))
            {
                if (!_memberIndexes.TryGetValue(location, out index))
                {
                    ThreadHelper.JoinableTaskFactory.Run(async delegate
                    {
                        await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
                        _XMLMemberIndexService.CreateXMLMemberIndex(location, out index);
                        if (index != null)
                        {
                            _memberIndexes.Add(location, index);
                        }
                    });
                }
            }
            if (index == null && project != null)  // Sometimes we get a type in the Microsoft.Net folder and not the reference assemblies folder
            {
                string refasm = "";
                foreach (var asm in project.AssemblyReferences)
                {
                    if (asm.FullName == assembly.FullName)
                    {
                        refasm = asm.FileName;
                        break;
                    }
                    if (!string.IsNullOrEmpty(asm.FileName) && asm.FileName.EndsWith("System.DLL", StringComparison.OrdinalIgnoreCase))
                    {
                        if (assembly.FullName.Contains("mscorlib"))
                        {
                            refasm = Path.Combine(Path.GetDirectoryName(asm.FileName), "mscorlib.dll");
                            break;
                        }
                    }
                }

                if (refasm != location && !String.IsNullOrEmpty(refasm))
                {
                    if (!_memberIndexes.TryGetValue(refasm, out index))
                    {
                        ThreadHelper.JoinableTaskFactory.Run(async delegate
                        {
                            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
                            _XMLMemberIndexService.CreateXMLMemberIndex(refasm, out index);
                        });
                        if (index != null)
                        {
                            if (!String.IsNullOrWhiteSpace(location))
                                _memberIndexes.Add(location, index);
                            _memberIndexes.Add(refasm, index);
                        }

                    }
                }
            }

            return index;
        }
    }


    static public class XSharpXMLDocMember
    {
        public static IEnumerable<string> MemoLines(this string str, int maxLength)
        {
            str = str.Replace("\r\n", "\r");
            var tokens = str.Split(" \t".ToCharArray());
            var result = "";
            foreach (var token in tokens)
            {
                if (result.Length + token.Length + 1 > maxLength )
                { 
                    yield return result;
                    result = "";
                }
                if (result.Length > 0)
                    result += ' ';

                if (token.Contains("\r"))
                {
                    var lhs = token.Substring(0, token.IndexOf('\r'));
                    var rhs = token.Substring(token.IndexOf('\r') + 1);
                    result += lhs;
                    yield return result;
                    result = rhs;
                }
                else
                {
                    result += token;
                }
            }
            yield return result;
        }
        static string addXml(string token, string line)
        {
            var result = "";
            result += $"<{token}>";
            if (line.Length < 60)
            {
                result += line;
                result += $"<\\{token}>\r\n";
            }
            else
            {
                foreach (var element in MemoLines(line, 70))
                {
                    result += "\r\n" + element;
                }
                result += $"\r\n<\\{token}>\r\n";
            }
            return result;
        }
        public static string GetDoc(XAssembly asm, IXSymbol symbol)
        {
            var file = XSharpXMLDocTools.GetXmlDocFile(asm, null);
            string key=null;
            if (symbol is IXTypeSymbol type)
                key = type.XMLSignature;
            else if (symbol is IXMemberSymbol member)
                key = member.XMLSignature;
            if (file == null)
                return null;
            if (!string.IsNullOrEmpty(key))
            {
                uint id = 0;
                string xml = "";<commit_msg>Fix incorrect usage of slash in generated XML comments<commit_after>﻿//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//
using System;
using System.Collections.Generic;
using System.IO;
using XSharpModel;
using Microsoft.VisualStudio.Shell.Interop;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Shell;
using Microsoft;
using Task = System.Threading.Tasks.Task;
using Community.VisualStudio.Toolkit;
using System.Text;
using System.Xml;

namespace XSharp.LanguageService
{
    // No need to do a complicated lookup for the reference assembly names
    // Our system type controller has these already
    static public class XSharpXMLDocTools
    {
        static readonly Dictionary<string, IVsXMLMemberIndex> _memberIndexes = new Dictionary<string, IVsXMLMemberIndex>();
        static IVsXMLMemberIndexService _XMLMemberIndexService;
        static string coreLoc = "";
        static IVsXMLMemberIndex coreIndex = null;
        static XSharpXMLDocTools()
        {
            ThreadHelper.JoinableTaskFactory.Run(async delegate
            {
                _XMLMemberIndexService = await VS.GetServiceAsync<SVsXMLMemberIndexService, IVsXMLMemberIndexService>();
            });
            Assumes.Present(_XMLMemberIndexService);
            return;
        }
        public static void Initialize()
        {
            ; // Do nothing. This just triggers the Class Constructor
        }
        private static async Task LoadCoreDllAsync()
        {
            var node = @"HKEY_LOCAL_MACHINE\Software\XSharpBV\XSharp";
            var InstallPath = (string)Microsoft.Win32.Registry.GetValue(node, "XSharpPath", "");
            var assemblies = Path.Combine(InstallPath, "Assemblies");
            coreLoc = Path.Combine(assemblies, "XSharp.Core.dll");
            coreIndex = null;
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
            _XMLMemberIndexService.CreateXMLMemberIndex(coreLoc, out IVsXMLMemberIndex index);
            if (index != null)
            {
                _memberIndexes.Add(coreLoc, index);
                coreIndex = index;
            }
            return;
        }

        private static void LoadCoreDLL()
        {
            ThreadHelper.JoinableTaskFactory.Run(() => LoadCoreDllAsync());
        }
        public static void Close()
        {
            _memberIndexes.Clear();
            if (coreIndex != null)
            {
                _memberIndexes.Add(coreLoc, coreIndex);
            }
        }

        public static IVsXMLMemberIndex Firstfile
        {
            get
            {
                if (_memberIndexes.Count == 0)
                {
                    LoadCoreDLL();
                }
                return _memberIndexes.Values.FirstOrDefault();
            }
        }

        public static IVsXMLMemberIndex GetXmlDocFile(XAssembly assembly, XProject project)
        {
            IVsXMLMemberIndex index = null;
            var location = assembly.FileName;
            if (!string.IsNullOrWhiteSpace(location))
            {
                if (!_memberIndexes.TryGetValue(location, out index))
                {
                    ThreadHelper.JoinableTaskFactory.Run(async delegate
                    {
                        await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
                        _XMLMemberIndexService.CreateXMLMemberIndex(location, out index);
                        if (index != null)
                        {
                            _memberIndexes.Add(location, index);
                        }
                    });
                }
            }
            if (index == null && project != null)  // Sometimes we get a type in the Microsoft.Net folder and not the reference assemblies folder
            {
                string refasm = "";
                foreach (var asm in project.AssemblyReferences)
                {
                    if (asm.FullName == assembly.FullName)
                    {
                        refasm = asm.FileName;
                        break;
                    }
                    if (!string.IsNullOrEmpty(asm.FileName) && asm.FileName.EndsWith("System.DLL", StringComparison.OrdinalIgnoreCase))
                    {
                        if (assembly.FullName.Contains("mscorlib"))
                        {
                            refasm = Path.Combine(Path.GetDirectoryName(asm.FileName), "mscorlib.dll");
                            break;
                        }
                    }
                }

                if (refasm != location && !String.IsNullOrEmpty(refasm))
                {
                    if (!_memberIndexes.TryGetValue(refasm, out index))
                    {
                        ThreadHelper.JoinableTaskFactory.Run(async delegate
                        {
                            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
                            _XMLMemberIndexService.CreateXMLMemberIndex(refasm, out index);
                        });
                        if (index != null)
                        {
                            if (!String.IsNullOrWhiteSpace(location))
                                _memberIndexes.Add(location, index);
                            _memberIndexes.Add(refasm, index);
                        }

                    }
                }
            }

            return index;
        }
    }


    static public class XSharpXMLDocMember
    {
        public static IEnumerable<string> MemoLines(this string str, int maxLength)
        {
            str = str.Replace("\r\n", "\r");
            var tokens = str.Split(" \t".ToCharArray());
            var result = "";
            foreach (var token in tokens)
            {
                if (result.Length + token.Length + 1 > maxLength )
                { 
                    yield return result;
                    result = "";
                }
                if (result.Length > 0)
                    result += ' ';

                if (token.Contains("\r"))
                {
                    var lhs = token.Substring(0, token.IndexOf('\r'));
                    var rhs = token.Substring(token.IndexOf('\r') + 1);
                    result += lhs;
                    yield return result;
                    result = rhs;
                }
                else
                {
                    result += token;
                }
            }
            yield return result;
        }
        static string addXml(string token, string line)
        {
            var result = "";
            result += $"<{token}>";
            if (line.Length < 60)
            {
                result += line;
                result += $"</{token}>\r\n";
            }
            else
            {
                foreach (var element in MemoLines(line, 70))
                {
                    result += "\r\n" + element;
                }
                result += $"\r\n</{token}>\r\n";
            }
            return result;
        }
        public static string GetDoc(XAssembly asm, IXSymbol symbol)
        {
            var file = XSharpXMLDocTools.GetXmlDocFile(asm, null);
            string key=null;
            if (symbol is IXTypeSymbol type)
                key = type.XMLSignature;
            else if (symbol is IXMemberSymbol member)
                key = member.XMLSignature;
            if (file == null)
                return null;
            if (!string.IsNullOrEmpty(key))
            {
                uint id = 0;
                string xml = "";
{'fraction_non_alphanumeric': 0.08485005505537924, 'fraction_numerical': 0.0018135889630157393, 'mean_word_length': 1.2769503023152928, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, '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': '2646033', 'n_tokens_mistral': 3804, 'n_tokens_neox': 3569, 'n_words': 830}