Task ICommandHandler <ViewItemPropertiesFromProjectCommandDefinition> .Run(Command command)
        {
            // Really
            void BuildDependency(ProjectItem item, FactorioModificationDependency dependency)
            {
                var oldJsonRaw = dependency.JsonRaw();

                dependency.PropertyChanged += (s, e) =>
                {
                    item.Text = dependency.DisplayText;
                    item.Tag  = dependency.JsonRaw();
                    if (e.PropertyName.Equals(nameof(dependency.State), StringComparison.OrdinalIgnoreCase))
                    {
                        var projectParent = item.GetItemProjectRoot();
                        if (projectParent.Tag is FactorioProjectInfo project)
                        {
                            FactorioModificationDependency dep = null;
                            if (dep == null) // Really
                            {
                                dep = project.Dependencies
                                      .OfType <FactorioModificationDependency>()
                                      .SingleOrDefault(fmd => fmd.JsonRaw().Equals(oldJsonRaw, StringComparison.InvariantCulture));
                            }

                            if (dep == null) // Really
                            {
                                dep = project.Dependencies
                                      .OfType <FactorioModificationDependency>()
                                      .SingleOrDefault(fmd => fmd == dependency);
                            }

                            project.Dependencies.Remove(dep);
                            project.Dependencies.Add(dependency);
                        }
                    }
                };

                InspectorTool.DisplayName = item.Text;
                var properties = TypeDescriptor.GetProperties(dependency);

                InspectorTool.SelectedObject = new InspectableObjectBuilder()
                                               .WithEditor(dependency, d => d.Name, new TextBoxEditorViewModel <string>())
                                               .WithEditor(dependency, d => d.State, new Inspectors.EnumEditorViewModel <FactorioModificationDependency.DependencyState>())
                                               .WithEditor(dependency, d => d.Version, new VersionEditorViewModel())
                                               .WithEditor(dependency, d => d.VersionRequirement, new FactrIDE.Gemini.Modules.SolutionExplorer.Inspectors.EnumEditorViewModel <FactorioModificationDependency.VersionState>())
                                               .ToInspectableObject();
                Shell.ShowTool(InspectorTool);
            }

            if (command.Tag is ProjectItem item)
            {
                if (item.ProjectItemDefintion is FactorioProjectItemDefinition && item.Tag is FactorioProjectInfo project)
                {
                    var projectFile = project.Folder.GetFile("info.json");
                    var data        = JsonConvert.DeserializeObject <FactorioProjectData>(projectFile.ReadAllText());
                    data.PropertyChanged += (s, e) =>
                    {
                        project.Data = data;

                        projectFile.WriteAllText(JsonConvert.SerializeObject(data, Formatting.Indented));
                        item.Text = $"{data.Name}_{data.Version}";
                    };

                    InspectorTool.DisplayName = item.Text;
                    var properties = TypeDescriptor.GetProperties(data);
                    InspectorTool.SelectedObject = new InspectableObjectBuilder()
                                                   .WithEditor(data, d => d.Name, new TextBoxEditorViewModel <string>())
                                                   .WithEditor(data, d => d.Version, new VersionEditorViewModel())
                                                   .WithEditor(data, d => d.Title, new TextBoxEditorViewModel <string>())
                                                   .WithEditor(data, d => d.Description, new TextBoxEditorViewModel <string>())
                                                   .WithEditor(data, d => d.Author, new TextBoxEditorViewModel <string>())
                                                   .WithEditor(data, d => d.Contact, new TextBoxEditorViewModel <string>())
                                                   .WithEditor(data, d => d.Homepage, new TextBoxEditorViewModel <string>())
                                                   .WithEditor(data, d => d.FactorioVersion, new VersionEditorViewModel())
                                                   .ToInspectableObject();

                    Shell.ShowTool(InspectorTool);
                }
                else if (item.ProjectItemDefintion is FactorioDependencyProjectItemDefinition && item.Tag is string jsonRaw)
                {
                    var dependency = new FactorioModificationDependency(jsonRaw);
                    BuildDependency(item, dependency);
                }
            }

            return(Task.CompletedTask);
        }
        async Task ICommandHandler <OpenDependencyFromProjectCommandDefinition> .Run(Command command)
        {
            if (command.Tag is ProjectItem item)
            {
                if (item.ProjectItemDefintion is FactorioDependencyProjectItemDefinition && item.Tag is string jsonRaw)
                {
                    var dependency = new FactorioModificationDependency(jsonRaw);

                    var folder = new ModificationCacheFolder();

                    //if(folder.CheckExistsAsync())

                    FactorioAPI.UpdateToken();
                    var     mod     = FactorioAPI.GetModificationInfo(dependency.Name);
                    Release release = null;
                    switch (dependency.VersionRequirement)
                    {
                    case FactorioModificationDependency.VersionState.Exact:
                        release = mod.Releases
                                  .FirstOrDefault(m => (Version.TryParse(m.Version, out var v) ? v : new Version()) == dependency.Version);
                        break;

                    case FactorioModificationDependency.VersionState.GreatherThan:
                        release = mod.Releases
                                  .OrderByDescending(m => Version.TryParse(m.Version, out var v) ? v : new Version())
                                  .FirstOrDefault(m => (Version.TryParse(m.Version, out var v) ? v : new Version()) > dependency.Version);
                        break;

                    case FactorioModificationDependency.VersionState.GreatherThanExact:
                        release = mod.Releases
                                  .OrderByDescending(m => Version.TryParse(m.Version, out var v) ? v : new Version())
                                  .FirstOrDefault(m => (Version.TryParse(m.Version, out var v) ? v : new Version()) >= dependency.Version);
                        break;

                    case FactorioModificationDependency.VersionState.LowerThan:
                        release = mod.Releases
                                  .OrderBy(m => Version.TryParse(m.Version, out var v) ? v : new Version())
                                  .FirstOrDefault(m => (Version.TryParse(m.Version, out var v) ? v : new Version()) < dependency.Version);
                        break;

                    case FactorioModificationDependency.VersionState.LowerThanExact:
                        release = mod.Releases
                                  .OrderBy(m => Version.TryParse(m.Version, out var v) ? v : new Version())
                                  .FirstOrDefault(m => (Version.TryParse(m.Version, out var v) ? v : new Version()) <= dependency.Version);
                        break;
                    }
                    if (release != null)
                    {
                        var modData = FactorioAPI.GetModification(release.DownloadUrl);
                        var file    = await folder.CreateFileAsync(release.Filename, PCLExt.FileStorage.CreationCollisionOption.ReplaceExisting).ConfigureAwait(false);

                        await file.WriteAllBytesAsync(modData).ConfigureAwait(false);

                        Process.Start(new ProcessStartInfo()
                        {
                            FileName        = file.Path,
                            UseShellExecute = true,
                            Verb            = "open"
                        });
                    }
                }
            }
        }