/// <summary>
        /// Retrive a list of compatible software Version for a specific host
        /// The result can be multiple versions of the software content's if it's a suite.
        /// </summary>
        /// <param name="depotKey"></param>
        /// <param name="appId"></param>
        /// <param name="host"></param>
        /// <param name="completionCallback"></param>
        /// <param name="errorCallback"></param>
        public static void GetCompatibleSoftwareVersions(string depotKey, string appId, PlaygroundHost host, Action<IList<SoftwareVersion>> completionCallback, Action<ErrorResponse> errorCallback = null)
        {
            if (string.IsNullOrEmpty(depotKey)) throw new ArgumentNullException("depotKey");
            if (string.IsNullOrEmpty(appId)) throw new ArgumentNullException("appId");
            if (host == null) throw new ArgumentNullException("host");

            Settings settings = Settings.GetSettings();
            if (settings == null) throw new InvalidOperationException("settings is null");

            GetCompatibleSoftwareVersion(settings.WarehouseIP, settings.WarehousePort, depotKey, appId, host.Information == null ? null : host.Information.StarcounterVersion, (versionsJson) => {
                try {
                    IList<SoftwareVersion> result = new List<SoftwareVersion>();

                    foreach (var versionJson in versionsJson.Versions) {

                        // Check for duplicates
                        string sourceUrl = string.Format("http://{0}:{1}{2}", settings.WarehouseIP, settings.WarehousePort, versionJson.Url);

                        foreach (SoftwareVersion item in result) {
                            if (item.SourceUrl == sourceUrl) {
                                continue;
                            }
                        }

                        SoftwareVersion softwareVersion = new SoftwareVersion();
                        softwareVersion.Namespace = versionJson.Namespace;
                        softwareVersion.SourceUrl = sourceUrl;
                        softwareVersion.Channel = versionJson.Channel;
                        softwareVersion.Version = versionJson.Name;
                        softwareVersion.Compatiblility = versionJson.Compatiblility;

                        result.Add(softwareVersion);
                    }

                    if (completionCallback != null) {
                        try {
                            completionCallback(result);
                        }
                        catch (Exception e) {
                            Program.PlaygroundKeeperLogSource.LogError(string.Format("UnhandledException, {0}", e.ToString()));
                        }
                    }
                }
                catch (Exception e) {
                    Utils.CallBack(errorCallback, e);
                }
            }, errorCallback);
        }
        private static void SyncHost(PlaygroundHost host, Action completionCallback, Action<ErrorResponse> errorCallback)
        {
            // TODO:

            if (completionCallback != null) {
                completionCallback();
            }
        }
 public TaskItem(TaskFlag flag, Playground hive = null, PlaygroundHost host = null, string depotKey = null, string appId = null)
 {
     this.Flag = flag;
     this.Hive = hive;
     this.Host = host;
     this.DepotKey = depotKey;
     this.AppId = appId;
 }
        /// <summary>
        /// Create a new hive on a host
        /// </summary>
        /// <remarks>
        /// The hive name is the current signed in user username.
        /// </remarks>
        /// <param name="host"></param>
        /// <param name="completionCallback"></param>
        /// <param name="progressCallback"></param>
        /// <param name="errorCallback"></param>
        public static void CreateHive(PlaygroundHost host, Action<Playground> completionCallback = null, Action<string, double> progressCallback = null, Action<ErrorResponse> errorCallback = null)
        {
            if (host == null) throw new ArgumentNullException("host");

            ConcurrentQueue<TaskItem> tasks = new ConcurrentQueue<TaskItem>();      // FIFO
            ConcurrentStack<TaskItem> revertList = new ConcurrentStack<TaskItem>(); // LIFO

            SystemUser user = SystemUser.GetCurrentSystemUser();
            if (user == null) {
                Utils.CallBack(errorCallback, Utils.GenerateError("Anonymous user can not create a hive"));
                return;
            }

            Playground hive = null;
            Db.Transact(() => {
                hive = new Playground();
                hive.PlaygroundHost = host;
                hive.Owner = user;
                hive.Created = hive.Updated = DateTime.UtcNow;
            });

            // Add tasks
            tasks.Enqueue(new TaskItem(TaskFlag.AllocatedPort, hive, host));
            tasks.Enqueue(new TaskItem(TaskFlag.CreateDatabase, hive, host));
            tasks.Enqueue(new TaskItem(TaskFlag.AddReverseProxy, hive, host));

            if (!string.IsNullOrEmpty(host.EntryPoint)) {
                tasks.Enqueue(new TaskItem(TaskFlag.AddUriAlias, hive, host));
            }

            // Install default apps
            QueryResultRows<DefaultApp> defaultApps = Db.SQL<DefaultApp>("SELECT o FROM PlaygroundKeeper.DefaultApp o WHERE o.PlaygroundHost=?", host);
            foreach (DefaultApp defaultApp in defaultApps) {
                tasks.Enqueue(new TaskItem(TaskFlag.InstallSoftware, hive, host, defaultApp.DepotKey, defaultApp.ID));
            }

            ProcessTasks(tasks, revertList, () => {

                try {
                    // Find created hive
                    foreach (TaskItem item in revertList) {
                        if (item.Hive != null) {
                            if (completionCallback != null) {
                                try {
                                    completionCallback(item.Hive);
                                }
                                catch (Exception e) {
                                    Program.PlaygroundKeeperLogSource.LogError(string.Format("UnhandledException, {0}", e.ToString()));
                                }
                            }
                            return;
                        }
                    }

                    Utils.CallBack(errorCallback, Utils.GenerateError("Failed to find the created hive."));
                }
                catch (Exception e) {
                    Utils.CallBack(errorCallback, Utils.GenerateError(e));
                }
            }, progressCallback, errorCallback);
        }