<commit_before>﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;

namespace Cake.AndroidAppManifest
{
    public class AndroidAppManifest
    {
        private static readonly XNamespace aNS = "http://schemas.android.com/apk/res/android";
        private static readonly XName aName = aNS + "name";
        private readonly XDocument doc;
        private readonly XElement manifest;
        private readonly XElement application;
        private readonly XElement usesSdk;

        private AndroidAppManifest(XDocument doc)
        {
            this.doc = doc;
            manifest = doc.Root;
            if (manifest.Name != "manifest")
            {
                throw new Exception("App manifest does not have 'manifest' root element");
            }

            application = manifest.Element("application");
            if (application == null)
            {
                manifest.Add(application = new XElement("application"));
            }

            usesSdk = manifest.Element("uses-sdk");
            if (usesSdk == null)
            {
                manifest.Add(usesSdk = new XElement("uses-sdk"));
            }
        }

        public string PackageName
        {
            get { return (string)manifest.Attribute("package"); }
            set { manifest.SetAttributeValue("package", NullIfEmpty(value)); }
        }

        public string ApplicationLabel
        {
            get { return (string)application.Attribute(aNS + "label"); }
            set { application.SetAttributeValue(aNS + "label", NullIfEmpty(value)); }
        }

        public string ApplicationIcon
        {
            get { return (string)application.Attribute(aNS + "icon"); }
            set { application.SetAttributeValue(aNS + "icon", NullIfEmpty(value)); }
        }

        public string ApplicationTheme
        {
            get { return (string)application.Attribute(aNS + "theme"); }
            set { application.SetAttributeValue(aNS + "theme", NullIfEmpty(value)); }
        }

        public string VersionName
        {
            get { return (string)manifest.Attribute(aNS + "versionName"); }
            set { manifest.SetAttributeValue(aNS + "versionName", NullIfEmpty(value)); }
        }

        public int VersionCode
        {
            get { return this.ParseRequiredInt(manifest.Attribute(aNS + "versionCode")); }
            set { manifest.SetAttributeValue(aNS + "versionCode", value); }
        }

        public string InstallLocation
        {
            get { return (string)manifest.Attribute(aNS + "installLocation"); }
            set { manifest.SetAttributeValue(aNS + "installLocation", NullIfEmpty(value)); }
        }

        public int? MinSdkVersion
        {
            get { return ParseSdkVersion(usesSdk.Attribute(aNS + "minSdkVersion")); }
            set { usesSdk.SetAttributeValue(aNS + "minSdkVersion", value == null ? null : value.ToString()); }
        }

        public int? TargetSdkVersion
        {
            get { return ParseSdkVersion(usesSdk.Attribute(aNS + "targetSdkVersion")); }
            set { usesSdk.SetAttributeValue(aNS + "targetSdkVersion", value == null ? null : value.ToString()); }
        }

        public IEnumerable<string> AndroidPermissions
        {
            get
            {
                foreach (var el in manifest.Elements("uses-permission"))
                {
                    var name = (string)el.Attribute(aName);
                    if (name == null)
                    {
                        continue;
                    }
                    var lastDot = name.LastIndexOf('.');
                    if (lastDot >= 0)
                    {
                        yield return name.Substring(lastDot + 1);
                    }
                }
            }
        }

        public IEnumerable<string> AndroidPermissionsQualified
        {
            get
            {
                foreach (var el in manifest.Elements("uses-permission"))
                {
                    var name = (string)el.Attribute(aName);
                    if (name != null)
                    {
                        yield return name;
                    }
                }
            }
        }

        public bool? Debuggable
        {
            get { return (bool?)application.Attribute(aNS + "debuggable"); }
            set { application.SetAttributeValue(aNS + "debuggable", value); }
        }

