/*This is a default execution of action, some actions may perform differently, like a complex action.
         * We should choose to override execute routine if possible to enable action test */
        public void ExecuteAction(bool reportLabel)
        {
            /* This is moved from constructor: We should launch browser when required only,
             * keep this inside constructor will make unable to access other function that doesnot require browser*/
            //  if (!Modules.BrowserSupport.BrowserIsOpenned() || !Modules.BrowserSupport._ProfileName.Equals(_user.ChromeProfile))
            if (!Modules.BrowserSupport.BrowserIsOpenned())
            {
                //  Modules.BrowserSupport.OpenBrowser(_user.ChromeProfile);
                Modules.BrowserSupport.OpenBrowser(null);
            }
            //The convert node happen repeated and don't need to be reported
            if (_wk != null && _ReportActionName)
            {
                _wk.ReportProgress(0, "Execute action " + _ActionData.ActionName);
            }
            try
            {
                //we handle errors here so to cover all overload method of innerexecuteaction
                InnerExecuteAction(reportLabel);
            }
            catch (MyExceptions.MyMyExceptions)
            {
                throw;
            }
            catch (OpenQA.Selenium.NoSuchElementException)
            {
                throw;
            }
            catch (Exception ex)
            {
                //we should make the error short for easy reading
                if (objLastError == null)
                {
                    objLastError            = new ErrorObject();
                    objLastError.ActionName = _ActionData.ActionName;
                }
                string message = "Error on action: " + _ActionData.ActionName + Environment.NewLine;
                if (objLastError.Label == null)
                {
                    message += "Label Null" + Environment.NewLine;
                }
                else
                {
                    message += "Label: " + objLastError.Label.LabelName + Environment.NewLine;
                }
                message += "Error Type: " + ex.GetType() + Environment.NewLine;
                message += "Detail message: " + ex.ToString();
                _wk.ReportProgress(0, ex.ToString());
                //  FrmLabelNavigator nav = new FrmLabelNavigator(this, objLastError.Label, message);
                //   DialogResult dresult = nav.ShowDialog();
                DialogResult dresult = DialogResult.Yes;

                /* We supposed to execute manually in LabelNavigator, if success
                 * then we just continue everything, if not then break */
                if (dresult != DialogResult.Yes)
                {
                    //if the error is handle we don't need to add it to error collection
                    bool isRepeated = Global.CheckIfErrorRepeatedInAPeriod(objLastError, TimeSpan.FromMinutes(60));
                    Global.AddError(objLastError);
                    if (dresult == DialogResult.Abort)
                    {
                        throw new MyExceptions.ActionCanceledException("Action canceled by user");
                    }
                    else if (dresult == DialogResult.Ignore)//this case happens on auto close after some minutes
                    {
                        if (isRepeated)
                        {
                            if (ex is MyExceptions.LabelException)
                            {
                                throw new MyExceptions.LabelException(message);
                            }
                            else
                            {
                                //The exception is likely come from overload version of ExecuteRoutine
                                throw new MyExceptions.MyMyExceptions(message);
                            }
                        }
                    }
                }
            }
        }
        /* A routine can execute flawless but not get what we want, e.g node selected but not have value, or select nodes
         * return count = 0 so we
         * need to return a boolean to tell the action to stop, not throw error everywhere */
        /// <summary>
        /// Make this public so we can call directly to test on a routine.
        /// </summary>
        /// <param name="routine"></param>
        /// <returns></returns>
        protected virtual void InnerExecuteAction(bool reportLabel)
        {
            BO.ElementLabelBO elbo   = new BO.ElementLabelBO();
            List <int>        lblIds = elbo.GetQueryable(_ActionData.ActionId).OrderBy(l => l.LabelOrder).Select(l => l.LabelId).ToList();

            Objects.LabelObject objLabel;
            for (int i = 0; i < lblIds.Count; i++)
            {
                if (_wk != null && _wk.CancellationPending)
                {
                    break;
                }
                //well this should be enough to refresh data
                elbo = new BO.ElementLabelBO();
                var label = elbo.GetLabel(lblIds[i]);
                //In this case we use special wait not just sleep
                if (label.ExpectedBehavior != (int)WebElementBehavior.WaitForSomethingHappen)
                {
                    var sleep = label.WaitSeconds == 0 ? DefaultLabelWaitMiliseconds : label.WaitSeconds * 1000;
                    System.Threading.Thread.Sleep(sleep);
                }
                if (_wk != null && _wk.CancellationPending)
                {
                    break;
                }
                if (_wk != null && reportLabel)
                {
                    _wk.ReportProgress(0, "execute label \"" + label.LabelName + "\"");
                }
                objLabel             = new LabelObject(label, this._inputDatas);
                objLabel._NodeParent = _CurrentHtmlAgilityNodeParent;
                objLabel._wk         = _wk;
                try
                {
                    objLabel.ExecuteBehavior();
                    //do not wait by label.seconds because it is for behavior like waitforvisible etc
                    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1));
                    if (objLabel._ReturnData != null)
                    {
                        if (_ReturnDataCollection == null)
                        {
                            _ReturnDataCollection = new Dictionary <string, object>();
                        }
                        _ReturnDataCollection[objLabel._LabelData.ReturnDataKey] = objLabel._ReturnData;
                    }
                }
                catch (MyExceptions.BreakRoutineIfFoundException)
                {
                    if (_wk != null)
                    {
                        _wk.ReportProgress(0, "Found label " + label.LabelName + ", break routine" + Environment.NewLine);
                    }
                    break;
                }
                catch (MyExceptions.BreakRoutineIfNOTFoundException)
                {
                    if (_wk != null)
                    {
                        _wk.ReportProgress(0, "Not found label " + label.LabelName + ", break routine" + Environment.NewLine);
                    }
                    break;
                }
                catch (Exception ex)
                {
                    //we should make the error short for easy reading
                    string message = "Error on action: " + _ActionData.ActionName + Environment.NewLine;
                    message += "Label: " + label.LabelName + Environment.NewLine;
                    message += "Label Error Type: " + ex.GetType() + Environment.NewLine;
                    message += "Detail message: " + ex.Message;
                    //if the error is handle we don't need to add it to error collection
                    objLastError            = new ErrorObject();
                    objLastError.Label      = label;
                    objLastError.ActionName = _ActionData.ActionName;
                    //we throw to handle the error upper so we can cover all overload method
                    throw;
                }
            }
        }