/// <summary>
        /// Cancel any current operations
        /// </summary>
        public void Cancel()
        {
            switch (_state)
            {
            case States.ScanQueued:
            {
                _state = States.Idle;
                break;
            }

            case States.Scanning:
            {
                AbortScan();
                break;
            }

            case States.Compiling:
            {
                AbortCompile();
                break;
            }

            case States.Waiting:
            {
                _compileController = null;
                _state             = States.Idle;

                break;
            }
            }
        }
        private void AbortCompile()
        {
            if (_state != States.Compiling)
            {
                throw new InvalidOperationException();
            }

            if (_compileController != null)
            {
                _compileController.Abort();
                _compileController = null;
            }

            _state = States.Idle;
            TSLog.EndBuffer(LogCategory.Compile, false);
        }
        private void BeginCompile()
        {
            if (_scanResult == null)
            {
                throw new InvalidOperationException();
            }

            TSLog.Log(LogCategory.Trace, "BeginCompile");

            _state = States.Compiling;

            _compileController = new CompileController();
            _compileController.ResourceDatabase = _scanResult.ResourceDatabase;
            _compileController.DataUnits        = _scanResult.DataUnits;

            _compileController.Compile();
        }
        private void Step()
        {
            switch (State)
            {
            case States.Idle:
                break;

            case States.ScanQueued:

                if (!TypeSafeUtil.ShouldBeOperating())
                {
                    break;
                }

                BeginScan();

                break;

            case States.Scanning:

                if (_scanController == null)
                {
                    TSLog.LogError(LogCategory.Trace, "ScanController = null, but State = Scanning");
                    _state = States.Idle;
                    break;
                }

                if (!TypeSafeUtil.ShouldBeOperating())
                {
                    TSLog.Log(LogCategory.Trace, "Aborting scan due to script reload in progress.");

                    Cancel();
                    Queue();
                    break;
                }

                _scanController.Update();

                ItemsCompleted = _scanController.ItemsCompleted;
                TotalItems     = _scanController.TotalItems;

                if (_scanController.IsDone)
                {
                    TSLog.Log(LogCategory.Trace, string.Format("Scan complete (took {0}s).", _stopwatch.Elapsed.TotalSeconds));

                    if (_scanController.WasSuccessful)
                    {
                        _scanResult     = _scanController.Result;
                        _scanController = null;
                        BeginCompile();
                    }
                    else
                    {
                        TSLog.LogError(LogCategory.Info, "Error occured while scanning. Aborting process.");
                        _state = States.Idle;
                    }
                }

                break;

            case States.Compiling:
            case States.Waiting:

                if (_compileController == null)
                {
                    TSLog.LogError(LogCategory.Trace, "CompileController = null, but State = Compiling");
                    _state = States.Idle;
                    break;
                }

                if (!TypeSafeUtil.ShouldBeOperating())
                {
                    TSLog.Log(LogCategory.Trace, "Aborting compile.");
                    Cancel();
                    Queue();
                    break;
                }

                if (_compileController.IsDone)
                {
                    if (_state != States.Waiting)
                    {
                        // Perform a dry run of the deploy step to see if there were any changes since the last compile
                        int changeCount;
                        TypeSafeUtil.DeployBuildArtifacts(_compileController.Output, out changeCount, true);

                        // Delay for minimum build time if not user initiated and there were changes
                        if (Settings.Instance.EnableWaiting && changeCount > 0 && !_userInitiated &&
                            _stopwatch.Elapsed.TotalSeconds < Settings.Instance.MinimumBuildTime)
                        {
                            _state = States.Waiting;
                            break;
                        }
                    }
                    else
                    {
                        // Wait for wait stage to elapse
                        if (!_abortWait && _stopwatch.Elapsed.TotalSeconds < Settings.Instance.MinimumBuildTime)
                        {
                            break;
                        }
                    }

                    _abortWait = false;

                    TSLog.Log(LogCategory.Trace,
                              string.Format("Compile Complete (WasSuccessful={0})", _compileController.WasSuccessful));

                    if (_compileController.WasSuccessful)
                    {
                        int updatedFileCount;
                        var deployResult = TypeSafeUtil.DeployBuildArtifacts(_compileController.Output,
                                                                             out updatedFileCount);

                        TSLog.Log(LogCategory.Trace,
                                  string.Format("Deploy Complete (WasSuccessful={0}, updatedFileCount={1})", deployResult, updatedFileCount));

                        var shouldReport = _userInitiated || updatedFileCount > 0;

                        TSLog.EndBuffer(LogCategory.Compile, shouldReport);

                        if (!deployResult)
                        {
                            TSLog.LogError(LogCategory.Info, "Compile failed.");
                        }
                        else if (shouldReport)
                        {
                            if (updatedFileCount == 0)
                            {
                                TSLog.Log(LogCategory.Info, "Compile complete, no changes.");
                            }
                            else
                            {
                                TSLog.Log(LogCategory.Info,
                                          string.Format("Compile completed. (Took {0}s)", _stopwatch.Elapsed.Seconds));
                            }
                        }
                    }

                    _compileController = null;
                    _state             = States.Idle;
                }

                break;
            }
        }