/// <summary>
        /// Transform each form element to a HtmlFormTag.
        /// </summary>
        /// <param name="htmlDoc"> The HTML DOM Document to process.</param>
        public static HtmlFormTagCollection TransformFormElements(IHTMLDocument2 htmlDoc, Uri currentUri)
        {
            // For each form, add in temp FormTags Collection
            FormConverter converter = new FormConverter();

            HtmlFormTagCollection formCollection = new HtmlFormTagCollection(htmlDoc.forms.length);

            try
            {
                foreach ( HTMLFormElementClass formElement in htmlDoc.forms )
                {
                    System.Windows.Forms.Application.DoEvents();

                    // Convert to HTML Form Tag
                    HtmlFormTag form = converter.ConvertToHtmlFormTag(formElement, currentUri);

                    if ( !formCollection.ContainsKey(form.Name) )
                    {
                        formCollection.Add(form.Name, form);
                    }
                }
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.ToString());
                Microsoft.ApplicationBlocks.ExceptionManagement.ExceptionManager.Publish(ex);
            }

            return formCollection;
        }
        /// <summary>
        /// Normalizes the form tag. For use with the multipart/form-data.
        /// </summary>
        public static HtmlFormTag NormalizeFormTag(HtmlFormTag formTag, string data)
        {
            FormConverter converter = new FormConverter();
            PostDataCollection postDataItems = converter.GetPostDataCollection(data);
            // removes extra tags.

            foreach ( string name in postDataItems.Keys )
            {
                if ( formTag.ContainsKey(name) )
                {
                    HtmlTagBaseList list = formTag[name];

                    if ( list.Count > 1 )
                    {
                        for ( int i=1;i<(list.Count+1);i++ )
                        {
                            list.Remove(list[i]);
                        }
                    }
                }
                else
                {
                    formTag.Remove(name);
                }
            }

            return formTag;
        }
        /// <summary>
        /// Called when no OnSubmit event is raised.
        /// </summary>
        /// <param name="sender"> The sender object.</param>
        /// <param name="e"> The FormHeuriscticEventArgs.</param>
        private void navForm_FormHeuristicEvent(object sender, FormHeuristicArgs e)
        {
            FormConverter converter = new FormConverter();
            HtmlFormTag form = converter.AddPostDataValues(e.FormTag, e.PostData);

            if ( form.Action.Length == 0 )
            {
                form.Action = e.SiteUri.Scheme + "://" + e.SiteUri.Authority + e.SiteUri.AbsolutePath;
            }
            RequestPostEventArgs postArgs = new RequestPostEventArgs();

            // TODO: Check of Method is POST or GET
            // Just post
            postArgs.InspectorRequestAction = InspectorAction.WebBrowserPost;
            postArgs.Form = form;
            postArgs.Method = form.Method;
            postArgs.PostData = Encoding.UTF8.GetBytes(e.PostData);
            postArgs.CurrentUri = e.SiteUri;

            // request
            this.InspectorStartPostEvent(this, postArgs);

            // Add Easy Test options
            //this.RunQuickTests(postArgs);
        }
        /// <summary>
        /// Called when a OnSubmit event is raised.
        /// </summary>
        /// <param name="sender"> The sender object.</param>
        /// <param name="e"> The FormConvertionEventArgs.</param>
        private void navForm_FormConvertionEvent(object sender, FormConvertionArgs e)
        {
            FormConverter converter = new FormConverter();

            HtmlFormTag form = converter.ConvertToHtmlFormTag(e.FormElement, e.SiteUri);
            form = converter.AddPostDataValues(form, e.PostData);

            // Just post
            RequestPostEventArgs postArgs = new RequestPostEventArgs();
            postArgs.InspectorRequestAction = InspectorAction.WebBrowserPost;
            postArgs.Form = form;
            postArgs.Method = form.Method;
            postArgs.PostData = Encoding.UTF8.GetBytes(e.PostData);
            postArgs.CurrentUri = e.SiteUri;

            this.InspectorStartPostEvent(this, postArgs);

            // Add Quick Test options
            //this.RunQuickTests(postArgs);
        }
        /// <summary>
        /// Creates a form from a query string.
        /// </summary>
        /// <param name="url"> The complete url.</param>
        /// <returns> A HtmlFormTag.</returns>
        private HtmlFormTag CreateFormFromQueryString(Uri url)
        {
            string action = url.Scheme + "://" + url.Host + url.AbsolutePath;
            FormConverter converter = new FormConverter();
            PostDataCollection postData = converter.GetPostDataCollection(url.Query.TrimStart('?'));

            HtmlFormTag formTag = new HtmlFormTag();
            formTag.Action = action;
            formTag.Name = "docform";
            formTag.Method = base.WebRequest.RequestType.ToString();

            foreach ( string key in postData.Keys )
            {
                ArrayList items = postData[key];

                HtmlTagBaseList list = new HtmlTagBaseList();
                formTag.Add(key, list);
                foreach ( string value in items )
                {
                    HtmlInputTag hiddenField = new HtmlInputTag();
                    hiddenField.Type = HtmlInputType.Hidden;
                    hiddenField.Name = key;
                    hiddenField.Value = value.Trim().TrimEnd('\0');
                    list.Add(hiddenField);
                }
            }

            return formTag;
        }
        /// <summary>
        /// Matches the post data to a form in a form collection.
        /// </summary>
        /// <param name="formCollection"> The form collection.</param>
        /// <param name="data"> The post data string.</param>
        /// <returns> A HtmlFormTag.</returns>
        public HtmlFormTag MatchPostDataToForm(HtmlFormTagCollection formCollection, string data)
        {
            FormConverter converter = new FormConverter();
            PostDataCollection postDataItems = converter.GetPostDataCollection(data);

            int matchByFieldName = 0;

            HtmlFormTagCollection formMatchByCount =  new HtmlFormTagCollection();

            #region First Match By Count
            foreach (DictionaryEntry de in formCollection)
            {
                HtmlFormTag form = (HtmlFormTag)de.Value;

                // if match count is unique then use that form
                if ( postDataItems.Count == form.Count )
                {
                    formMatchByCount.Add(form.Name, form);
                }
            }
            #endregion

            HtmlFormTag foundFormTag = null;
            if ( formMatchByCount.Count == 0 )
            {
                #region Then Match by Field Names, select the one with the matching more fields

                int weight = 0;
                string currentForm = string.Empty;
                Hashtable formKeysFound = new Hashtable(formCollection.Count);

                foreach ( DictionaryEntry de in formCollection )
                {
                    HtmlFormTag form = (HtmlFormTag)de.Value;
                    ArrayList keysToMaintain = new ArrayList();

                    // if match by field name is unique then use that form
                    for (int i=0;i<postDataItems.Count;i++ )
                    {
                        string name = postDataItems.Keys[i];

                        // all values has to be found, else exit
                        if ( form.ContainsKey(name) )
                        {
                            keysToMaintain.Add(name);
                            matchByFieldName++;
                        }
                    }

                    // form keys to maintain
                    formKeysFound.Add(form.Name, keysToMaintain);

                    // Example: 31 Forms Items, but match only 29 equals 2
                    if ( matchByFieldName > 0 )
                    {
                        if ( (matchByFieldName - form.Count) < weight )
                        {
                            weight = matchByFieldName - form.Count;
                            currentForm = form.Name;
                        }
                        matchByFieldName = 0;
                    }
                }

                // select form and remove not needed items
                foundFormTag = formCollection[currentForm];

                if ( foundFormTag != null )
                {
                    ArrayList itemKeys = (ArrayList)formKeysFound[currentForm];

                    // remove other fields from FormTag
                    HtmlFormTag clone = foundFormTag.CloneTag();
                    foundFormTag.Clear();

                    for (int j=0;j<itemKeys.Count;j++)
                    {
                        string itemName = (string)itemKeys[j];
                        foundFormTag.Add(itemName, clone[itemName]);
                    }
                }
                #endregion
            }
            else
            {
                #region Then Match by Field Names
                foreach ( DictionaryEntry de in formMatchByCount )
                {
                    HtmlFormTag form = (HtmlFormTag)de.Value;
                    Hashtable formKeysFound = new Hashtable(formCollection.Count);
                    ArrayList keysToMaintain = new ArrayList();

                    // if match by field name is unique then use that form
                    for (int i=0;i<postDataItems.Count;i++ )
                    {
                        string name = postDataItems.Keys[i];

                        // all values has to be found, else exit
                        if ( form.ContainsKey(name) )
                        {
                            keysToMaintain.Add(name);
                            matchByFieldName++;
                        }
                        else
                        {
                            matchByFieldName = -1;
                            break;
                        }
                    }

                    // form keys to maintain
                    formKeysFound.Add(form.Name, keysToMaintain);

                    if ( matchByFieldName != -1 )
                    {
                        // found, return first occurence no matter what
                        foundFormTag = form;

                        ArrayList itemKeys = (ArrayList)formKeysFound[foundFormTag.Name];

                        // remove other fields from FormTag
                        HtmlFormTag clone = foundFormTag.CloneTag();
                        foundFormTag.Clear();

                        for (int j=0;j<itemKeys.Count;j++)
                        {
                            string itemName = (string)itemKeys[j];
                            foundFormTag.Add(itemName, clone[itemName]);
                        }
                    }
                }
                #endregion
            }

            return foundFormTag;
        }
        /// <summary>
        /// Apply the test requests for a session request.
        /// </summary>
        /// <param name="sessionRequest"> The session request.</param>
        /// <param name="result"> The response buffer result from the safe session.</param>
        private void ApplyRequestTests(SessionRequest sessionRequest, ResponseBuffer result)
        {
            UnitTestItem unitTestItem = sessionRequest.WebUnitTest;
            unitTestItem.Form = sessionRequest.Form;

            CookieCollection cookies = null;

            //int availableTests = this.AvailableTests();
            //bool lastItem = false;
            string requestUrl = sessionRequest.Url.ToString();

            #region Run each test in SessionRequest WebUnitTestItem

            // run each test in Form
            foreach (DictionaryEntry de in unitTestItem.Tests)
            {
                Test test = (Test)de.Value;
                ArrayList values = new ArrayList();

                // get cookies
                cookies = cookieManager.GetCookies(sessionRequest.Url);

                // set current test index
                unitTestItem.SelectedTestIndex = unitTestItem.Tests.IndexOfValue(test);

                // create SessionCommandProcessEventArgs
                SessionCommandProcessEventArgs args = new SessionCommandProcessEventArgs("Applying test '" + test.Name + "' to " + sessionRequest.Url.ToString());
                args.ProcessType = SessionProcessType.TestRequest;

                #region Apply Test
                // --------------------------------------------------------------------------------
                // Process data
                // Html Form Tag
                if ( test.UnitTestDataType == UnitTestDataContainer.HtmlFormTag )
                {
                    // is a form tag
                    // apply test to form
                    HtmlFormTag filledForm = ApplyTestToForm(test, sessionRequest.Form.CloneTag());
                    values = parser.GetArrayList(filledForm, result.HttpBody, updateElementNames);
                }
                // Post Data Hashtable
                if ( test.UnitTestDataType == UnitTestDataContainer.PostDataHashtable )
                {
                    string postdata = ((PostSessionRequest)sessionRequest).PostData;

                    // TODO: Change to PostDataCollection method.
                    // convert post data to hashtable
                    FormConverter converter = new FormConverter();
                    //Hashtable postDataCollection = converter.ConvertPostDataStringHashtable(postdata);
                    PostDataCollection postDataCollection = converter.GetPostDataCollection(postdata);

                    // Applies test to post data hashtable
                    PostDataCollection filledPostData = ApplyTestToPostData(test, postDataCollection.Clone());
                    values = converter.GetArrayList(filledPostData);
                }
                // Cookies
                if ( test.UnitTestDataType == UnitTestDataContainer.Cookies )
                {
                    cookies = ApplyTestToCookies(test, cookies);
                }
                // Url
                if( test.UnitTestDataType == UnitTestDataContainer.NoPostData )
                {
                    // a url test
                    requestUrl = ApplyTestToUrl(test, WebServerUriType.Normal,sessionRequest.Url).ToString();
                }
                // -----------------------------------------------------------------------------------
                #endregion

                if ( (test.UnitTestDataType == UnitTestDataContainer.HtmlFormTag ) || ( test.UnitTestDataType == UnitTestDataContainer.PostDataHashtable ) )
                {
                    // Set post data for report
                    test.Arguments.PostData = ConvertToPostDataString(values);
                    args.Detail = "Posted Data:" + test.Arguments.PostData;
                }
                if ( test.UnitTestDataType == UnitTestDataContainer.NoPostData )
                {
                    args.Detail = "Url query:" + requestUrl;
                }
                if ( test.UnitTestDataType == UnitTestDataContainer.Cookies )
                {
                    StringBuilder cookieQuery = new StringBuilder();

                    foreach ( Cookie cky in cookies )
                    {
                        cookieQuery.Append("Name:" + cky.Name);
                        cookieQuery.Append(", ");
                        cookieQuery.Append("Value:" + cky.Value);
                        cookieQuery.Append(";");
                    }

                    args.Detail = "Cookie:" + cookieQuery.ToString();
                }

            //				// set last item flag
            //				if ( availableTests == 1)
            //				{
            //					lastItem = true;
            //				}

                // display the current processing
                this.DisplaySessionProcessEvent(this,args);

                // clone test item and set last item value
                HttpState httpRequestState = new HttpState();
                httpRequestState.TestItem = unitTestItem.Clone();
                //httpRequestState.IsLastItem = lastItem;

                // http settings
                HttpProperties httpSettings = null;
                if ( sessionRequest.RequestHttpSettings == null )
                {
                    httpSettings = unitTestGetRequest.ClientSettings;
                }
                else
                {
                    httpSettings = sessionRequest.RequestHttpSettings;
                }

                if ( sessionRequest.RequestType == HttpRequestType.GET )
                {
                    // get request
                    this.StartGetRequest(unitTestGetRequest,
                        requestUrl,
                        null,
                        cookies,
                        httpSettings,
                        httpRequestState);
                }
                else  if ( sessionRequest.RequestType == HttpRequestType.POST )
                {
                    // post request
                    this.StartPostRequest(unitTestPostRequest,
                        requestUrl,
                        values,
                        cookies,
                        httpSettings,
                        httpRequestState);
                }

                //availableTests--;
            }
            #endregion
        }