/// <summary>
        /// Creates a new <see cref="NugetPackage"/> from the given <see cref="NuspecFile"/>.
        /// </summary>
        /// <param name="nuspec">The <see cref="NuspecFile"/> to use to create the <see cref="NugetPackage"/>.</param>
        /// <returns>The newly created <see cref="NugetPackage"/>.</returns>
        public static NugetPackage FromNuspec(NuspecFile nuspec)
        {
            NugetPackage package = new NugetPackage();

            package.Id           = nuspec.Id;
            package.Version      = nuspec.Version;
            package.Title        = nuspec.Title;
            package.Description  = nuspec.Description;
            package.ReleaseNotes = nuspec.ReleaseNotes;
            package.LicenseUrl   = nuspec.LicenseUrl;
            package.ProjectUrl   = nuspec.ProjectUrl;
            //package.DownloadUrl = not in a nuspec

            if (!string.IsNullOrEmpty(nuspec.IconUrl))
            {
                NugetImageLoader.TryDownloadImage(nuspec.IconUrl, tex => {
                    package.Icon = tex;
                });
            }

            package.RepositoryUrl = nuspec.RepositoryUrl;

            try
            {
                package.RepositoryType = (RepositoryType)Enum.Parse(typeof(RepositoryType), nuspec.RepositoryType, true);
            }
            catch (Exception) { }

            package.RepositoryBranch = nuspec.RepositoryBranch;
            package.RepositoryCommit = nuspec.RepositoryCommit;

            // if there is no title, just use the ID as the title
            if (string.IsNullOrEmpty(package.Title))
            {
                package.Title = package.Id;
            }

            package.Dependencies = nuspec.Dependencies;

            return(package);
        }
        /// <summary>
        /// Parses the given <see cref="XDocument"/> and returns the list of <see cref="NugetPackage"/>s contained within.
        /// </summary>
        /// <param name="document">The <see cref="XDocument"/> that is the OData XML response from the NuGet server.</param>
        /// <returns>The list of <see cref="NugetPackage"/>s read from the given XML.</returns>
        public static List <NugetPackage> Parse(XDocument document)
        {
            List <NugetPackage> packages = new List <NugetPackage>();

            var packageEntries = document.Root.Elements(XName.Get("entry", AtomNamespace));

            foreach (var entry in packageEntries)
            {
                NugetPackage package = new NugetPackage();
                package.Id          = entry.GetAtomElement("title").Value;
                package.DownloadUrl = entry.GetAtomElement("content").Attribute("src").Value;

                var entryProperties = entry.Element(XName.Get("properties", MetaDataNamespace));
                package.Title        = entryProperties.GetProperty("Title");
                package.Version      = entryProperties.GetProperty("Version");
                package.Description  = entryProperties.GetProperty("Description");
                package.ReleaseNotes = entryProperties.GetProperty("ReleaseNotes");
                package.LicenseUrl   = entryProperties.GetProperty("LicenseUrl");
                package.ProjectUrl   = entryProperties.GetProperty("ProjectUrl");

                string iconUrl = entryProperties.GetProperty("IconUrl");
                if (!string.IsNullOrEmpty(iconUrl))
                {
                    NugetImageLoader.TryDownloadImage(iconUrl, tex => {
                        package.Icon = tex;
                    });
                }

                // if there is no title, just use the ID as the title
                if (string.IsNullOrEmpty(package.Title))
                {
                    package.Title = package.Id;
                }

                // Get dependencies
                package.Dependencies = new List <NugetPackageIdentifier>();
                string rawDependencies = entryProperties.GetProperty("Dependencies");
                if (!string.IsNullOrEmpty(rawDependencies))
                {
                    var dependencyGroups = new Dictionary <string, NugetFrameworkGroup>();

                    string[] dependencies = rawDependencies.Split('|');
                    foreach (var dependencyString in dependencies)
                    {
                        string[] details    = dependencyString.Split(':');
                        var      dependency = new NugetPackageIdentifier(details[0], details[1]);

                        // some packages (ex: FSharp.Data - 2.1.0) have inproper "semi-empty" dependencies such as:
                        // "Zlib.Portable:1.10.0:portable-net40+sl50+wp80+win80|::net40"
                        // so we need to only add valid dependencies and skip invalid ones
                        if (string.IsNullOrEmpty(dependency.Id) && string.IsNullOrEmpty(dependency.Version))
                        {
                            continue;
                        }

                        string framework = string.Empty;
                        if (details.Length > 2)
                        {
                            framework = details[2];
                        }

                        NugetFrameworkGroup group;
                        if (dependencyGroups.TryGetValue(framework, out group))
                        {
                            group.Dependencies.Add(dependency);
                        }
                        else
                        {
                            group = new NugetFrameworkGroup();
                            group.Dependencies = new List <NugetPackageIdentifier>();
                            group.Dependencies.Add(dependency);
                            dependencyGroups.Add(framework, group);
                        }
                    }

                    // find the correct group for this project
                    int intDotNetVersion = (int)NugetHelper.DotNetVersion;
                    //bool using46 = DotNetVersion == ApiCompatibilityLevel.NET_4_6; // NET_4_6 option was added in Unity 5.6
                    bool using46 = intDotNetVersion == 3; // NET_4_6 = 3 in Unity 5.6 and Unity 2017.1 - use the hard-coded int value to ensure it works in earlier versions of Unity
                    NugetFrameworkGroup selectedGroup = null;

                    foreach (var kvPair in dependencyGroups.OrderByDescending(x => x.Key))
                    {
                        string framework          = kvPair.Key;
                        NugetFrameworkGroup group = kvPair.Value;

                        // Select the highest .NET library available that is supported
                        // See here: https://docs.nuget.org/ndocs/schema/target-frameworks
                        if (using46 && framework == "net462")
                        {
                            selectedGroup = group;
                            break;
                        }
                        else if (using46 && framework == "net461")
                        {
                            selectedGroup = group;
                            break;
                        }
                        else if (using46 && framework == "net46")
                        {
                            selectedGroup = group;
                            break;
                        }
                        else if (using46 && framework == "net452")
                        {
                            selectedGroup = group;
                            break;
                        }
                        else if (using46 && framework == "net451")
                        {
                            selectedGroup = group;
                            break;
                        }
                        else if (using46 && framework == "net45")
                        {
                            selectedGroup = group;
                            break;
                        }
                        else if (using46 && framework == "net403")
                        {
                            selectedGroup = group;
                            break;
                        }
                        else if (using46 && (framework == "net40" || framework == "net4"))
                        {
                            selectedGroup = group;
                            break;
                        }
                        else if (framework == "net35")
                        {
                            selectedGroup = group;
                            break;
                        }
                        else if (framework == "net20")
                        {
                            selectedGroup = group;
                            break;
                        }
                        else if (framework == "net11")
                        {
                            selectedGroup = group;
                            break;
                        }
                        else if (framework == string.Empty)
                        {
                            selectedGroup = group;
                            break;
                        }
                    }

                    if (selectedGroup != null)
                    {
                        package.Dependencies = selectedGroup.Dependencies;
                    }
                }

                packages.Add(package);
            }

            return(packages);
        }
        /// <summary>
        /// Use the Unity GUI to draw the controls.
        /// </summary>
        protected void OnGUI()
        {
            if (nuspec == null)
            {
                Reload();
            }

            if (nuspec == null)
            {
                titleContent = new GUIContent("[NO NUSPEC]");
                EditorGUILayout.LabelField("There is no .nuspec file selected.");
            }
            else
            {
                EditorGUIUtility.labelWidth = 100;
                nuspec.Id         = EditorGUILayout.TextField(new GUIContent("ID", "The name of the package."), nuspec.Id);
                nuspec.Version    = EditorGUILayout.TextField(new GUIContent("Version", "The semantic version of the package."), nuspec.Version);
                nuspec.Authors    = EditorGUILayout.TextField(new GUIContent("Authors", "The authors of the package."), nuspec.Authors);
                nuspec.Owners     = EditorGUILayout.TextField(new GUIContent("Owners", "The owners of the package."), nuspec.Owners);
                nuspec.LicenseUrl = EditorGUILayout.TextField(new GUIContent("License URL", "The URL for the license of the package."), nuspec.LicenseUrl);
                nuspec.ProjectUrl = EditorGUILayout.TextField(new GUIContent("Project URL", "The URL of the package project."), nuspec.ProjectUrl);
                nuspec.IconUrl    = EditorGUILayout.TextField(new GUIContent("Icon URL", "The URL for the icon of the package."), nuspec.IconUrl);

                EditorGUILayout.BeginHorizontal();
                {
                    const int iconSize    = 50;
                    const int leftPadding = 5;
                    var       rect        = GUILayoutUtility.GetRect(iconSize, iconSize);
                    rect.x      = leftPadding;
                    rect.width  = iconSize;
                    rect.height = iconSize;

                    if (icon != null)
                    {
                        GUI.DrawTexture(rect, icon, ScaleMode.StretchToFill);
                    }
                }
                EditorGUILayout.EndHorizontal();

                if (!initied || GUI.changed)
                {
                    initied = true;

                    if (currRequest != null)
                    {
                        currRequest.Dispose();
                    }

                    currRequest = NugetImageLoader.TryDownloadImage(nuspec.IconUrl, tex => {
                        icon = tex;
                    });
                }

                nuspec.RequireLicenseAcceptance = EditorGUILayout.Toggle(new GUIContent("Require License Acceptance", "Does the package license need to be accepted before use?"), nuspec.RequireLicenseAcceptance);
                nuspec.Description  = EditorGUILayout.TextField(new GUIContent("Description", "The description of the package."), nuspec.Description);
                nuspec.ReleaseNotes = EditorGUILayout.TextField(new GUIContent("Release Notes", "The release notes for this specific version of the package."), nuspec.ReleaseNotes);
                nuspec.Copyright    = EditorGUILayout.TextField(new GUIContent("Copyright", "The copyright details for the package."), nuspec.Copyright);
                nuspec.Tags         = EditorGUILayout.TextField(new GUIContent("Tags", "The space-delimited list of tags and keywords that describe the package and aid discoverability of packages through search and filtering."), nuspec.Tags);

                dependenciesExpanded = EditorGUILayout.Foldout(dependenciesExpanded, new GUIContent("Dependencies", "The list of NuGet packages that this packages depends on."));

                if (dependenciesExpanded)
                {
                    EditorGUILayout.BeginHorizontal();
                    {
                        GUILayout.Space(50);

                        // automatically fill in the dependencies based upon the "root" packages currently installed in the project
                        if (GUILayout.Button(new GUIContent("Automatically Fill Dependencies", "Populates the list of dependencies with the \"root\" NuGet packages currently installed in the project.")))
                        {
                            NugetHelper.UpdateInstalledPackages();
                            List <NugetPackage> installedPackages = NugetHelper.InstalledPackages.ToList();

                            // default all packages to being roots
                            List <NugetPackage> roots = new List <NugetPackage>(installedPackages);

                            // remove a package as a root if another package is dependent on it
                            foreach (NugetPackage package in installedPackages)
                            {
                                foreach (NugetPackageIdentifier dependency in package.Dependencies)
                                {
                                    roots.RemoveAll(p => p.Id == dependency.Id);
                                }
                            }

                            // remove all existing dependencies from the .nuspec
                            nuspec.Dependencies.Clear();

                            nuspec.Dependencies = roots.Cast <NugetPackageIdentifier>().ToList();
                        }
                    }
                    EditorGUILayout.EndHorizontal();

                    // display the dependencies
                    NugetPackageIdentifier toDelete = null;
                    foreach (var dependency in nuspec.Dependencies)
                    {
                        EditorGUILayout.BeginHorizontal();
                        GUILayout.Space(75);
                        float prevLabelWidth = EditorGUIUtility.labelWidth;
                        EditorGUIUtility.labelWidth = 50;
                        dependency.Id = EditorGUILayout.TextField(new GUIContent("ID", "The ID of the dependency package."), dependency.Id);
                        EditorGUILayout.EndHorizontal();

                        //int oldSeletedIndex = IndexOf(ref existingComponents, dependency.Id);
                        //int newSelectIndex = EditorGUILayout.Popup("Name", oldSeletedIndex, existingComponents);
                        //if (oldSeletedIndex != newSelectIndex)
                        //{
                        //    dependency.Name = existingComponents[newSelectIndex];
                        //}

                        EditorGUILayout.BeginHorizontal();
                        GUILayout.Space(75);
                        dependency.Version = EditorGUILayout.TextField(new GUIContent("Version", "The version number of the dependency package. (specify ranges with =><)"), dependency.Version);
                        EditorGUILayout.EndHorizontal();

                        EditorGUILayout.BeginHorizontal();
                        {
                            GUILayout.Space(75);

                            if (GUILayout.Button("Remove " + dependency.Id))
                            {
                                toDelete = dependency;
                            }
                        }
                        EditorGUILayout.EndHorizontal();

                        EditorGUILayout.Separator();

                        EditorGUIUtility.labelWidth = prevLabelWidth;
                    }

                    if (toDelete != null)
                    {
                        nuspec.Dependencies.Remove(toDelete);
                    }

                    EditorGUILayout.BeginHorizontal();
                    {
                        GUILayout.Space(50);

                        if (GUILayout.Button("Add Dependency"))
                        {
                            nuspec.Dependencies.Add(new NugetPackageIdentifier());
                        }
                    }
                    EditorGUILayout.EndHorizontal();
                }

                EditorGUILayout.Separator();

                if (GUILayout.Button(string.Format("Save {0}", Path.GetFileName(filepath))))
                {
                    nuspec.Save(filepath);
                }

                EditorGUILayout.Separator();

                if (GUILayout.Button(string.Format("Pack {0}.nupkg", Path.GetFileNameWithoutExtension(filepath))))
                {
                    NugetHelper.Pack(filepath);
                }

                EditorGUILayout.Separator();

                apiKey = EditorGUILayout.TextField(new GUIContent("API Key", "The API key to use when pushing the package to the server"), apiKey);

                if (GUILayout.Button(string.Format("Push to Server")))
                {
                    NugetHelper.Push(nuspec, filepath, apiKey);
                }
            }
        }