//TODO: MOve to extension method...
        public async static Task<string> GetPropertyValueAsync(ZvsContext Context, Scene scene, string scenePropertyUniqueIdentifier)
        {
            //Find the property
            SceneSetting property = await Context.SceneSettings.FirstOrDefaultAsync(p => p.UniqueIdentifier == scenePropertyUniqueIdentifier);
            
            if (property == null)
                return string.Empty;

            Scene s2 = await Context.Scenes.Include(o=> o.SettingValues).FirstOrDefaultAsync(o => o.Id == scene.Id);

            if (s2 == null)
                return string.Empty;

            SceneSettingValue spv = s2.SettingValues.FirstOrDefault(o => o.SceneSetting == property);
                
            //Check to see if the property has been set yet, otherwise return the default value for this property.
            if (spv != null)
                return spv.Value;

            return property.Value; //default value
        }
        private async void ButtonDuplicate_OnClick(object sender, RoutedEventArgs e)
        {
            var scene = SceneGrid.SelectedItem as Scene;
            if (scene == null) return;

            if (MessageBox.Show("Are you sure you want to duplicate this scene?",
                   "Are you sure?", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes) return;

            var newScene = new Scene { Name = "Copy of " + scene.Name, SortOrder = SceneGrid.Items.Count + 1 };
            foreach (var sc in scene.Commands)
            {
                newScene.Commands.Add(new SceneStoredCommand
                {
                    Argument = sc.Argument,
                    Argument2 = sc.Argument2,
                    CommandId = sc.CommandId,
                    Description = sc.Description,
                    TargetObjectName = sc.TargetObjectName,
                    SortOrder = sc.SortOrder
                });
                SceneGrid.Focus();
            }
            _context.Scenes.Local.Add(newScene);
            var result = await _context.TrySaveChangesAsync(_app.Cts.Token);
            if (result.HasError)
                await Log.ReportErrorFormatAsync(_app.Cts.Token, "Error duplicating scene. {0}", result.Message);
        }
        private async Task<bool> DeleteSelectedScene(Scene scene)
        {
            if (
                MessageBox.Show($"Are you sure you want to delete the '{scene.Name}' scene?",
                    "Are you sure?", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
                return false;
            if (scene.IsRunning)
                ShowSceneEditWarning(scene.Name);
            else
                _context.Scenes.Local.Remove(scene);

            var result = await _context.TrySaveChangesAsync(_app.Cts.Token);
            if (result.HasError)
                await Log.ReportErrorFormatAsync(_app.Cts.Token, "Error deleting scene. {0}", result.Message);

            SceneGrid.Focus();
            return true;
        }
        public async Task RunSceneAsyncMultipleCommandCancelRunTest()
        {
            //Arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "Scene-RunSceneAsyncMultipleCommandCancelRunTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());

            var logEntries = new List<LogEntry>();
            var ranstoredCommands = new List<int>();

            var log = new StubIFeedback<LogEntry>
            {
                ReportAsyncT0CancellationToken = (e, c) =>
                {
                    Console.WriteLine(e);
                    logEntries.Add(e);
                    return Task.FromResult(0);
                }
            };
            var cts = new CancellationTokenSource();
            var commandProcessor = new StubICommandProcessor
            {
                RunCommandAsyncNullableOfInt32StringStringCancellationToken = ( commandId, argument, argument2, cancellationToken) =>
                {
                    if (commandId.HasValue) ranstoredCommands.Add(commandId.Value);
                    if (ranstoredCommands.Count == 2)
                    {
                        cts.Cancel();
                    }

                    return Task.FromResult(Result.ReportSuccessFormat("Ran command Id:{0}", commandId));
                }
            };
            var scene = new Scene
            {
                Name = "I have one command"
            };

            var cmd1 = new Command
            {
                Description = "Command 1"
            };
            var command1 = new SceneStoredCommand
            {
                SortOrder = 1,
                TargetObjectName = "Device 1",
                Description = "Turn On Device 1",
                Command = cmd1
            };

            var cmd2 = new Command
            {
                Description = "Command 2"
            };
            var command2 = new SceneStoredCommand
            {
                SortOrder = 2,
                Description = "TIME DELAY",
                Command = cmd2
            };

            var cmd3 = new Command
            {
                Description = "Command 3"
            };
            var command3 = new SceneStoredCommand
            {
                SortOrder = 3,
                TargetObjectName = "Device 3",
                Description = "Turn On Device 3",
                Command = cmd3
            };

            scene.Commands.Add(command3);
            scene.Commands.Add(command1);
            scene.Commands.Add(command2);

            using (var context = new ZvsContext(dbConnection))
            {
                context.Scenes.Add(scene);
                await context.SaveChangesAsync(CancellationToken.None);
            }

           
            var sceneRunner = new SceneRunner(log, commandProcessor, dbConnection);

            //Act
            var result = await sceneRunner.RunSceneAsync(scene.Id, cts.Token);

            Console.WriteLine(result.Message);

            //Assert
            Assert.IsFalse(result.HasError);
            Assert.IsTrue(logEntries.Count(o => o.Level == LogEntryLevel.Warn) == 0, "Expected one warning log entries");
            Assert.IsTrue(logEntries.Count(o => o.Level == LogEntryLevel.Error) == 0, "Expected zero error log entries");
            Assert.IsTrue(ranstoredCommands.Count == 2, "Scene runner did not run the correct amount of commands.");
        }
        public async Task RunSceneAsyncSceneNoCommandsTest()
        {
            //Arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "Scene-RunSceneAsyncSceneNoCommandsTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());

            var logEntries = new List<LogEntry>();
            var ranstoredCommands = new List<int>();

            var log = new StubIFeedback<LogEntry>
            {
                ReportAsyncT0CancellationToken = (e, c) =>
                {
                    Console.WriteLine(e.ToString());
                    logEntries.Add(e);
                    return Task.FromResult(0);
                }
            };

            var commandProcessor = new StubICommandProcessor
            {
                RunCommandAsyncNullableOfInt32StringStringCancellationToken = ( commandId, argument, argument2, cancellationToken) =>
                {
                    if (commandId.HasValue) ranstoredCommands.Add(commandId.Value);
                    return Task.FromResult(Result.ReportSuccess());
                }
            };

            var scene = new Scene
            {
                Name = "I have no commands"
            };

            using (var context = new ZvsContext(dbConnection))
            {
                context.Scenes.Add(scene);
                await context.SaveChangesAsync(CancellationToken.None);
            }

            var cts = new CancellationTokenSource();
            var sceneRunner = new SceneRunner(log, commandProcessor, dbConnection);

            //Act
            var result = await sceneRunner.RunSceneAsync(scene.Id, cts.Token);

            //Assert
            Assert.IsTrue(result.HasError);
            Assert.IsTrue(logEntries.All(o => o.Level == LogEntryLevel.Warn), "Expected only info type log entries");
            Assert.IsTrue(ranstoredCommands.Count == 0, "Scene runner did not run the correct amount of commands.");
        }
        public async Task ExecuteBuiltinCommandAsyncSceneTest()
        {
            //Arrange 
            var dbConnection = new UnitTestDbConnection();
            Database.SetInitializer(new CreateFreshDbInitializer());

            var deviceCommandIds = new List<int>();
            var adapterManager = new StubIAdapterManager
            {
                FindZvsAdapterGuid = adapterGuid => new StubZvsAdapter
                {
                    IsEnabled = true,
                    ProcessDeviceCommandAsyncDeviceDeviceCommandStringString = async (adapterDevice, command, argument, argument2) => deviceCommandIds.Add(command.Id)
                }
            };
            var log = new StubIFeedback<LogEntry>
            {
                ReportAsyncT0CancellationToken = (e, c) =>
                {
                    Console.WriteLine(e);
                    return Task.FromResult(0);
                }
            };

            var cts = new CancellationTokenSource();
            var commmandProcessor = new CommandProcessor(adapterManager, dbConnection, log);

            var device = UnitTesting.CreateFakeDevice();
            using (var context = new ZvsContext(dbConnection))
            {
                var deviceCommand = new DeviceCommand
                {
                    Name = "Turn On"
                };
                device.Commands.Add(deviceCommand);
                context.Devices.Add(device);

                var scene = new Scene
                {
                    Name = "Test Scene"
                };
                scene.Commands.Add(new SceneStoredCommand
                {
                    Command = deviceCommand,
                    Argument = "0"
                });
                context.Scenes.Add(scene);

                var builtinCommand = new BuiltinCommand
                {
                    Name = "Activate Scene",
                    UniqueIdentifier = "RUN_SCENE"
                };
                context.Commands.Add(builtinCommand);
                await context.SaveChangesAsync(new CancellationToken());

                //Act
                var result = await commmandProcessor.ExecuteBuiltinCommandAsync(builtinCommand, scene.Id.ToString(CultureInfo.InvariantCulture), "", cts.Token);
                Console.WriteLine(result.Message);

                //Assert
                Assert.IsFalse(result.HasError);
                Assert.IsTrue(deviceCommandIds.Count == 1, "Process did not run the correct amount of commands.");
                Assert.IsTrue(deviceCommand.Id == deviceCommandIds[0], "Ran the wrong scene!");
            }
        }
        public async override Task<Result> ImportAsync(string fileName, CancellationToken cancellationToken)
        {
            var result = await ReadAsXmlFromDiskAsync<List<SceneBackup>>(fileName);

            if (result.HasError)
                return Result.ReportError(result.Message);

            var skippedCount = 0;
            var newScene = new List<Scene>();
            var importedCmdCount = 0;

            using (var context = new ZvsContext(EntityContextConnection))
            {
                var existingScenes = await context.Scenes.ToListAsync(cancellationToken);
                foreach (var backupScene in result.Data)
                {
                    if (existingScenes.Any(o => o.Name == backupScene.Name))
                    {
                        skippedCount++;
                        continue;
                    }

                    var s = new Scene {Name = backupScene.Name};

                    foreach (var backupSceneCmd in backupScene.Commands)
                    {
                        var sc = await StoredCmdBackup.RestoreStoredCommandAsync(context, backupSceneCmd.StoredCommand,cancellationToken);
                        if (sc == null) continue;
                        s.Commands.Add(new SceneStoredCommand
                        {
                            Argument = sc.Argument,
                            Argument2 = sc.Argument2,
                            CommandId = sc.CommandId,
                            SortOrder = backupSceneCmd.Order
                        });
                        importedCmdCount++;
                    }
                    newScene.Add(s);
                }

                context.Scenes.AddRange(newScene);

                if (newScene.Count > 0)
                {
                    var saveResult = await context.TrySaveChangesAsync(cancellationToken);
                    if (saveResult.HasError)
                        return Result.ReportError(saveResult.Message);
                }
            }
            return Result.ReportSuccess(
                $"Imported {newScene.Count} scenes with {importedCmdCount} scene commands. Skipped {skippedCount} scene from {Path.GetFileName(fileName)}");
        }
        public async Task RunSceneAsyncOneCommandTest()
        {
            //Arrange 
            var dbConnection = new UnitTestDbConnection();
            Database.SetInitializer(new CreateFreshDbInitializer());

            var logEntries = new List<LogEntry>();
            var ranstoredCommands = new List<int>();

            var log = new StubIFeedback<LogEntry>
            {
                ReportAsyncT0CancellationToken = (e, c) =>
                {
                    Console.WriteLine(e.ToString());
                    logEntries.Add(e);
                    return Task.FromResult(0);
                }
            };

            var commandProcessor = new StubICommandProcessor
            {
                RunCommandAsyncNullableOfInt32StringStringCancellationToken = ( commandId, argument, argument2, cancellationToken) =>
                {
                    if (commandId.HasValue) ranstoredCommands.Add(commandId.Value);
                    return Task.FromResult(Result.ReportSuccessFormat("Ran command Id:{0}", commandId));
                }
            };
            var scene = new Scene
            {
                Name = "I have one command"
            };

            var command1 = new SceneStoredCommand
            {
                SortOrder = 1,
                TargetObjectName = "Device 1",
                Description = "Turn On",
                Command = new Command
                {
                    Description = "Command 1"
                }
            };

            scene.Commands.Add(command1);

            using (var context = new ZvsContext(dbConnection))
            {
                context.Scenes.Add(scene);
                await context.SaveChangesAsync(CancellationToken.None);
            }

            var cts = new CancellationTokenSource();
            var sceneRunner = new SceneRunner(log, commandProcessor, dbConnection);

            //Act
            var result = await sceneRunner.RunSceneAsync(scene.Id, cts.Token);
            Console.WriteLine(result.Message);

            //Assert
            Assert.IsFalse(result.HasError);
            Assert.IsTrue(logEntries.All(o => o.Level == LogEntryLevel.Info), "Expected only info type log entries");
            Assert.IsTrue(ranstoredCommands.Count == 1, "Scene runner did not run the correct amount of commands.");
            Assert.IsTrue(ranstoredCommands.All(o => o == command1.Id), "Scene runner did not run the correct command.");
        }