private void OnSolved(BackgroundJob job, Step[][] solutions)
        {
            if (job.CancellationTokenSource.IsCancellationRequested)
            {
                return;
            }

            this.Status = SolverServiceStatus.Solved;
            this.Solutions = solutions
                .OrderBy(solution => string.Join(",", solution))
                .Select(solution => solution.Select(step => new SolutionStep(step, SolutionStepStatus.NotSteppedYet)).ToList())
                .ToList();

            this.SolutionLength = solutions[0].Length;
            this.nextStepIndex = 0;
            this.solvedBoardState = job.StateToSolve;

            this.messageBus.Publish(new SolutionsFound(job.InitialState, job.StateToSolve, solutions));
        }
        private void OnSlideHappened(SlideHappened message)
        {
            if (this.Solutions == null)
            {
                return;
            }

            this.Status = SolverServiceStatus.NotSolved;
            if (this.nextStepIndex >= this.SolutionLength)
            {
                return;
            }

            foreach (IReadOnlyList<SolutionStep> solution in this.Solutions)
            {
                if (solution[this.nextStepIndex].Status == SolutionStepStatus.Misstepped)
                {
                    continue;
                }

                if (solution[this.nextStepIndex].Step == message.Step)
                {
                    solution[this.nextStepIndex].Status = SolutionStepStatus.Stepped;
                }
                else
                {
                    for (int i = this.nextStepIndex; i < solution.Count; i++)
                    {
                        solution[i].Status = SolutionStepStatus.Misstepped;
                    }
                }
            }

            this.nextStepIndex++;
        }
        private void OnBoardResetted(BoardResetted message)
        {
            if (this.Solutions == null)
            {
                return;
            }

            if (this.gameService.BoardState.Equals(this.solvedBoardState))
            {
                this.nextStepIndex = 0;
                foreach (IReadOnlyList<SolutionStep> solution in this.Solutions)
                {
                    foreach (SolutionStep solutionStep in solution)
                    {
                        solutionStep.Status = SolutionStepStatus.NotSteppedYet;
                    }
                }
            }
            else
            {
                this.Status = SolverServiceStatus.NotSolved;
                this.Solutions = null;
                this.SolutionLength = null;
                if (this.AutoSolve)
                {
                    this.StartSolveCurrentBoard();
                }
            }
        }
        private void OnBoardScrambled(BoardScrambled message)
        {
            if (this.Status == SolverServiceStatus.Solving)
            {
                this.currentBackgroundJob.CancellationTokenSource.Cancel();
            }

            this.Status = SolverServiceStatus.NotSolved;
            this.Solutions = null;
            this.SolutionLength = null;
            if (this.AutoSolve)
            {
                this.StartSolveCurrentBoard();
            }
        }
        public void StartSolveCurrentBoard()
        {
            if (this.Status != SolverServiceStatus.NotSolved)
            {
                return;
            }

            this.Status = SolverServiceStatus.Solving;
            this.Solutions = null;
            this.currentBackgroundJob = new BackgroundJob
            {
                InitialState = this.gameService.InitialState,
                StateToSolve = this.gameService.BoardState,
                Goal = this.gameService.Drill.Goal,
                CancellationTokenSource = new CancellationTokenSource()
            };

            Task.Factory.StartNew(() => this.BackgroundThreadMain(this.currentBackgroundJob), this.currentBackgroundJob.CancellationTokenSource.Token);
        }