<commit_before>﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Xml.Linq;
using Newtonsoft.Json;
using Umbraco.Core.Composing;
using Umbraco.Core.Models;
using Umbraco.Core.Strings;

namespace Umbraco.Core.Services.Implement
{
    /// <summary>
    /// Serializes entities to XML
    /// </summary>
    internal class EntityXmlSerializer : IEntityXmlSerializer
    {
        private readonly IContentTypeService _contentTypeService;
        private readonly IMediaService _mediaService;
        private readonly IContentService _contentService;
        private readonly IDataTypeService _dataTypeService;
        private readonly IUserService _userService;
        private readonly ILocalizationService _localizationService;
        private readonly UrlSegmentProviderCollection _urlSegmentProviders;

        public EntityXmlSerializer(
            IContentService contentService,
            IMediaService mediaService,
            IDataTypeService dataTypeService,
            IUserService userService,
            ILocalizationService localizationService,
            IContentTypeService contentTypeService,
            UrlSegmentProviderCollection urlSegmentProviders)
        {
            _contentTypeService = contentTypeService;
            _mediaService = mediaService;
            _contentService = contentService;
            _dataTypeService = dataTypeService;
            _userService = userService;
            _localizationService = localizationService;
            _urlSegmentProviders = urlSegmentProviders;
        }

        /// <summary>
        /// Exports an IContent item as an XElement.
        /// </summary>
        public XElement Serialize(IContent content,
            bool published,
            bool withDescendants = false) // TODO: take care of usage! only used for the packager
        {
            if (content == null) throw new ArgumentNullException(nameof(content));

            var nodeName = content.ContentType.Alias.ToSafeAlias();

            var xml = SerializeContentBase(content, content.GetUrlSegment(_urlSegmentProviders), nodeName, published);

            xml.Add(new XAttribute("nodeType", content.ContentType.Id));
            xml.Add(new XAttribute("nodeTypeAlias", content.ContentType.Alias));

            xml.Add(new XAttribute("creatorName", content.GetCreatorProfile(_userService)?.Name ?? "??"));
            //xml.Add(new XAttribute("creatorID", content.CreatorId));
            xml.Add(new XAttribute("writerName", content.GetWriterProfile(_userService)?.Name ?? "??"));
            xml.Add(new XAttribute("writerID", content.WriterId));

            xml.Add(new XAttribute("template", content.TemplateId?.ToString(CultureInfo.InvariantCulture) ?? ""));

            xml.Add(new XAttribute("isPublished", content.Published));

            if (withDescendants)
            {
                const int pageSize = 500;
                var page = 0;
                var total = long.MaxValue;
                while(page * pageSize < total)
                {
                    var children = _contentService.GetPagedChildren(content.Id, page++, pageSize, out total);
                    SerializeChildren(children, xml, published);
                }
                
            }

            return xml;
        }

        /// <summary>
        /// Exports an IMedia item as an XElement.
        /// </summary>
        public XElement Serialize(
            IMedia media,
            bool withDescendants = false)
        {
            if (_mediaService == null) throw new ArgumentNullException(nameof(_mediaService));
            if (_dataTypeService == null) throw new ArgumentNullException(nameof(_dataTypeService));
            if (_userService == null) throw new ArgumentNullException(nameof(_userService));
            if (_localizationService == null) throw new ArgumentNullException(nameof(_localizationService));
            if (media == null) throw new ArgumentNullException(nameof(media));
            if (_urlSegmentProviders == null) throw new ArgumentNullException(nameof(_urlSegmentProviders));

            var nodeName = media.ContentType.Alias.ToSafeAlias();

            const bool published = false; // always false for media
            var xml = SerializeContentBase(media, media.GetUrlSegment(_urlSegmentProviders), nodeName, published);

            xml.Add(new XAttribute("nodeType", media.ContentType.Id));
            xml.Add(new XAttribute("nodeTypeAlias", media.ContentType.Alias));

            //xml.Add(new XAttribute("creatorName", media.GetCreatorProfile(userService).Name));
            //xml.Add(new XAttribute("creatorID", media.CreatorId));
            xml.Add(new XAttribute("writerName", media.GetWriterProfile(_userService)?.Name ?? string.Empty));
            xml.Add(new XAttribute("writerID", media.WriterId));

            //xml.Add(new XAttribute("template", 0)); // no template for media

            if (withDescendants)
            {
                const int pageSize = 500;
                var page = 0;
                var total = long.MaxValue;
                while (page * pageSize < total)
                {
                    var children = _mediaService.GetPagedChildren(media.Id, page++, pageSize, out total);
                    SerializeChildren(children, xml);
                }
            }

            return xml;
        }

