// We know this is clumsy, but its a .NET-ism --
        // Form widgets can *only* be controlled by the thread that creates them.
        // Thus, we make this guarantee by wrapping all creation & processing actions
        // in a method called by just one thread.  <sigh>
        private static void PopupDialogViaDelegate(AsyncCompletionToken completionToken,
                                                   string toonName,
                                                   string dialogTitle,
                                                   string dialogMessage,
                                                   string expiryActionName,
                                                   int expiryRemainingInSeconds,
                                                   bool isBotStopAllowed,
                                                   bool isStopOnContinue,
                                                   SystemSound soundCue,
                                                   int soundPeriodInSeconds)
        {
            UserDialogForm dialogForm = new UserDialogForm(completionToken,
                                                           toonName,
                                                           dialogTitle,
                                                           dialogMessage,
                                                           expiryActionName,
                                                           expiryRemainingInSeconds,
                                                           isBotStopAllowed,
                                                           isStopOnContinue,
                                                           soundCue,
                                                           soundPeriodInSeconds);

            // Popup the window--
            // We'd *really* like to make this dialog a child of the main Honorbuddy window.
            // By doing such, the dialog would be 'brought to the front' any time te Honorbuddy main
            // window was.
            // Alas, C#/WindowsForms disallows this because the main HB GUI and this dialog are
            // on separate threads.
            dialogForm.TopMost = true;
            dialogForm.Activate();
            dialogForm.ShowDialog();
        }
        public override void OnFinished()
        {
            if (_completionToken != null)
            {
                _completionToken.Dispose();
                _completionToken = null;
            }

            if (_configMemento != null)
            {
                _configMemento.Dispose();
                _configMemento = null;
            }
            UserDialogExitProcessing(PopdownReason.UNKNOWN);
            TreeRoot.GoalText   = string.Empty;
            TreeRoot.StatusText = string.Empty;
            base.OnFinished();
        }
        public override void OnStart()
        {
            // This reports problems, and stops BT processing if there was a problem with attributes...
            // We had to defer this action, as the 'profile line number' is not available during the element's
            // constructor call.
            OnStart_HandleAttributeProblem();

            // If the quest is complete, this behavior is already done...
            // So we don't want to falsely inform the user of things that will be skipped.
            if (!IsDone)
            {
                _configMemento = new ConfigMemento();

                // We don't want the bot running around harvesting while the user
                // is manually controlling it trying to get the task completed.
                // (We've already captured the existing configuration which will
                //  be restored when this behavior exits, or the bot is stopped.
                //  So there are no worries about destroying user's configuration.)
                CharacterSettings.Instance.HarvestHerbs    = false;
                CharacterSettings.Instance.HarvestMinerals = false;
                CharacterSettings.Instance.LootChests      = false;
                ProfileManager.CurrentProfile.LootMobs     = false;
                CharacterSettings.Instance.NinjaSkin       = false;
                CharacterSettings.Instance.SkinMobs        = false;

                _completionToken = new AsyncCompletionToken(StyxWoW.Me.Name,
                                                            DialogTitle,
                                                            DialogText,
                                                            ExpiryActionName,
                                                            ExpiryTime,
                                                            IsBotStopAllowed,
                                                            IsStopOnContinue,
                                                            SoundCue,
                                                            SoundCueIntervalInSeconds);

                this.UpdateGoalText(QuestId, "User Attention Required...");
                TreeRoot.StatusText = "Waiting for user dialog to close";
            }
        }
        public UserDialogForm(AsyncCompletionToken completionToken,
                              string toonName,
                              string dialogTitle,
                              string dialogMessage,
                              string expiryActionName,
                              int expiryRemainingInSeconds,
                              bool isBotStopAllowed,
                              bool isStopOnContinue,
                              SystemSound soundCue,
                              int soundCuePeriodInSeconds)
        {
            _completionToken = completionToken;
            _completionToken.PopdownResponse = PopdownReason.UNKNOWN;
            _expiryActionHandler             = ExpiryActionHandler.GetEnumItemByName(expiryActionName);
            _expiryRemainingInSeconds        = expiryRemainingInSeconds;
            _isBotStopAllowed        = isBotStopAllowed;
            _isStopOnContinue        = isStopOnContinue;
            _soundCue                = soundCue;
            _soundCuePeriodInSeconds = soundCuePeriodInSeconds;


            // Dialog creation
            InitializeComponent();

            this.ControlBox      = false; // disable close box for this dialog
            this.MinimizeBox     = false; // disable minimize box for this dialog
            this.MaximizeBox     = false; // disable maximize box for this dialog
            this.FormBorderStyle = FormBorderStyle.FixedDialog;

            this.FormClosing += new FormClosingEventHandler(dialogForm_FormClosing);

            _heartbeatPulseTimer.Stop();


            // Dialog identity
            this.Text                      = String.Format("['{0}' UserDialog] {1}", toonName, dialogTitle);
            _textBoxMessage.Text           = dialogMessage.Replace("\\n", Environment.NewLine).Replace("\\t", "\t");
            _textBoxMessage.SelectionStart = _textBoxMessage.SelectionLength;
            _checkBoxAutoDefend.Checked    = _completionToken.IsAutoDefend;
            _buttonStopBot.Enabled         = isBotStopAllowed;
            _labelStatus.Text              = "";

            // If only 'stop' allowed, convert the normally 'profile continue' button to 'stop'
            if (_isStopOnContinue)
            {
                _buttonStopBot.Visible      = false;
                _buttonContinueProfile.Text = "Stop Bot";
            }


            // Setup the Expiry countdown, if enabled--
            // Our pulse timer goes off every second to notify the user how much time
            // remains before the expiry action will be executed.
            if (_expiryRemainingInSeconds > 0)
            {
                _expiryActionHandler.Initialize(this);
                _labelStatus.Text = UtilBuildTimeRemainingStatusText(_expiryActionHandler.ActionAsString(), _expiryRemainingInSeconds);
            }


            // Setup the audible warnings --
            // Note: *Never* try to set the System.Windows.Forms.Timer.Interval to zero.
            // Doing so will trigger a Windoze bug that prevents the dialog from
            // opening.
            switch (_soundCuePeriodInSeconds)
            {
            case 0:
                // Play no sound--nothing to do
                _soundPeriodRemaining          = 0;
                _checkBoxSuppressAudio.Enabled = false;
                break;

            case 1:
                // Play sound once for dialog open
                _soundPeriodRemaining = 0;
                soundCue.Play();
                _checkBoxSuppressAudio.Enabled = false;
                break;

            default:
                // Play sound now for dialog open, and
                // arrange to play the sound at the specified intervals
                _soundPeriodRemaining = _soundCuePeriodInSeconds;
                soundCue.Play();
                _checkBoxSuppressAudio.Enabled = true;
                break;
            }



            // Our heartbeat pulse handler looks for things like timer expiry, and dialog close requests.
            // Polling techniques like this offend us; however, our choices are limited, since
            // .NET requires the actual processing of a request to occur on the same thread
            // that created the dialog and its widgets.  Yet, .NET provides us with no clean mechanisms
            // for external event notifications other than through timers.
            _heartbeatPulseTimer.Interval = 1000;    // one second
            _heartbeatPulseTimer.Enabled  = true;
        }