        public static string CanonicalizePackageName(string packageNameOrAssemblyName)
        {
            if (packageNameOrAssemblyName == null)
            {
                throw new ArgumentNullException("packageNameOrAssemblyName");
            }

            if (string.IsNullOrEmpty(packageNameOrAssemblyName = packageNameOrAssemblyName.Trim()))
            {
                throw new ArgumentException("Must specify a package name or assembly name", "packageNameOrAssemblyName");
            }

            var packageParts = packageNameOrAssemblyName.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
            for (var i = 0; i < packageParts.Length; ++i)
            {
                packageParts[i] = Regex.Replace(packageParts[i], "[^A-Za-z0-9_]", "_");
                if (char.IsDigit(packageParts[i], 0) || packageParts[i][0] == '_')
                    packageParts[i] = "x" + packageParts[i];
            }

            return packageParts.Length == 1
                ? packageParts[0] + "." + packageParts[0]
                : string.Join(".", packageParts);
        }

        public static AndroidAppManifest Create(string packageName, string appLabel)
        {
            return new AndroidAppManifest(XDocument.Parse(
                @"<?xml version=""1.0"" encoding=""utf-8""?>
<manifest xmlns:android=""http://schemas.android.com/apk/res/android"" android:versionCode=""1"" android:versionName=""1.0"">
  <uses-sdk />
  <application android:label="""">
  </application>
</manifest>"))
            {
                PackageName = packageName,
                ApplicationLabel = appLabel
            };
        }

        public static AndroidAppManifest Load(string filename)
        {
            return Load(XDocument.Load(filename));
        }

        public static AndroidAppManifest Load(XDocument doc)
        {
            return new AndroidAppManifest(doc);
        }

        public void Write(XmlWriter writer)
        {
            doc.Save(writer);
        }

        public void WriteToFile(string fileName)
        {
            var xmlSettings = new XmlWriterSettings
            {
                Encoding = Encoding.UTF8,
                CloseOutput = false,
                Indent = true,
                IndentChars = "\t",
                NewLineChars = "\n"
            };
            using (var stream = File.OpenWrite(fileName))
            using (var writer = XmlWriter.Create(stream, xmlSettings))
            {
                Write(writer);
            }
        }

        private static string NullIfEmpty(string value)
        {<commit_msg>Wipes destination manifests on write. Resolves Issue #16<commit_after>﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;

namespace Cake.AndroidAppManifest
{
    public class AndroidAppManifest
    {
        private static readonly XNamespace aNS = "http://schemas.android.com/apk/res/android";
        private static readonly XName aName = aNS + "name";
        private readonly XDocument doc;
        private readonly XElement manifest;
        private readonly XElement application;
        private readonly XElement usesSdk;

        private AndroidAppManifest(XDocument doc)
        {
            this.doc = doc;
            manifest = doc.Root;
            if (manifest.Name != "manifest")
            {
                throw new Exception("App manifest does not have 'manifest' root element");
            }

            application = manifest.Element("application");
            if (application == null)
            {
                manifest.Add(application = new XElement("application"));
            }

            usesSdk = manifest.Element("uses-sdk");
            if (usesSdk == null)
            {
                manifest.Add(usesSdk = new XElement("uses-sdk"));
            }
        }

        public string PackageName
        {
            get { return (string)manifest.Attribute("package"); }
            set { manifest.SetAttributeValue("package", NullIfEmpty(value)); }
        }

        public string ApplicationLabel
        {
            get { return (string)application.Attribute(aNS + "label"); }
            set { application.SetAttributeValue(aNS + "label", NullIfEmpty(value)); }
        }

        public string ApplicationIcon
        {
            get { return (string)application.Attribute(aNS + "icon"); }
            set { application.SetAttributeValue(aNS + "icon", NullIfEmpty(value)); }
        }

        public string ApplicationTheme
        {
            get { return (string)application.Attribute(aNS + "theme"); }
            set { application.SetAttributeValue(aNS + "theme", NullIfEmpty(value)); }
        }

        public string VersionName
        {
            get { return (string)manifest.Attribute(aNS + "versionName"); }
            set { manifest.SetAttributeValue(aNS + "versionName", NullIfEmpty(value)); }
        }

        public int VersionCode
        {
            get { return this.ParseRequiredInt(manifest.Attribute(aNS + "versionCode")); }
            set { manifest.SetAttributeValue(aNS + "versionCode", value); }
        }

        public string InstallLocation
        {
            get { return (string)manifest.Attribute(aNS + "installLocation"); }
            set { manifest.SetAttributeValue(aNS + "installLocation", NullIfEmpty(value)); }
        }

        public int? MinSdkVersion
        {
            get { return ParseSdkVersion(usesSdk.Attribute(aNS + "minSdkVersion")); }
            set { usesSdk.SetAttributeValue(aNS + "minSdkVersion", value == null ? null : value.ToString()); }
        }

        public int? TargetSdkVersion
        {
            get { return ParseSdkVersion(usesSdk.Attribute(aNS + "targetSdkVersion")); }
            set { usesSdk.SetAttributeValue(aNS + "targetSdkVersion", value == null ? null : value.ToString()); }
        }

        public IEnumerable<string> AndroidPermissions
        {
            get
            {
                foreach (var el in manifest.Elements("uses-permission"))
                {
                    var name = (string)el.Attribute(aName);
                    if (name == null)
                    {
                        continue;
                    }
                    var lastDot = name.LastIndexOf('.');
                    if (lastDot >= 0)
                    {
                        yield return name.Substring(lastDot + 1);
                    }
                }
            }
        }

        public IEnumerable<string> AndroidPermissionsQualified
        {
            get
            {
                foreach (var el in manifest.Elements("uses-permission"))
                {
                    var name = (string)el.Attribute(aName);
                    if (name != null)
                    {
                        yield return name;
                    }
                }
            }
        }

        public bool? Debuggable
        {
            get { return (bool?)application.Attribute(aNS + "debuggable"); }
            set { application.SetAttributeValue(aNS + "debuggable", value); }
        }

        public static string CanonicalizePackageName(string packageNameOrAssemblyName)
        {
            if (packageNameOrAssemblyName == null)
            {
                throw new ArgumentNullException("packageNameOrAssemblyName");
            }

            if (string.IsNullOrEmpty(packageNameOrAssemblyName = packageNameOrAssemblyName.Trim()))
            {
                throw new ArgumentException("Must specify a package name or assembly name", "packageNameOrAssemblyName");
            }

            var packageParts = packageNameOrAssemblyName.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
            for (var i = 0; i < packageParts.Length; ++i)
            {
                packageParts[i] = Regex.Replace(packageParts[i], "[^A-Za-z0-9_]", "_");
                if (char.IsDigit(packageParts[i], 0) || packageParts[i][0] == '_')
                    packageParts[i] = "x" + packageParts[i];
            }

            return packageParts.Length == 1
                ? packageParts[0] + "." + packageParts[0]
                : string.Join(".", packageParts);
        }

        public static AndroidAppManifest Create(string packageName, string appLabel)
        {
            return new AndroidAppManifest(XDocument.Parse(
                @"<?xml version=""1.0"" encoding=""utf-8""?>
<manifest xmlns:android=""http://schemas.android.com/apk/res/android"" android:versionCode=""1"" android:versionName=""1.0"">
  <uses-sdk />
  <application android:label="""">
  </application>
</manifest>"))
            {
                PackageName = packageName,
                ApplicationLabel = appLabel
            };
        }

        public static AndroidAppManifest Load(string filename)
        {
            return Load(XDocument.Load(filename));
        }

        public static AndroidAppManifest Load(XDocument doc)
        {
            return new AndroidAppManifest(doc);
        }

        public void Write(XmlWriter writer)
        {
            doc.Save(writer);
        }

        public void WriteToFile(string fileName)
        {
            var xmlSettings = new XmlWriterSettings
            {
                Encoding = Encoding.UTF8,
                CloseOutput = false,
                Indent = true,
                IndentChars = "\t",
                NewLineChars = "\n"
            };
            using (var stream = File.Open(fileName, FileMode.Create))
            using (var writer = XmlWriter.Create(stream, xmlSettings))
            {
                Write(writer);
            }
        }

        private static string NullIfEmpty(string value)
        {
{'fraction_non_alphanumeric': 0.10264601708451976, 'fraction_numerical': 0.0025001736231682757, 'mean_word_length': 1.6701279436306322, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 2, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 8}, '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': '3101136', 'n_tokens_mistral': 3652, 'n_tokens_neox': 3491, 'n_words': 760}