using System;
using System.Threading.Tasks;
using MonoDevelop.ConnectedServices.Gui.ServicesTab;
using MonoDevelop.Core;
using MonoDevelop.Components;
using System.Threading;
using System.Linq;
namespace MonoDevelop.ConnectedServices
{
///
/// Builtin section object that displays the dependencies for the service
///
sealed class DependenciesSection: IConfigurationSection
{
bool isAdded;
bool initialized;
///
/// Initializes a new instance of the class.
///
public DependenciesSection (IConnectedService service)
{
this.Service = service;
this.DisplayName = GettextCatalog.GetString ("Dependencies");
// dependencies are added when the service is added, therefore it's not really optional
this.CanBeAdded = false;
this.isAdded = this.Service.AreDependenciesInstalled;
Service.StatusChanged += HandleServiceStatusChanged;
}
///
/// Gets the service for this section
///
public IConnectedService Service { get; private set; }
///
/// Gets the name of the section to display to the user.
///
public string DisplayName { get; private set; }
///
/// Gets the description of the section to display to the user.
///
public string Description { get; private set; }
///
/// Gets a value indidating if this section represents something that can be added to the project.
///
public bool CanBeAdded { get; private set; }
///
/// Gets a value indicating that whatever changes to the project that can be added by this section have been added.
///
public bool IsAdded {
get {
if (!initialized) {
isAdded = this.Service.AreDependenciesInstalled;
initialized = true;
}
return isAdded;
}
private set {
if (isAdded != value) {
isAdded = value;
if (isAdded)
NotifyAddedToProject ();
else
NotifyRemovedFromProject ();
}
}
}
///
/// Occurs when the status of the section changes
///
public event EventHandler StatusChanged;
///
/// Gets the widget to display to the user
///
public Control GetSectionWidget ()
{
return new DependenciesSectionWidget (this);
}
///
/// Adds the service dependencies to the project
///
public async Task AddToProject (CancellationToken token)
{
this.NotifyAddingToProject ();
// ask all the dependencies to add themselves to the project
// we'll do them one at a time in case there are interdependencies between them
// we are going to short circuit package dependencies though and install them in one go
var packages = this.Service.Dependencies.OfType ().Cast().ToList();
await this.Service.Project.AddPackageDependencies (packages).ConfigureAwait (false);
try {
foreach (var dependency in Service.Dependencies) {
if (packages.Contains (dependency)) {
continue;
}
await dependency.AddToProject (token).ConfigureAwait (false);
}
} catch (Exception ex) {
LoggingService.LogError ("Could not add dependency", ex);
NotifyAddingToProjectFailed ();
return IsAdded = false;
}
return IsAdded = true;
}
void HandleServiceStatusChanged (object sender, StatusChangedEventArgs e)
{
// update the status when the service is removed
if (e.WasRemoved) {
IsAdded = this.Service.AreDependenciesInstalled;
}
}
///
/// Invokes the Adding event on the main thread
///
void NotifyAddingToProject ()
{
this.NotifyStatusChange (Status.Adding, Status.NotAdded);
}
///
/// Notifies subscribers that adding the dependencies to the project has failed
///
void NotifyAddingToProjectFailed ()
{
this.NotifyStatusChange (Status.NotAdded, Status.Adding);
}
///
/// Notifies subscribers that all dependencies have been added to the project
///
void NotifyAddedToProject ()
{
this.NotifyStatusChange (Status.Added, Status.Adding);
}
///
/// Notifies subscribers that a dependency has been removed from the project
///
void NotifyRemovedFromProject ()
{
this.NotifyStatusChange (Status.NotAdded, Status.Removing);
}
void NotifyStatusChange(Status newStatus, Status oldStatus)
{
var handler = this.StatusChanged;
if (handler != null) {
// make sure this gets called on the main thread in case we have async calls for adding a nuget
Xwt.Application.Invoke (() => {
handler (this, new StatusChangedEventArgs (newStatus, oldStatus, null));
});
}
}
internal void HandleDependenciesChanged ()
{
IsAdded = this.Service.AreDependenciesInstalled;
}
}
}