        /// <summary>
        /// Exports an IMember item as an XElement.
        /// </summary>
        public XElement Serialize(IMember member)
        {
            var nodeName = member.ContentType.Alias.ToSafeAlias();

            const bool published = false; // always false for member
            var xml = SerializeContentBase(member, "", nodeName, published);

            xml.Add(new XAttribute("nodeType", member.ContentType.Id));
            xml.Add(new XAttribute("nodeTypeAlias", member.ContentType.Alias));

            // what about writer/creator/version?

            xml.Add(new XAttribute("loginName", member.Username));
            xml.Add(new XAttribute("email", member.Email));
            xml.Add(new XAttribute("icon", member.ContentType.Icon));

            return xml;
        }

        /// <summary>
        /// Exports a list of Data Types
        /// </summary>
        /// <param name="dataTypeDefinitions">List of data types to export</param>
        /// <returns><see cref="XElement"/> containing the xml representation of the IDataTypeDefinition objects</returns>
        public XElement Serialize(IEnumerable<IDataType> dataTypeDefinitions)
        {
            var container = new XElement("DataTypes");
            foreach (var dataTypeDefinition in dataTypeDefinitions)
            {
                container.Add(Serialize(dataTypeDefinition));
            }
            return container;
        }

        public XElement Serialize(IDataType dataType)
        {
            var xml = new XElement("DataType");
            xml.Add(new XAttribute("Name", dataType.Name));
            //The 'ID' when exporting is actually the property editor alias (in pre v7 it was the IDataType GUID id)
            xml.Add(new XAttribute("Id", dataType.EditorAlias));
            xml.Add(new XAttribute("Definition", dataType.Key));
            xml.Add(new XAttribute("DatabaseType", dataType.DatabaseType.ToString()));
            xml.Add(new XAttribute("Configuration", JsonConvert.SerializeObject(dataType.Configuration)));

            var folderNames = string.Empty;
            if (dataType.Level != 1)
            {
                //get url encoded folder names<commit_msg>Data type configuration serialization<commit_after>﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Xml.Linq;
using Newtonsoft.Json;
using Umbraco.Core.Composing;
using Umbraco.Core.Models;
using Umbraco.Core.Strings;

namespace Umbraco.Core.Services.Implement
{
    /// <summary>
    /// Serializes entities to XML
    /// </summary>
    internal class EntityXmlSerializer : IEntityXmlSerializer
    {
        private readonly IContentTypeService _contentTypeService;
        private readonly IMediaService _mediaService;
        private readonly IContentService _contentService;
        private readonly IDataTypeService _dataTypeService;
        private readonly IUserService _userService;
        private readonly ILocalizationService _localizationService;
        private readonly UrlSegmentProviderCollection _urlSegmentProviders;

        public EntityXmlSerializer(
            IContentService contentService,
            IMediaService mediaService,
            IDataTypeService dataTypeService,
            IUserService userService,
            ILocalizationService localizationService,
            IContentTypeService contentTypeService,
            UrlSegmentProviderCollection urlSegmentProviders)
        {
            _contentTypeService = contentTypeService;
            _mediaService = mediaService;
            _contentService = contentService;
            _dataTypeService = dataTypeService;
            _userService = userService;
            _localizationService = localizationService;
            _urlSegmentProviders = urlSegmentProviders;
        }

        /// <summary>
        /// Exports an IContent item as an XElement.
        /// </summary>
        public XElement Serialize(IContent content,
            bool published,
            bool withDescendants = false) // TODO: take care of usage! only used for the packager
        {
            if (content == null) throw new ArgumentNullException(nameof(content));

            var nodeName = content.ContentType.Alias.ToSafeAlias();

            var xml = SerializeContentBase(content, content.GetUrlSegment(_urlSegmentProviders), nodeName, published);

            xml.Add(new XAttribute("nodeType", content.ContentType.Id));
            xml.Add(new XAttribute("nodeTypeAlias", content.ContentType.Alias));

            xml.Add(new XAttribute("creatorName", content.GetCreatorProfile(_userService)?.Name ?? "??"));
            //xml.Add(new XAttribute("creatorID", content.CreatorId));
            xml.Add(new XAttribute("writerName", content.GetWriterProfile(_userService)?.Name ?? "??"));
            xml.Add(new XAttribute("writerID", content.WriterId));

            xml.Add(new XAttribute("template", content.TemplateId?.ToString(CultureInfo.InvariantCulture) ?? ""));

            xml.Add(new XAttribute("isPublished", content.Published));

            if (withDescendants)
            {
                const int pageSize = 500;
                var page = 0;
                var total = long.MaxValue;
                while(page * pageSize < total)
                {
                    var children = _contentService.GetPagedChildren(content.Id, page++, pageSize, out total);
                    SerializeChildren(children, xml, published);
                }
                
            }

            return xml;
        }

        /// <summary>
        /// Exports an IMedia item as an XElement.
        /// </summary>
        public XElement Serialize(
            IMedia media,
            bool withDescendants = false)
        {
            if (_mediaService == null) throw new ArgumentNullException(nameof(_mediaService));
            if (_dataTypeService == null) throw new ArgumentNullException(nameof(_dataTypeService));
            if (_userService == null) throw new ArgumentNullException(nameof(_userService));
            if (_localizationService == null) throw new ArgumentNullException(nameof(_localizationService));
            if (media == null) throw new ArgumentNullException(nameof(media));
            if (_urlSegmentProviders == null) throw new ArgumentNullException(nameof(_urlSegmentProviders));

            var nodeName = media.ContentType.Alias.ToSafeAlias();

            const bool published = false; // always false for media
            var xml = SerializeContentBase(media, media.GetUrlSegment(_urlSegmentProviders), nodeName, published);

            xml.Add(new XAttribute("nodeType", media.ContentType.Id));
            xml.Add(new XAttribute("nodeTypeAlias", media.ContentType.Alias));

            //xml.Add(new XAttribute("creatorName", media.GetCreatorProfile(userService).Name));
            //xml.Add(new XAttribute("creatorID", media.CreatorId));
            xml.Add(new XAttribute("writerName", media.GetWriterProfile(_userService)?.Name ?? string.Empty));
            xml.Add(new XAttribute("writerID", media.WriterId));

            //xml.Add(new XAttribute("template", 0)); // no template for media

            if (withDescendants)
            {
                const int pageSize = 500;
                var page = 0;
                var total = long.MaxValue;
                while (page * pageSize < total)
                {
                    var children = _mediaService.GetPagedChildren(media.Id, page++, pageSize, out total);
                    SerializeChildren(children, xml);
                }
            }

            return xml;
        }

        /// <summary>
        /// Exports an IMember item as an XElement.
        /// </summary>
        public XElement Serialize(IMember member)
        {
            var nodeName = member.ContentType.Alias.ToSafeAlias();

            const bool published = false; // always false for member
            var xml = SerializeContentBase(member, "", nodeName, published);

            xml.Add(new XAttribute("nodeType", member.ContentType.Id));
            xml.Add(new XAttribute("nodeTypeAlias", member.ContentType.Alias));

            // what about writer/creator/version?

            xml.Add(new XAttribute("loginName", member.Username));
            xml.Add(new XAttribute("email", member.Email));
            xml.Add(new XAttribute("icon", member.ContentType.Icon));

            return xml;
        }

        /// <summary>
        /// Exports a list of Data Types
        /// </summary>
        /// <param name="dataTypeDefinitions">List of data types to export</param>
        /// <returns><see cref="XElement"/> containing the xml representation of the IDataTypeDefinition objects</returns>
        public XElement Serialize(IEnumerable<IDataType> dataTypeDefinitions)
        {
            var container = new XElement("DataTypes");
            foreach (var dataTypeDefinition in dataTypeDefinitions)
            {
                container.Add(Serialize(dataTypeDefinition));
            }
            return container;
        }

        public XElement Serialize(IDataType dataType)
        {
            var xml = new XElement("DataType");
            xml.Add(new XAttribute("Name", dataType.Name));
            //The 'ID' when exporting is actually the property editor alias (in pre v7 it was the IDataType GUID id)
            xml.Add(new XAttribute("Id", dataType.EditorAlias));
            xml.Add(new XAttribute("Definition", dataType.Key));
            xml.Add(new XAttribute("DatabaseType", dataType.DatabaseType.ToString()));
            xml.Add(new XAttribute("Configuration", JsonConvert.SerializeObject(dataType.Configuration, PropertyEditors.ConfigurationEditor.ConfigurationJsonSettings)));

            var folderNames = string.Empty;
            if (dataType.Level != 1)
            {
                //get url encoded folder names
{'fraction_non_alphanumeric': 0.09622015483703077, 'fraction_numerical': 0.0014312666710038385, 'mean_word_length': 2.2783109404990403, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 70}, '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': '4667527', 'n_tokens_mistral': 3792, 'n_tokens_neox': 3679, 'n_words': 903}